-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse.js
More file actions
92 lines (75 loc) · 2.49 KB
/
parse.js
File metadata and controls
92 lines (75 loc) · 2.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
var SaxParser = require("sax").SAXParser
var last = require("./lib").last
var reduce = require("./lib").reduce
var isArray = Array.isArray
var hasDefaultNamespace = require("./lib").contains.bind(null, "")
var STRICT = true
var EMPTY = Object.create(null)
var VERSION = /\bversion=["']([^"']+)["']/
var ENCODING = /\bencoding=["']([^"']+)["']/
var TEXT_ATTR = "$"
var NAMESPACE_SEP = "$"
module.exports = parse
function parse(namespaces, xml) {
return new Parser(namespaces).parse(xml)
}
function Parser(namespaces) {
SaxParser.call(this, STRICT, {trim: true, xmlns: true, position: false})
this.namespaces = namespaces || EMPTY
this.unscoped = hasDefaultNamespace(this.namespaces)
this.stack = [{}]
}
Parser.prototype = Object.create(SaxParser.prototype, {
constructor: {value: Parser, configurable: true, writeable: true}
})
Parser.prototype.parse = function(xml) {
this.write(xml)
this.close()
return this.stack[0]
}
Parser.prototype.nameTag = function(tag) {
var alias = this.namespaces[tag.uri]
if (alias === "") return tag.local
if (alias != null) return alias + NAMESPACE_SEP + tag.local
// Alternative default namespace would be the "xml" namespace.
if (tag.prefix === "" && this.unscoped) return ":" + tag.name
return tag.name
}
Parser.prototype.nameAttribute = function(attr) {
if (attr.uri === "") return attr.local
var alias = this.namespaces[attr.uri]
if (alias === "") return attr.local
if (alias != null) return alias + NAMESPACE_SEP + attr.local
return attr.name
}
Parser.prototype.onprocessinginstruction = function(xml) {
var version = VERSION.exec(xml.body)
var encoding = ENCODING.exec(xml.body)
if (version) this.stack[0].version = version[1]
if (encoding) this.stack[0].encoding = encoding[1]
}
Parser.prototype.onopentag = function(tag) {
var self = this
var name = this.nameTag(tag)
var attrs = reduce(function(attrs, attr) {
attrs[self.nameAttribute(attr)] = attr.value
return attrs
}, {}, tag.attributes)
var parent = last(this.stack)
if (name in parent && isArray(parent[name])) parent[name].push(attrs)
else if (typeof parent[name] == "object") parent[name] = [parent[name], attrs]
else parent[name] = attrs
this.stack.push(attrs)
}
Parser.prototype.ontext = function(text) {
var node = last(this.stack)
if (node[TEXT_ATTR] == null) node[TEXT_ATTR] = text
else node[TEXT_ATTR] += text
}
Parser.prototype.oncdata = Parser.prototype.ontext
Parser.prototype.onclosetag = function(_tag) {
this.stack.pop()
}
Parser.prototype.onerror = function(err) {
throw err
}