xml-toolkit 0.0.1 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +6 -4
- package/lib/AttributesMap.js +74 -0
- package/lib/EntityResolver.js +66 -0
- package/lib/MoxyLikeJsonEncoder.js +41 -0
- package/lib/NamespacesMap.js +48 -0
- package/lib/SAXEvent.js +52 -5
- package/lib/XMLLexer.js +0 -6
- package/lib/XMLNode.js +141 -0
- package/lib/XMLReader.js +274 -0
- package/package.json +4 -2
- package/test/ent.xml +6 -0
- package/test/soap.xml +40 -0
- package/test/test.js +40 -25
- package/lib/SAXEventEmitter.js +0 -42
package/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
const XMLLexer
|
|
2
|
-
const
|
|
3
|
-
const SAXEvent
|
|
1
|
+
const XMLLexer = require ('./lib/XMLLexer')
|
|
2
|
+
const XMLReader = require ('./lib/XMLReader')
|
|
3
|
+
const SAXEvent = require ('./lib/SAXEvent')
|
|
4
|
+
const AttributesMap = require ('./lib/AttributesMap')
|
|
5
|
+
const MoxyLikeJsonEncoder = require ('./lib/MoxyLikeJsonEncoder')
|
|
4
6
|
|
|
5
|
-
module.exports = {
|
|
7
|
+
module.exports = {XMLLexer, XMLReader, SAXEvent, AttributesMap, MoxyLikeJsonEncoder}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const CH_COLON = ':'.charCodeAt (0)
|
|
2
|
+
|
|
3
|
+
const AttributesMap = class extends Map {
|
|
4
|
+
|
|
5
|
+
constructor (xmlReader, nsMap = null) {
|
|
6
|
+
|
|
7
|
+
super ()
|
|
8
|
+
|
|
9
|
+
this._xmlReader = xmlReader
|
|
10
|
+
this._nsMap = nsMap
|
|
11
|
+
|
|
12
|
+
this.fixText = xmlReader.fixText
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getLocalName (name) {
|
|
17
|
+
|
|
18
|
+
return (require ('./XMLNode.js')).getLocalName (name)
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getNamespaceURI (name) {
|
|
23
|
+
|
|
24
|
+
return this._nsMap.getNamespaceURI (name)
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get (name, namespaceURI = null) {
|
|
29
|
+
|
|
30
|
+
if (namespaceURI === null) return super.get (name)
|
|
31
|
+
|
|
32
|
+
for (const k of this._nsMap.getQNames (name, namespaceURI)) {
|
|
33
|
+
|
|
34
|
+
if (!this.has (k)) continue
|
|
35
|
+
|
|
36
|
+
return this.get (k)
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
set (k, v) {
|
|
43
|
+
|
|
44
|
+
const {_nsMap} = this; if (_nsMap !== null) {
|
|
45
|
+
|
|
46
|
+
if (k.slice (0, 5) === 'xmlns') {
|
|
47
|
+
|
|
48
|
+
if (k.length === 5) {
|
|
49
|
+
|
|
50
|
+
_nsMap.set ('', v)
|
|
51
|
+
|
|
52
|
+
return this
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (k.charCodeAt (5) === CH_COLON) {
|
|
57
|
+
|
|
58
|
+
_nsMap.set (k.slice (6), v)
|
|
59
|
+
|
|
60
|
+
return this
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return super.set (k, this.fixText (v))
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = AttributesMap
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const XMLReader = require ('./XMLReader.js')
|
|
2
|
+
|
|
3
|
+
const CH_HASH = '#'.charCodeAt (0)
|
|
4
|
+
|
|
5
|
+
const PREDEFINED = new Map ([
|
|
6
|
+
['lt' , '<'],
|
|
7
|
+
['gt' , '>'],
|
|
8
|
+
['quot' , '"'],
|
|
9
|
+
['amp' , '&'],
|
|
10
|
+
['apos' , "'"],
|
|
11
|
+
])
|
|
12
|
+
|
|
13
|
+
const EntityResolver = class {
|
|
14
|
+
|
|
15
|
+
constructor () {
|
|
16
|
+
|
|
17
|
+
this.body = new Map (PREDEFINED)
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
fix (s) {
|
|
22
|
+
|
|
23
|
+
let start = s.indexOf ('&'); if (start === -1) return s
|
|
24
|
+
|
|
25
|
+
let r = s.slice (0, start)
|
|
26
|
+
|
|
27
|
+
const {body} = this
|
|
28
|
+
|
|
29
|
+
while (true) {
|
|
30
|
+
|
|
31
|
+
let end = s.indexOf (';', ++ start); if (end === -1) throw new Error ('Unterminated entity reference in ' + JSON.stringify ([s]))
|
|
32
|
+
|
|
33
|
+
const key = s.slice (start, end)
|
|
34
|
+
|
|
35
|
+
if (body.has (key)) {
|
|
36
|
+
|
|
37
|
+
r += body.get (key)
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
|
|
42
|
+
const charCode = key.charCodeAt (0) === CH_HASH ? parseInt (key.slice (1), 16) : parseInt (key, 10)
|
|
43
|
+
|
|
44
|
+
if (isNaN (charCode) || charCode <= 0) throw new Error ('Unknown entity reference ' + key + ' in ' + JSON.stringify ([s]))
|
|
45
|
+
|
|
46
|
+
const c = String.fromCharCode (charCode)
|
|
47
|
+
|
|
48
|
+
body.set (key, c)
|
|
49
|
+
|
|
50
|
+
r += c
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
start = s.indexOf ('&', ++ end)
|
|
55
|
+
|
|
56
|
+
if (start === -1) return r + s.slice (end)
|
|
57
|
+
|
|
58
|
+
r += s.slice (end, start)
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = EntityResolver
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const SAXEvent = require ('./SAXEvent.js')
|
|
2
|
+
|
|
3
|
+
const set = (o, k, nv) => {
|
|
4
|
+
|
|
5
|
+
if (!(k in o)) return o [k] = nv
|
|
6
|
+
|
|
7
|
+
const ov = o [k]; if (!Array.isArray (ov)) o [k] = [ov]
|
|
8
|
+
|
|
9
|
+
o [k].push (nv)
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const xform = ({children, attributes}) => {
|
|
14
|
+
|
|
15
|
+
let o = attributes == null ? {} : Object.fromEntries (attributes.entries ())
|
|
16
|
+
|
|
17
|
+
if (children != null) for (const child of children) switch (child.type) {
|
|
18
|
+
|
|
19
|
+
case SAXEvent.TYPES.CHARACTERS: return child.text
|
|
20
|
+
|
|
21
|
+
case SAXEvent.TYPES.END_ELEMENT: set (o, child.localName, xform (child))
|
|
22
|
+
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return o
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const MoxyLikeJsonEncoder = function (options = {}) {
|
|
30
|
+
|
|
31
|
+
return function (node) {
|
|
32
|
+
|
|
33
|
+
let result = xform (node)
|
|
34
|
+
|
|
35
|
+
return options.wrap ? {[node.localName]: result} : result
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = MoxyLikeJsonEncoder
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const NamespacesMap = class extends Map {
|
|
2
|
+
|
|
3
|
+
constructor (xmlNode) {
|
|
4
|
+
|
|
5
|
+
const {parent} = xmlNode
|
|
6
|
+
|
|
7
|
+
if (parent === null) {
|
|
8
|
+
|
|
9
|
+
super ()
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
|
|
14
|
+
super (parent.namespacesMap)
|
|
15
|
+
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getNamespaceURI (name, useDefault = false) {
|
|
21
|
+
|
|
22
|
+
const pos = name.indexOf (':'), noColon = pos === -1
|
|
23
|
+
|
|
24
|
+
if (noColon && !useDefault) return null
|
|
25
|
+
|
|
26
|
+
const key = noColon ? '' : name.slice (0, pos)
|
|
27
|
+
|
|
28
|
+
if (!this.has (key)) return null
|
|
29
|
+
|
|
30
|
+
return this.get (key)
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
* getQNames (localName, namespaceURI) {
|
|
35
|
+
|
|
36
|
+
for (let [k, v] of this.entries ())
|
|
37
|
+
|
|
38
|
+
if (v === namespaceURI)
|
|
39
|
+
|
|
40
|
+
yield k === '' ? localName :
|
|
41
|
+
|
|
42
|
+
k + ':' + localName
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = NamespacesMap
|
package/lib/SAXEvent.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const assert = require ('assert')
|
|
2
2
|
|
|
3
3
|
const CH_LT = '<'.charCodeAt (0)
|
|
4
|
+
const CH_GT = '>'.charCodeAt (0)
|
|
4
5
|
const CH_EXCLAMATION = '!'.charCodeAt (0)
|
|
5
6
|
const CH_QUESTION = '?'.charCodeAt (0)
|
|
6
7
|
const CH_SLASH = '/'.charCodeAt (0)
|
|
@@ -46,7 +47,7 @@ const SAXEvent = class {
|
|
|
46
47
|
|
|
47
48
|
case CH_QUESTION:
|
|
48
49
|
|
|
49
|
-
switch (src.slice (2, 5).
|
|
50
|
+
switch (src.slice (2, 5).toUpperCase ()) {
|
|
50
51
|
|
|
51
52
|
case STR_XML: return START_DOCUMENT
|
|
52
53
|
|
|
@@ -95,6 +96,20 @@ const SAXEvent = class {
|
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
}
|
|
99
|
+
|
|
100
|
+
get xml () {
|
|
101
|
+
|
|
102
|
+
switch (this.type) {
|
|
103
|
+
|
|
104
|
+
case END_DOCUMENT: return ''
|
|
105
|
+
|
|
106
|
+
case END_ELEMENT: return this.isSelfEnclosed ? '' : `</${this.name}>`
|
|
107
|
+
|
|
108
|
+
default: return this.src
|
|
109
|
+
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
}
|
|
98
113
|
|
|
99
114
|
get attributes () {
|
|
100
115
|
|
|
@@ -106,6 +121,38 @@ const SAXEvent = class {
|
|
|
106
121
|
|
|
107
122
|
}
|
|
108
123
|
|
|
124
|
+
get name () {
|
|
125
|
+
|
|
126
|
+
if (this._afterName === 0) this.findAfterName ()
|
|
127
|
+
|
|
128
|
+
const {src} = this, start = src.charCodeAt (1) === CH_SLASH ? 2 : 1
|
|
129
|
+
|
|
130
|
+
return this.src.slice (start, this._afterName).trim ()
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
findAfterName () {
|
|
135
|
+
|
|
136
|
+
const {src} = this, {length} = src;
|
|
137
|
+
|
|
138
|
+
for (let i = 1; i < length; i ++) {
|
|
139
|
+
|
|
140
|
+
const c = src.charCodeAt (i)
|
|
141
|
+
|
|
142
|
+
switch (c) {
|
|
143
|
+
case CH_SLASH:
|
|
144
|
+
case CH_GT:
|
|
145
|
+
return this._afterName = i
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (c <= 32) return this._afterName = i
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
this._afterName = length - 1
|
|
153
|
+
|
|
154
|
+
}
|
|
155
|
+
|
|
109
156
|
writeAttributesToMap (m) {
|
|
110
157
|
|
|
111
158
|
const {src} = this
|
|
@@ -117,12 +164,12 @@ const SAXEvent = class {
|
|
|
117
164
|
const q = src.indexOf (src.charAt (eq + 1), eq + 2); if (q === -1) break
|
|
118
165
|
|
|
119
166
|
let k = src.slice (start, eq)
|
|
120
|
-
|
|
167
|
+
|
|
121
168
|
if (start === 0) {
|
|
122
|
-
|
|
123
|
-
let p = k.length - 2; while (p !== 0 && k.charCodeAt (p) <= 32) p --
|
|
124
169
|
|
|
125
|
-
|
|
170
|
+
let p = k.length - 1; while (p !== 0 && k.charCodeAt (p) > 32) p --
|
|
171
|
+
|
|
172
|
+
k = k.slice (this._afterName = ++ p)
|
|
126
173
|
|
|
127
174
|
}
|
|
128
175
|
else {
|
package/lib/XMLLexer.js
CHANGED
|
@@ -38,14 +38,10 @@ const XMLLexer = class extends Transform {
|
|
|
38
38
|
assert (Number.isInteger (maxLength), 'maxLength must be integer, not ' + maxLength)
|
|
39
39
|
assert (maxLength > 0, 'maxLength must be positive, not ' + maxLength)
|
|
40
40
|
|
|
41
|
-
if (!('stripSpace' in options)) options.stripSpace = false
|
|
42
|
-
assert (options.stripSpace === true || options.stripSpace === false, 'options.stripSpace must be boolean, not ' + typeof options.stripSpace)
|
|
43
|
-
|
|
44
41
|
super (options)
|
|
45
42
|
|
|
46
43
|
this.decoder = new StringDecoder ('utf8')
|
|
47
44
|
|
|
48
|
-
this.stripSpace = options.stripSpace
|
|
49
45
|
this.body = ''
|
|
50
46
|
this.start = 0
|
|
51
47
|
this.setState (ST_TEXT)
|
|
@@ -237,8 +233,6 @@ const XMLLexer = class extends Transform {
|
|
|
237
233
|
|
|
238
234
|
this.start = pos
|
|
239
235
|
|
|
240
|
-
if (this.stripSpace) lexeme = lexeme.trim ()
|
|
241
|
-
|
|
242
236
|
if (lexeme.length !== 0) this.push (lexeme)
|
|
243
237
|
|
|
244
238
|
}
|
package/lib/XMLNode.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
const SAXEvent = require ('./SAXEvent.js')
|
|
2
|
+
const AttributesMap = require ('./AttributesMap')
|
|
3
|
+
const NamespacesMap = require ('./NamespacesMap')
|
|
4
|
+
|
|
5
|
+
const XML_READER = Symbol ('_xmlReader')
|
|
6
|
+
const ATTRIBUTES = Symbol ('_attributes')
|
|
7
|
+
const TYPE = Symbol ('_type')
|
|
8
|
+
const PARENT = Symbol ('_parent')
|
|
9
|
+
const LEVEL = Symbol ('_level')
|
|
10
|
+
const NS_MAP = Symbol ('_ns_map')
|
|
11
|
+
|
|
12
|
+
const XMLNode = class extends SAXEvent {
|
|
13
|
+
|
|
14
|
+
constructor (src, xmlReader, _type) {
|
|
15
|
+
|
|
16
|
+
super (src)
|
|
17
|
+
|
|
18
|
+
this [TYPE] = _type || super.type
|
|
19
|
+
|
|
20
|
+
this [XML_READER] = xmlReader
|
|
21
|
+
this [PARENT] = null
|
|
22
|
+
this [LEVEL] = 0
|
|
23
|
+
|
|
24
|
+
this.children = null
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
cloneStart () {
|
|
29
|
+
|
|
30
|
+
let e = new XMLNode (this.src, this [XML_READER], SAXEvent.TYPES.START_ELEMENT)
|
|
31
|
+
|
|
32
|
+
e [PARENT] = this [PARENT]
|
|
33
|
+
e [LEVEL] = this [LEVEL]
|
|
34
|
+
e [ATTRIBUTES] = this [ATTRIBUTES]
|
|
35
|
+
e [NS_MAP] = this [NS_MAP]
|
|
36
|
+
|
|
37
|
+
return e
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get level () {
|
|
42
|
+
|
|
43
|
+
return this [LEVEL]
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get parent () {
|
|
48
|
+
|
|
49
|
+
return this [PARENT]
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get namespacesMap () {
|
|
54
|
+
|
|
55
|
+
return this [NS_MAP]
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
readNamespaces () {
|
|
60
|
+
|
|
61
|
+
this [NS_MAP] = new NamespacesMap (this)
|
|
62
|
+
|
|
63
|
+
this.readAttributes ()
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
set parent (_parent) {
|
|
68
|
+
|
|
69
|
+
if (_parent == null) return
|
|
70
|
+
|
|
71
|
+
this [PARENT] = _parent
|
|
72
|
+
|
|
73
|
+
this [LEVEL] = 1 + _parent.level
|
|
74
|
+
|
|
75
|
+
const {children} = _parent; if (children !== null) children.push (this)
|
|
76
|
+
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get type () {
|
|
80
|
+
|
|
81
|
+
return this [TYPE]
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
set type (_type) {
|
|
86
|
+
|
|
87
|
+
this [TYPE] = _type
|
|
88
|
+
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get localName () {
|
|
92
|
+
|
|
93
|
+
return XMLNode.getLocalName (this.name)
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get namespaceURI () {
|
|
98
|
+
|
|
99
|
+
return this.namespacesMap.getNamespaceURI (this.name, true)
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
readAttributes () {
|
|
104
|
+
|
|
105
|
+
const m = new AttributesMap (this [XML_READER], this [NS_MAP])
|
|
106
|
+
|
|
107
|
+
this.writeAttributesToMap (m)
|
|
108
|
+
|
|
109
|
+
this [ATTRIBUTES] = m
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get attributes () {
|
|
114
|
+
|
|
115
|
+
if (!(ATTRIBUTES in this)) this.readAttributes ()
|
|
116
|
+
|
|
117
|
+
return this [ATTRIBUTES]
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get text () {
|
|
122
|
+
|
|
123
|
+
let s = super.text
|
|
124
|
+
|
|
125
|
+
if (this [TYPE] === SAXEvent.TYPES.CHARACTERS) s = this [XML_READER].fixText (s)
|
|
126
|
+
|
|
127
|
+
return s
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
XMLNode.getLocalName = name => {
|
|
134
|
+
|
|
135
|
+
const pos = name.indexOf (':'); if (pos === -1) return name
|
|
136
|
+
|
|
137
|
+
return name.slice (pos + 1)
|
|
138
|
+
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = XMLNode
|
package/lib/XMLReader.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
const assert = require ('assert')
|
|
2
|
+
const {Transform} = require ('stream')
|
|
3
|
+
const SAXEvent = require ('./SAXEvent.js')
|
|
4
|
+
const XMLNode = require ('./XMLNode.js')
|
|
5
|
+
const XMLLexer = require ('./XMLLexer.js')
|
|
6
|
+
|
|
7
|
+
const OPT_SRC = Symbol ('_src')
|
|
8
|
+
const OPT_SAX = Symbol ('_sax')
|
|
9
|
+
|
|
10
|
+
const XMLReader = class extends Transform {
|
|
11
|
+
|
|
12
|
+
constructor (options = {}) {
|
|
13
|
+
|
|
14
|
+
options.decodeStrings = false
|
|
15
|
+
options.objectMode = true
|
|
16
|
+
|
|
17
|
+
if (!('stripSpace' in options)) options.stripSpace = false
|
|
18
|
+
assert (options.stripSpace === true || options.stripSpace === false, 'options.stripSpace must be boolean, not ' + typeof options.stripSpace)
|
|
19
|
+
|
|
20
|
+
if (!('useEntities' in options)) options.useEntities = true
|
|
21
|
+
assert (options.useEntities === true || options.useEntities === false, 'options.useEntities must be boolean, not ' + typeof options.useEntities)
|
|
22
|
+
|
|
23
|
+
if (!('useNamespaces' in options)) options.useNamespaces = true
|
|
24
|
+
assert (options.useNamespaces === true || options.useNamespaces === false, 'options.useNamespaces must be boolean, not ' + typeof options.useNamespaces)
|
|
25
|
+
|
|
26
|
+
let {filterElements} = options; delete options.filterElements; if (filterElements != null) {
|
|
27
|
+
|
|
28
|
+
assert (!('filter' in options), 'filter and filterElements options cannot be set simultaneously')
|
|
29
|
+
|
|
30
|
+
switch (typeof filterElements) {
|
|
31
|
+
|
|
32
|
+
case 'string':
|
|
33
|
+
const localName = filterElements
|
|
34
|
+
filterElements = e => e.localName === localName
|
|
35
|
+
|
|
36
|
+
case 'function':
|
|
37
|
+
options.filter = e => e.type === SAXEvent.TYPES.END_ELEMENT && filterElements (e)
|
|
38
|
+
break
|
|
39
|
+
|
|
40
|
+
default:
|
|
41
|
+
assert.fail ('options.filterElements must be a string or function')
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let {collect} = options; delete options.collect
|
|
48
|
+
assert (collect == null || typeof collect === 'function', 'options.collect must be a function, not ' + typeof collect)
|
|
49
|
+
if (collect == null && filterElements != null) collect = filterElements
|
|
50
|
+
|
|
51
|
+
const {filter} = options; delete options.filter
|
|
52
|
+
assert (filter == null || typeof filter === 'function', 'options.filter must be a function, not ' + typeof filter)
|
|
53
|
+
|
|
54
|
+
const {map} = options; delete options.map
|
|
55
|
+
assert (map == null || typeof map === 'function', 'options.map must be a function, not ' + typeof map)
|
|
56
|
+
|
|
57
|
+
super (options)
|
|
58
|
+
|
|
59
|
+
this.stripSpace = options.stripSpace
|
|
60
|
+
this.useEntities = options.useEntities
|
|
61
|
+
this.useNamespaces = options.useNamespaces
|
|
62
|
+
this.collect = collect || null
|
|
63
|
+
this.filter = filter || null
|
|
64
|
+
this.map = map || null
|
|
65
|
+
|
|
66
|
+
if (this.useEntities) this.entityResolver = new (require ('./EntityResolver.js')) ()
|
|
67
|
+
|
|
68
|
+
this.text = ''
|
|
69
|
+
this.element = null
|
|
70
|
+
this.position = 0n
|
|
71
|
+
|
|
72
|
+
this [OPT_SRC] = null; this.on ('pipe', src => this [OPT_SRC] = src)
|
|
73
|
+
|
|
74
|
+
this [OPT_SAX] = null
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async findFirst () {
|
|
79
|
+
|
|
80
|
+
assert (!this.isSAX, 'SAX event subscriber detected, findFirst () cannot be used')
|
|
81
|
+
|
|
82
|
+
return new Promise ((ok, fail) => {
|
|
83
|
+
|
|
84
|
+
this.once ('error', fail)
|
|
85
|
+
|
|
86
|
+
const THE_END = 'finish', nope = () => ok (null)
|
|
87
|
+
|
|
88
|
+
this.on (THE_END, nope)
|
|
89
|
+
|
|
90
|
+
this.on ('data', e => {
|
|
91
|
+
|
|
92
|
+
this.off (THE_END, nope)
|
|
93
|
+
|
|
94
|
+
if (e.type === SAXEvent.TYPES.END_DOCUMENT) return nope ()
|
|
95
|
+
|
|
96
|
+
const src = this [OPT_SRC]; if (src !== null) src.unpipe (this)
|
|
97
|
+
|
|
98
|
+
ok (e)
|
|
99
|
+
|
|
100
|
+
this.destroy ()
|
|
101
|
+
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
process (src, lexerOptions = {}) {
|
|
109
|
+
|
|
110
|
+
const lex = new XMLLexer (lexerOptions)
|
|
111
|
+
|
|
112
|
+
lex.once ('error', x => this.destroy (x))
|
|
113
|
+
|
|
114
|
+
lex.pipe (this)
|
|
115
|
+
|
|
116
|
+
if (Buffer.isBuffer (src) || typeof src === 'string') lex.end (src); else src.pipe (lex)
|
|
117
|
+
|
|
118
|
+
return this
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
_flush (callback) {
|
|
123
|
+
|
|
124
|
+
this.flush_text ()
|
|
125
|
+
|
|
126
|
+
this.publish (new XMLNode ('', this), SAXEvent.TYPES.END_DOCUMENT)
|
|
127
|
+
|
|
128
|
+
callback ()
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get isSAX () {
|
|
133
|
+
|
|
134
|
+
const v = this [OPT_SAX]; if (v !== null) return v
|
|
135
|
+
|
|
136
|
+
for (const type of Object.values (SAXEvent.TYPES)) if (this.listenerCount (type) !== 0) return this [OPT_SAX] = true
|
|
137
|
+
|
|
138
|
+
return this [OPT_SAX] = false
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
publish (xmlNode, type = null) {
|
|
143
|
+
|
|
144
|
+
if (type !== null) xmlNode.type = type
|
|
145
|
+
|
|
146
|
+
const {filter} = this; if (filter !== null && !filter (xmlNode)) return
|
|
147
|
+
|
|
148
|
+
const {map} = this, value = map === null ? xmlNode : map (xmlNode)
|
|
149
|
+
|
|
150
|
+
if (this.isSAX) {
|
|
151
|
+
|
|
152
|
+
this.emit (xmlNode.type, value)
|
|
153
|
+
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
|
|
157
|
+
this.push (value)
|
|
158
|
+
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
flush_text () {
|
|
164
|
+
|
|
165
|
+
let {text} = this; if (text.length === 0) return
|
|
166
|
+
|
|
167
|
+
if (this.stripSpace) text = text.trim ()
|
|
168
|
+
|
|
169
|
+
if (text.length !== 0) {
|
|
170
|
+
|
|
171
|
+
let e = new XMLNode (text, this, SAXEvent.TYPES.CHARACTERS)
|
|
172
|
+
|
|
173
|
+
e.parent = this.element
|
|
174
|
+
|
|
175
|
+
this.publish (e)
|
|
176
|
+
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
this.text = ''
|
|
180
|
+
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
get fixText () {
|
|
184
|
+
|
|
185
|
+
if (!this.useEntities) return s => s
|
|
186
|
+
|
|
187
|
+
const {entityResolver} = this
|
|
188
|
+
|
|
189
|
+
return s => entityResolver.fix (s)
|
|
190
|
+
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
_transform (chunk, encoding, callback) {
|
|
194
|
+
|
|
195
|
+
const {length} = chunk; if (length !== 0) {
|
|
196
|
+
|
|
197
|
+
let e = new XMLNode (chunk, this), {type} = e, {element} = this
|
|
198
|
+
|
|
199
|
+
switch (type) {
|
|
200
|
+
|
|
201
|
+
case SAXEvent.TYPES.CHARACTERS:
|
|
202
|
+
case SAXEvent.TYPES.CDATA:
|
|
203
|
+
|
|
204
|
+
this.text += e.text
|
|
205
|
+
return callback ()
|
|
206
|
+
|
|
207
|
+
default:
|
|
208
|
+
|
|
209
|
+
this.flush_text ()
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
switch (type) {
|
|
214
|
+
|
|
215
|
+
case SAXEvent.TYPES.END_ELEMENT:
|
|
216
|
+
|
|
217
|
+
if (element === null) throw new Error (`Unbalanced end element tag "${chunk}" occured at position ${this.position}`)
|
|
218
|
+
|
|
219
|
+
e = element
|
|
220
|
+
|
|
221
|
+
e.type = type
|
|
222
|
+
|
|
223
|
+
this.element = element.parent
|
|
224
|
+
|
|
225
|
+
break
|
|
226
|
+
|
|
227
|
+
default:
|
|
228
|
+
|
|
229
|
+
e.parent = element
|
|
230
|
+
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const isStart = type === SAXEvent.TYPES.START_ELEMENT
|
|
234
|
+
|
|
235
|
+
if (isStart && this.useNamespaces) e.readNamespaces ()
|
|
236
|
+
|
|
237
|
+
this.publish (isStart ? e.cloneStart () : e)
|
|
238
|
+
|
|
239
|
+
if (isStart) {
|
|
240
|
+
|
|
241
|
+
if (e.isSelfEnclosed) {
|
|
242
|
+
|
|
243
|
+
this.publish (e, SAXEvent.TYPES.END_ELEMENT)
|
|
244
|
+
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
|
|
248
|
+
if (
|
|
249
|
+
|
|
250
|
+
(this.element !== null && this.element.children !== null)
|
|
251
|
+
|
|
252
|
+
||
|
|
253
|
+
|
|
254
|
+
(this.collect !== null && this.collect (e))
|
|
255
|
+
|
|
256
|
+
) e.children = []
|
|
257
|
+
|
|
258
|
+
this.element = e
|
|
259
|
+
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
this.position += BigInt (length)
|
|
265
|
+
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
callback ()
|
|
269
|
+
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
module.exports = XMLReader
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xml-toolkit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Collection of classes for dealing with XML",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
"url": "git+https://github.com/do-/node-xml-toolkit.git"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
|
-
"xml
|
|
14
|
+
"xml",
|
|
15
|
+
"sax",
|
|
16
|
+
"stax"
|
|
15
17
|
],
|
|
16
18
|
"author": "Dmitry Ovsyanko",
|
|
17
19
|
"license": "MIT",
|
package/test/ent.xml
ADDED
package/test/soap.xml
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<?xml version="1.0"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
|
2
|
+
<SOAP-ENV:Header/>
|
|
3
|
+
<SOAP-ENV:Body>
|
|
4
|
+
<SendRequestRequest xmlns="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1" xmlns:ns0="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/basic/1.1">
|
|
5
|
+
<SenderProvidedRequestData Id="Ue7e71ce1-7ce3-4ca5-a689-1a8f2edbb1af">
|
|
6
|
+
<MessageID>3931cda8-3245-11ec-b0bc-000c293433a0</MessageID>
|
|
7
|
+
<ns0:MessagePrimaryContent>
|
|
8
|
+
<ExportDebtRequestsRequest xmlns="urn:dom.gosuslugi.ru/debt-responses/1.0.0" xmlns:ns0="urn:dom.gosuslugi.ru/common/1.2.0">
|
|
9
|
+
<ns0:information-system-id ns0:foo="bar" foo="baz">1f0823b4-9c11-4622-a561-6bae5c0a00ba</ns0:information-system-id>
|
|
10
|
+
<ns0:organization-id>6eef689e-48bb-4eb0-55da-18b6db9909b7</ns0:organization-id>
|
|
11
|
+
<request-id>87c4c940-6ad3-11eb-9439-0242ac130002</request-id>
|
|
12
|
+
</ExportDebtRequestsRequest>
|
|
13
|
+
</ns0:MessagePrimaryContent>
|
|
14
|
+
<TestMessage xmlns:ns1="urn://x-artefacts-smev-gov-ru/services/message-exchange/types/1.1"/>
|
|
15
|
+
</SenderProvidedRequestData>
|
|
16
|
+
<CallerInformationSystemSignature>
|
|
17
|
+
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
|
18
|
+
<ds:SignedInfo>
|
|
19
|
+
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
20
|
+
<ds:SignatureMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34102012-gostr34112012-256"/>
|
|
21
|
+
<ds:Reference URI="#Ue7e71ce1-7ce3-4ca5-a689-1a8f2edbb1af">
|
|
22
|
+
<ds:Transforms>
|
|
23
|
+
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
24
|
+
<ds:Transform Algorithm="urn://smev-gov-ru/xmldsig/transform"/>
|
|
25
|
+
</ds:Transforms>
|
|
26
|
+
<ds:DigestMethod Algorithm="urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34112012-256"/>
|
|
27
|
+
<ds:DigestValue>XrXb2BlS8uo68tyQ++KE1yPjj5y3TynCaRIpXeL5uPk=</ds:DigestValue>
|
|
28
|
+
</ds:Reference>
|
|
29
|
+
</ds:SignedInfo>
|
|
30
|
+
<ds:SignatureValue>9Th1waEJy83XQxxKD5DXT29g885RhJoYe3ZQ1HrbrQLCEBchCCTJtcThYmNBPL/HzF2gp7KQs3gXrnsj+OBlJQ==</ds:SignatureValue>
|
|
31
|
+
<ds:KeyInfo>
|
|
32
|
+
<ds:X509Data>
|
|
33
|
+
<ds:X509Certificate>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</ds:X509Certificate>
|
|
34
|
+
</ds:X509Data>
|
|
35
|
+
</ds:KeyInfo>
|
|
36
|
+
</ds:Signature>
|
|
37
|
+
</CallerInformationSystemSignature>
|
|
38
|
+
</SendRequestRequest>
|
|
39
|
+
</SOAP-ENV:Body>
|
|
40
|
+
</SOAP-ENV:Envelope>
|
package/test/test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require ('fs')
|
|
2
2
|
const assert = require ('assert')
|
|
3
|
-
const {
|
|
3
|
+
const {XMLReader, SAXEvent, XMLLexer, AttributesMap, MoxyLikeJsonEncoder} = require ('../')
|
|
4
4
|
|
|
5
5
|
async function test_001_lexer_sync (fn) {
|
|
6
6
|
|
|
@@ -52,38 +52,51 @@ async function test_003_emitter_sync (fn) {
|
|
|
52
52
|
|
|
53
53
|
const xml = fs.readFileSync (
|
|
54
54
|
'test/' + fn
|
|
55
|
-
|
|
55
|
+
, 'utf-8'
|
|
56
56
|
)
|
|
57
57
|
|
|
58
58
|
console.log (xml)
|
|
59
59
|
|
|
60
|
-
const
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
|
|
60
|
+
const sax = new XMLReader ({
|
|
61
|
+
// stripSpace: true,
|
|
62
|
+
// filterElements: 'SendRequestRequest',
|
|
63
|
+
// map: MoxyLikeJsonEncoder ({wrap: 1})
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
lex.pipe (sax)
|
|
69
|
-
|
|
66
|
+
/*
|
|
70
67
|
for (let event of [
|
|
71
|
-
'
|
|
72
|
-
'
|
|
73
|
-
'
|
|
74
|
-
'
|
|
75
|
-
'
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
]) sax.on (event, data => console.log ([event, data]))
|
|
80
|
-
|
|
81
|
-
// lexer.on ('data', data => console.log ({data}))
|
|
68
|
+
'data',
|
|
69
|
+
'close',
|
|
70
|
+
'end',
|
|
71
|
+
'finish',
|
|
72
|
+
// 'EndElement',
|
|
73
|
+
]) sax.on (event, data => {
|
|
74
|
+
|
|
75
|
+
console.log ([JSON.stringify (data, null, 2), event])
|
|
82
76
|
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
})
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// sax.process (fs.createReadStream ('test/' + fn))
|
|
82
|
+
|
|
83
|
+
sax.process (xml)
|
|
84
|
+
|
|
85
|
+
//console.log (sax)
|
|
86
|
+
//console.log (sax.isSAX)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
let s = ''
|
|
90
|
+
for await (const {type, src, xml, parent} of sax) {
|
|
91
|
+
s += xml
|
|
92
|
+
// console.log ([type, src, xml, (parent || {}).localName])
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log ([xml, s])
|
|
96
|
+
|
|
97
|
+
// const v = await sax.findFirst ()
|
|
85
98
|
|
|
86
|
-
|
|
99
|
+
// console.log (JSON.stringify (v, null, 2))
|
|
87
100
|
|
|
88
101
|
}
|
|
89
102
|
|
|
@@ -92,13 +105,15 @@ async function main () {
|
|
|
92
105
|
// await test_001_lexer_sync ('E05a.xml')
|
|
93
106
|
// await test_001_lexer_sync ('not-sa01.xml')
|
|
94
107
|
// await test_001_lexer_sync ('not-sa02.xml')
|
|
95
|
-
await test_001_lexer_sync ('param_types.xml')
|
|
108
|
+
// await test_001_lexer_sync ('param_types.xml')
|
|
96
109
|
// await test_002_lexer_stream ('E05a.xml')
|
|
97
110
|
// await test_002_lexer_stream ('param_types.xml')
|
|
98
111
|
// await test_002_lexer_stream ('not-sa02.xml')
|
|
99
112
|
// await test_003_emitter_sync ('E05a.xml')
|
|
100
113
|
// await test_003_emitter_sync ('param_types.xml')
|
|
101
114
|
// await test_003_emitter_sync ('not-sa01.xml')
|
|
115
|
+
// await test_003_emitter_sync ('ent.xml')
|
|
116
|
+
await test_003_emitter_sync ('soap.xml')
|
|
102
117
|
|
|
103
118
|
}
|
|
104
119
|
|
package/lib/SAXEventEmitter.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const assert = require ('assert')
|
|
2
|
-
const {Writable} = require ('stream')
|
|
3
|
-
const SAXEvent = require ('./SAXEvent.js')
|
|
4
|
-
|
|
5
|
-
const SAXEventEmitter = class extends Writable {
|
|
6
|
-
|
|
7
|
-
constructor (options = {}) {
|
|
8
|
-
|
|
9
|
-
options.decodeStrings = false
|
|
10
|
-
|
|
11
|
-
super (options)
|
|
12
|
-
|
|
13
|
-
this.on ('finish', () => this.emit (SAXEvent.TYPES.END_DOCUMENT))
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
_write (chunk, encoding, callback) {
|
|
18
|
-
|
|
19
|
-
if (chunk.length !== 0) {
|
|
20
|
-
|
|
21
|
-
let e = new SAXEvent (chunk), {type} = e
|
|
22
|
-
|
|
23
|
-
if (type === SAXEvent.TYPES.CDATA) {
|
|
24
|
-
e = new SAXEvent (e.text)
|
|
25
|
-
type = SAXEvent.TYPES.CHARACTERS
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
this.emit (type, e)
|
|
29
|
-
|
|
30
|
-
if (type === SAXEvent.TYPES.TYPE_START_ELEMENT && e.isSelfEnclosing ()) {
|
|
31
|
-
this.emit (SAXEvent.TYPES.TYPE_END_ELEMENT, e)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
callback ()
|
|
37
|
-
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
module.exports = SAXEventEmitter
|