xml-toolkit 0.0.3 → 0.0.4
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 -5
- package/lib/AttributesMap.js +53 -16
- package/lib/MoxyLikeJsonEncoder.js +41 -0
- package/lib/NamespacesMap.js +48 -0
- package/lib/SAXEvent.js +34 -1
- package/lib/XMLNode.js +128 -0
- package/lib/XMLReader.js +149 -15
- package/package.json +1 -1
- package/test/soap.xml +40 -0
- package/test/test.js +37 -12
- package/lib/SAXEventEmitter.js +0 -15
package/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
const XMLLexer
|
|
2
|
-
const
|
|
3
|
-
const SAXEvent
|
|
4
|
-
const AttributesMap
|
|
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')
|
|
5
6
|
|
|
6
|
-
module.exports = {
|
|
7
|
+
module.exports = {XMLLexer, XMLReader, SAXEvent, AttributesMap, MoxyLikeJsonEncoder}
|
package/lib/AttributesMap.js
CHANGED
|
@@ -1,35 +1,72 @@
|
|
|
1
|
+
const CH_COLON = ':'.charCodeAt (0)
|
|
2
|
+
|
|
1
3
|
const AttributesMap = class extends Map {
|
|
2
4
|
|
|
3
|
-
constructor (xmlReader) {
|
|
5
|
+
constructor (xmlReader, nsMap = null) {
|
|
4
6
|
|
|
5
7
|
super ()
|
|
6
|
-
|
|
8
|
+
|
|
7
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)
|
|
8
31
|
|
|
9
|
-
this.
|
|
10
|
-
|
|
11
|
-
if (xmlReader.useEntities) {
|
|
32
|
+
for (const k of this._nsMap.getQNames (name, namespaceURI)) {
|
|
12
33
|
|
|
13
|
-
|
|
34
|
+
if (!this.has (k)) continue
|
|
14
35
|
|
|
15
|
-
this.
|
|
16
|
-
|
|
17
|
-
}
|
|
36
|
+
return this.get (k)
|
|
18
37
|
|
|
38
|
+
}
|
|
39
|
+
|
|
19
40
|
}
|
|
20
41
|
|
|
21
42
|
set (k, v) {
|
|
22
43
|
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
+
}
|
|
28
65
|
|
|
29
66
|
}
|
|
30
67
|
|
|
31
|
-
return super.set (k, v)
|
|
32
|
-
|
|
68
|
+
return super.set (k, this.fixText (v))
|
|
69
|
+
|
|
33
70
|
}
|
|
34
71
|
|
|
35
72
|
}
|
|
@@ -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 = 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
|
|
|
@@ -106,6 +107,38 @@ const SAXEvent = class {
|
|
|
106
107
|
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
get name () {
|
|
111
|
+
|
|
112
|
+
if (this._afterName === 0) this.findAfterName ()
|
|
113
|
+
|
|
114
|
+
const {src} = this, start = src.charCodeAt (1) === CH_SLASH ? 2 : 1
|
|
115
|
+
|
|
116
|
+
return this.src.slice (start, this._afterName).trim ()
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
findAfterName () {
|
|
121
|
+
|
|
122
|
+
const {src} = this, {length} = src;
|
|
123
|
+
|
|
124
|
+
for (let i = 1; i < length; i ++) {
|
|
125
|
+
|
|
126
|
+
const c = src.charCodeAt (i)
|
|
127
|
+
|
|
128
|
+
switch (c) {
|
|
129
|
+
case CH_SLASH:
|
|
130
|
+
case CH_GT:
|
|
131
|
+
return this._afterName = i
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (c <= 32) return this._afterName = i
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
this._afterName = length - 1
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
109
142
|
writeAttributesToMap (m) {
|
|
110
143
|
|
|
111
144
|
const {src} = this
|
package/lib/XMLNode.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
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
|
+
get level () {
|
|
29
|
+
|
|
30
|
+
return this [LEVEL]
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get parent () {
|
|
35
|
+
|
|
36
|
+
return this [PARENT]
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get namespacesMap () {
|
|
41
|
+
|
|
42
|
+
return this [NS_MAP]
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
readNamespaces () {
|
|
47
|
+
|
|
48
|
+
this [NS_MAP] = new NamespacesMap (this)
|
|
49
|
+
|
|
50
|
+
this.readAttributes ()
|
|
51
|
+
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
set parent (_parent) {
|
|
55
|
+
|
|
56
|
+
if (_parent == null) return
|
|
57
|
+
|
|
58
|
+
this [PARENT] = _parent
|
|
59
|
+
|
|
60
|
+
this [LEVEL] = 1 + _parent.level
|
|
61
|
+
|
|
62
|
+
const {children} = _parent; if (children !== null) children.push (this)
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get type () {
|
|
67
|
+
|
|
68
|
+
return this [TYPE]
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
set type (_type) {
|
|
73
|
+
|
|
74
|
+
this [TYPE] = _type
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get localName () {
|
|
79
|
+
|
|
80
|
+
return XMLNode.getLocalName (this.name)
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
get namespaceURI () {
|
|
85
|
+
|
|
86
|
+
return this.namespacesMap.getNamespaceURI (this.name, true)
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
readAttributes () {
|
|
91
|
+
|
|
92
|
+
const m = new AttributesMap (this [XML_READER], this [NS_MAP])
|
|
93
|
+
|
|
94
|
+
this.writeAttributesToMap (m)
|
|
95
|
+
|
|
96
|
+
this [ATTRIBUTES] = m
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get attributes () {
|
|
101
|
+
|
|
102
|
+
if (!(ATTRIBUTES in this)) this.readAttributes ()
|
|
103
|
+
|
|
104
|
+
return this [ATTRIBUTES]
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get text () {
|
|
109
|
+
|
|
110
|
+
let s = super.text
|
|
111
|
+
|
|
112
|
+
if (this [TYPE] === SAXEvent.TYPES.CHARACTERS) s = this [XML_READER].fixText (s)
|
|
113
|
+
|
|
114
|
+
return s
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
XMLNode.getLocalName = name => {
|
|
121
|
+
|
|
122
|
+
const pos = name.indexOf (':'); if (pos === -1) return name
|
|
123
|
+
|
|
124
|
+
return name.slice (pos + 1)
|
|
125
|
+
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = XMLNode
|
package/lib/XMLReader.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
const assert = require ('assert')
|
|
2
2
|
const {Transform} = require ('stream')
|
|
3
3
|
const SAXEvent = require ('./SAXEvent.js')
|
|
4
|
+
const XMLNode = require ('./XMLNode.js')
|
|
5
|
+
|
|
6
|
+
const OPT_ONCE = Symbol ('_once')
|
|
7
|
+
const OPT_SRC = Symbol ('_src')
|
|
8
|
+
const OPT_SAX = Symbol ('_sax')
|
|
4
9
|
|
|
5
10
|
const XMLReader = class extends Transform {
|
|
6
11
|
|
|
@@ -15,14 +20,41 @@ const XMLReader = class extends Transform {
|
|
|
15
20
|
if (!('useEntities' in options)) options.useEntities = true
|
|
16
21
|
assert (options.useEntities === true || options.useEntities === false, 'options.useEntities must be boolean, not ' + typeof options.useEntities)
|
|
17
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
|
+
const {collect} = options; delete options.collect
|
|
27
|
+
assert (collect == null || typeof collect === 'function', 'options.collect must be a function, not ' + typeof collect)
|
|
28
|
+
|
|
29
|
+
const {filter} = options; delete options.filter
|
|
30
|
+
assert (filter == null || typeof filter === 'function', 'options.filter must be a function, not ' + typeof filter)
|
|
31
|
+
|
|
32
|
+
const {map} = options; delete options.map
|
|
33
|
+
assert (map == null || typeof map === 'function', 'options.map must be a function, not ' + typeof map)
|
|
34
|
+
|
|
35
|
+
const {find} = options; delete options.find
|
|
36
|
+
assert (filter == null || find == null, 'filter & find options cannot be set together')
|
|
37
|
+
assert (find == null || typeof find === 'function', 'options.find must be a function, not ' + typeof find)
|
|
38
|
+
|
|
18
39
|
super (options)
|
|
19
40
|
|
|
20
|
-
this.stripSpace
|
|
21
|
-
this.useEntities
|
|
22
|
-
|
|
41
|
+
this.stripSpace = options.stripSpace
|
|
42
|
+
this.useEntities = options.useEntities
|
|
43
|
+
this.useNamespaces = options.useNamespaces
|
|
44
|
+
this.collect = collect || null
|
|
45
|
+
this.filter = filter || find || null
|
|
46
|
+
this.map = map || null
|
|
47
|
+
this [OPT_ONCE] = find != null
|
|
48
|
+
|
|
23
49
|
if (this.useEntities) this.entityResolver = new (require ('./EntityResolver.js')) ()
|
|
24
50
|
|
|
25
51
|
this.text = ''
|
|
52
|
+
this.element = null
|
|
53
|
+
this.position = 0n
|
|
54
|
+
|
|
55
|
+
this [OPT_SRC] = null; this.on ('pipe', src => this [OPT_SRC] = src)
|
|
56
|
+
|
|
57
|
+
this [OPT_SAX] = null
|
|
26
58
|
|
|
27
59
|
}
|
|
28
60
|
|
|
@@ -30,11 +62,50 @@ const XMLReader = class extends Transform {
|
|
|
30
62
|
|
|
31
63
|
this.flush_text ()
|
|
32
64
|
|
|
33
|
-
this.
|
|
65
|
+
this.publish ({type: SAXEvent.TYPES.END_DOCUMENT})
|
|
34
66
|
|
|
35
67
|
callback ()
|
|
36
68
|
|
|
37
69
|
}
|
|
70
|
+
|
|
71
|
+
get isSAX () {
|
|
72
|
+
|
|
73
|
+
const v = this [OPT_SAX]; if (v !== null) return v
|
|
74
|
+
|
|
75
|
+
for (const type in SAXEvent.TYPES) if (this.listenerCount (type) !== 0) return this [OPT_SAX] = true
|
|
76
|
+
|
|
77
|
+
return this [OPT_SAX] = false
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
publish (xmlNode, type = null) {
|
|
82
|
+
|
|
83
|
+
if (type !== null) xmlNode.type = type
|
|
84
|
+
|
|
85
|
+
const {filter} = this; if (filter !== null && !filter (xmlNode)) return
|
|
86
|
+
|
|
87
|
+
const {map} = this, value = map === null ? xmlNode : map (xmlNode)
|
|
88
|
+
|
|
89
|
+
if (this.isSAX) {
|
|
90
|
+
|
|
91
|
+
this.emit (xmlNode.type, value)
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
|
|
96
|
+
this.push (value)
|
|
97
|
+
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (this [OPT_ONCE]) {
|
|
101
|
+
|
|
102
|
+
const src = this [OPT_SRC]; if (src !== null) src.unpipe (this)
|
|
103
|
+
|
|
104
|
+
this.destroy ()
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
}
|
|
38
109
|
|
|
39
110
|
flush_text () {
|
|
40
111
|
|
|
@@ -42,41 +113,104 @@ const XMLReader = class extends Transform {
|
|
|
42
113
|
|
|
43
114
|
if (this.stripSpace) text = text.trim ()
|
|
44
115
|
|
|
45
|
-
if (text.length !== 0)
|
|
116
|
+
if (text.length !== 0) {
|
|
117
|
+
|
|
118
|
+
let e = new XMLNode (text, this, SAXEvent.TYPES.CHARACTERS)
|
|
119
|
+
|
|
120
|
+
e.parent = this.element
|
|
121
|
+
|
|
122
|
+
this.publish (e)
|
|
123
|
+
|
|
124
|
+
}
|
|
46
125
|
|
|
47
126
|
this.text = ''
|
|
48
127
|
|
|
49
128
|
}
|
|
129
|
+
|
|
130
|
+
get fixText () {
|
|
131
|
+
|
|
132
|
+
if (!this.useEntities) return s => s
|
|
133
|
+
|
|
134
|
+
const {entityResolver} = this
|
|
135
|
+
|
|
136
|
+
return s => entityResolver.fix (s)
|
|
137
|
+
|
|
138
|
+
}
|
|
50
139
|
|
|
51
140
|
_transform (chunk, encoding, callback) {
|
|
52
141
|
|
|
53
|
-
if (
|
|
142
|
+
const {length} = chunk; if (length !== 0) {
|
|
54
143
|
|
|
55
|
-
let e = new
|
|
144
|
+
let e = new XMLNode (chunk, this), {type} = e, {element} = this
|
|
56
145
|
|
|
57
146
|
switch (type) {
|
|
58
147
|
|
|
59
148
|
case SAXEvent.TYPES.CHARACTERS:
|
|
60
|
-
|
|
61
|
-
this.text += this.useEntities ? this.entityResolver.fix (e.text) : e.text
|
|
62
|
-
break
|
|
63
|
-
|
|
64
149
|
case SAXEvent.TYPES.CDATA:
|
|
65
150
|
|
|
66
151
|
this.text += e.text
|
|
67
|
-
|
|
152
|
+
return callback ()
|
|
68
153
|
|
|
69
154
|
default:
|
|
70
155
|
|
|
71
156
|
this.flush_text ()
|
|
72
|
-
|
|
157
|
+
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
switch (type) {
|
|
161
|
+
|
|
162
|
+
case SAXEvent.TYPES.END_ELEMENT:
|
|
163
|
+
|
|
164
|
+
if (element === null) throw new Error (`Unbalanced end element tag "${chunk}" occured at position ${this.position}`)
|
|
165
|
+
|
|
166
|
+
e = element
|
|
167
|
+
|
|
168
|
+
e.type = type
|
|
169
|
+
|
|
170
|
+
this.element = element.parent
|
|
171
|
+
|
|
73
172
|
break
|
|
74
173
|
|
|
174
|
+
default:
|
|
175
|
+
|
|
176
|
+
e.parent = element
|
|
177
|
+
|
|
75
178
|
}
|
|
76
179
|
|
|
77
|
-
|
|
180
|
+
const isStart = type === SAXEvent.TYPES.START_ELEMENT
|
|
78
181
|
|
|
79
|
-
|
|
182
|
+
if (isStart && this.useNamespaces) e.readNamespaces ()
|
|
183
|
+
|
|
184
|
+
this.publish (e)
|
|
185
|
+
|
|
186
|
+
if (isStart) {
|
|
187
|
+
|
|
188
|
+
if (e.isSelfEnclosed) {
|
|
189
|
+
|
|
190
|
+
this.publish (e, SAXEvent.TYPES.END_ELEMENT)
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
|
|
195
|
+
if (
|
|
196
|
+
|
|
197
|
+
(this.element !== null && this.element.children !== null)
|
|
198
|
+
|
|
199
|
+
||
|
|
200
|
+
|
|
201
|
+
(this.collect !== null && this.collect (e))
|
|
202
|
+
|
|
203
|
+
) e.children = []
|
|
204
|
+
|
|
205
|
+
this.element = e
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.position += BigInt (length)
|
|
212
|
+
|
|
213
|
+
}
|
|
80
214
|
|
|
81
215
|
callback ()
|
|
82
216
|
|
package/package.json
CHANGED
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
|
|
|
@@ -63,14 +63,22 @@ console.log (xml)
|
|
|
63
63
|
// stripSpace: true,
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
-
const sax = new
|
|
66
|
+
const sax = new XMLReader ({
|
|
67
67
|
stripSpace: true,
|
|
68
|
+
collect: e => true,
|
|
69
|
+
find: e => true
|
|
70
|
+
// && e.type === SAXEvent.TYPES.CHARACTERS
|
|
71
|
+
&& e.localName === 'SendRequestRequest'
|
|
72
|
+
&& e.type === SAXEvent.TYPES.END_ELEMENT
|
|
73
|
+
// && e.level === 6
|
|
74
|
+
,
|
|
75
|
+
map: MoxyLikeJsonEncoder ({wrap: 1})
|
|
68
76
|
// useEntities: false,
|
|
69
77
|
})
|
|
70
78
|
|
|
71
79
|
lex.pipe (sax)
|
|
72
80
|
|
|
73
|
-
|
|
81
|
+
|
|
74
82
|
for (let event of [
|
|
75
83
|
'StartDocument',
|
|
76
84
|
'ProcessingInstruction',
|
|
@@ -80,21 +88,37 @@ console.log (xml)
|
|
|
80
88
|
'Characters',
|
|
81
89
|
'EndElement',
|
|
82
90
|
'EndDocument',
|
|
83
|
-
]) sax.on (event, data =>
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
-
sax.on ('StartElement', event => {
|
|
91
|
+
]) sax.on (event, data => {
|
|
87
92
|
|
|
88
|
-
console.log (
|
|
93
|
+
// console.log ([event, data])
|
|
89
94
|
|
|
90
|
-
|
|
95
|
+
console.log (JSON.stringify (data, null, 2))
|
|
96
|
+
|
|
97
|
+
/*
|
|
98
|
+
console.log ([event, data, data.name, data.localName, data.namespaceURI])
|
|
91
99
|
|
|
92
|
-
|
|
100
|
+
const {attributes} = data; for (const [k, v] of attributes.entries ()) {
|
|
93
101
|
|
|
94
|
-
|
|
102
|
+
console.log ([k, attributes.getLocalName (k), attributes.getNamespaceURI (k), v])
|
|
103
|
+
|
|
104
|
+
console.log ([attributes.get ('ns0:foo')])
|
|
105
|
+
|
|
106
|
+
console.log ([attributes.get ('foo')])
|
|
107
|
+
|
|
108
|
+
console.log ([attributes.get ('foo', 'urn:dom.gosuslugi.ru/common/1.2.0')])
|
|
95
109
|
|
|
110
|
+
}
|
|
111
|
+
*/
|
|
96
112
|
})
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
97
116
|
|
|
117
|
+
/*
|
|
118
|
+
sax.on ('StartElement', event => {
|
|
119
|
+
console.log ([event, event.attributes])
|
|
120
|
+
})
|
|
121
|
+
*/
|
|
98
122
|
// lexer.on ('data', data => console.log ({data}))
|
|
99
123
|
|
|
100
124
|
// for (let c of xml) lexer.write (c); lexer.end ()
|
|
@@ -116,7 +140,8 @@ async function main () {
|
|
|
116
140
|
// await test_003_emitter_sync ('E05a.xml')
|
|
117
141
|
// await test_003_emitter_sync ('param_types.xml')
|
|
118
142
|
// await test_003_emitter_sync ('not-sa01.xml')
|
|
119
|
-
await test_003_emitter_sync ('ent.xml')
|
|
143
|
+
// await test_003_emitter_sync ('ent.xml')
|
|
144
|
+
await test_003_emitter_sync ('soap.xml')
|
|
120
145
|
|
|
121
146
|
}
|
|
122
147
|
|
package/lib/SAXEventEmitter.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
const XMLReader = require ('./XMLReader.js')
|
|
2
|
-
|
|
3
|
-
const SAXEventEmitter = class extends XMLReader {
|
|
4
|
-
|
|
5
|
-
constructor (options = {}) {
|
|
6
|
-
|
|
7
|
-
super (options)
|
|
8
|
-
|
|
9
|
-
this.on ('data', e => this.emit (e.type, e))
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
module.exports = SAXEventEmitter
|