xml-toolkit 1.0.16 → 1.0.18
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/README.md +18 -1
- package/index.js +3 -0
- package/lib/AttributesMap.js +13 -5
- package/lib/SAXEvent.js +23 -13
- package/lib/XMLIterator.js +57 -0
- package/lib/XMLNode.js +70 -9
- package/lib/XMLParser.js +86 -0
- package/lib/XMLReader.js +3 -13
- package/lib/XMLSchema.js +15 -5
- package/lib/XMLSchemata.js +48 -1
- package/package.json +1 -1
- package/test/test.js +128 -110
package/README.md
CHANGED
|
@@ -8,6 +8,23 @@ npm i xml-toolkit
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
# Using
|
|
11
|
+
|
|
12
|
+
* [Parsing a small file completely](XMLParser)
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
const fs = require ('fs')
|
|
16
|
+
const {XMLParser} = require ('xml-toolkit')
|
|
17
|
+
|
|
18
|
+
const xml = fs.readFileSync ('doc.xml')
|
|
19
|
+
const parser = new XMLParser ({...options})
|
|
20
|
+
|
|
21
|
+
const document = parser.process (xml)
|
|
22
|
+
|
|
23
|
+
for (const element of document.detach ().children) {
|
|
24
|
+
console.log (element.attributes)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
11
28
|
* [Reading a Record List](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Reading-a-Record-List)
|
|
12
29
|
|
|
13
30
|
```js
|
|
@@ -65,7 +82,7 @@ const data = {ExportDebtRequestsResponse: {
|
|
|
65
82
|
}
|
|
66
83
|
}
|
|
67
84
|
|
|
68
|
-
const xs =
|
|
85
|
+
const xs = new XMLSchemata ('xs.xsd')
|
|
69
86
|
|
|
70
87
|
const xml = xs.stringify (data)
|
|
71
88
|
|
package/index.js
CHANGED
package/lib/AttributesMap.js
CHANGED
|
@@ -2,15 +2,13 @@ const CH_COLON = ':'.charCodeAt (0)
|
|
|
2
2
|
|
|
3
3
|
const AttributesMap = class extends Map {
|
|
4
4
|
|
|
5
|
-
constructor (
|
|
5
|
+
constructor (entityResolver = null, nsMap = null) {
|
|
6
6
|
|
|
7
7
|
super ()
|
|
8
8
|
|
|
9
|
-
this.
|
|
9
|
+
this.entityResolver = entityResolver
|
|
10
10
|
this._nsMap = nsMap
|
|
11
11
|
|
|
12
|
-
this.fixText = xmlReader.fixText
|
|
13
|
-
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
getLocalName (name) {
|
|
@@ -65,7 +63,17 @@ const AttributesMap = class extends Map {
|
|
|
65
63
|
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
|
|
66
|
+
const {entityResolver} = this
|
|
67
|
+
|
|
68
|
+
return super.set (k,
|
|
69
|
+
|
|
70
|
+
v === '' ? null :
|
|
71
|
+
|
|
72
|
+
entityResolver === null ? v :
|
|
73
|
+
|
|
74
|
+
entityResolver.fix (v)
|
|
75
|
+
|
|
76
|
+
)
|
|
69
77
|
|
|
70
78
|
}
|
|
71
79
|
|
package/lib/SAXEvent.js
CHANGED
|
@@ -7,7 +7,7 @@ const CH_QUESTION = '?'.charCodeAt (0)
|
|
|
7
7
|
const CH_SLASH = '/'.charCodeAt (0)
|
|
8
8
|
const CH_MINUS = '-'.charCodeAt (0)
|
|
9
9
|
|
|
10
|
-
const STR_XML = '
|
|
10
|
+
const STR_XML = 'xml'
|
|
11
11
|
const STR_CDATA = '[CDATA['
|
|
12
12
|
const STR_DOCTYPE = 'DOCTYPE'
|
|
13
13
|
|
|
@@ -46,14 +46,8 @@ const SAXEvent = class {
|
|
|
46
46
|
return END_ELEMENT
|
|
47
47
|
|
|
48
48
|
case CH_QUESTION:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
case STR_XML: return START_DOCUMENT
|
|
53
|
-
|
|
54
|
-
default: return PROCESSING_INSTRUCTION
|
|
55
|
-
|
|
56
|
-
}
|
|
49
|
+
|
|
50
|
+
return src.slice (2, 5) === STR_XML ? START_DOCUMENT : PROCESSING_INSTRUCTION
|
|
57
51
|
|
|
58
52
|
case CH_EXCLAMATION:
|
|
59
53
|
|
|
@@ -123,19 +117,19 @@ const SAXEvent = class {
|
|
|
123
117
|
|
|
124
118
|
get name () {
|
|
125
119
|
|
|
126
|
-
if (this._afterName === 0) this.findAfterName ()
|
|
127
|
-
|
|
128
120
|
const {src} = this, start = src.charCodeAt (1) === CH_SLASH ? 2 : 1
|
|
129
121
|
|
|
122
|
+
if (this._afterName === 0) this.findAfterName (start)
|
|
123
|
+
|
|
130
124
|
return this.src.slice (start, this._afterName).trim ()
|
|
131
125
|
|
|
132
126
|
}
|
|
133
127
|
|
|
134
|
-
findAfterName () {
|
|
128
|
+
findAfterName (start) {
|
|
135
129
|
|
|
136
130
|
const {src} = this, {length} = src;
|
|
137
131
|
|
|
138
|
-
for (let i =
|
|
132
|
+
for (let i = start; i < length; i ++) {
|
|
139
133
|
|
|
140
134
|
const c = src.charCodeAt (i)
|
|
141
135
|
|
|
@@ -228,4 +222,20 @@ SAXEvent.TYPES = {
|
|
|
228
222
|
CDATA,
|
|
229
223
|
}
|
|
230
224
|
|
|
225
|
+
SAXEvent.KET = new Map ([
|
|
226
|
+
|
|
227
|
+
[START_DOCUMENT, '?>'],
|
|
228
|
+
[PROCESSING_INSTRUCTION, '?>'],
|
|
229
|
+
|
|
230
|
+
[START_ELEMENT, '>'],
|
|
231
|
+
[END_ELEMENT, '>'],
|
|
232
|
+
[DTD, '>'],
|
|
233
|
+
|
|
234
|
+
[CDATA, ']]>'],
|
|
235
|
+
[COMMENT, '-->'],
|
|
236
|
+
|
|
237
|
+
[CHARACTERS, '<'],
|
|
238
|
+
|
|
239
|
+
])
|
|
240
|
+
|
|
231
241
|
module.exports = SAXEvent
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const XMLNode = require ('./XMLNode.js')
|
|
2
|
+
const SAXEvent = require ('./SAXEvent.js')
|
|
3
|
+
const EntityResolver = require ('./EntityResolver.js')
|
|
4
|
+
|
|
5
|
+
const XMLIterator = class {
|
|
6
|
+
|
|
7
|
+
constructor (src, options = {}) {
|
|
8
|
+
|
|
9
|
+
this.src = src
|
|
10
|
+
this.options = options
|
|
11
|
+
this.pos = 0
|
|
12
|
+
this.selfEnclosed = null
|
|
13
|
+
this.entityResolver = options.entityResolver || new EntityResolver ()
|
|
14
|
+
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
[Symbol.iterator] () {
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
autoClose () {
|
|
22
|
+
|
|
23
|
+
let value = this.selfEnclosed
|
|
24
|
+
|
|
25
|
+
value.type = SAXEvent.TYPES.END_ELEMENT
|
|
26
|
+
|
|
27
|
+
this.selfEnclosed = null
|
|
28
|
+
|
|
29
|
+
return {value}
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
next () {
|
|
34
|
+
|
|
35
|
+
if (this.selfEnclosed !== null) return this.autoClose ()
|
|
36
|
+
|
|
37
|
+
const {src, pos, entityResolver} = this
|
|
38
|
+
|
|
39
|
+
if (src.length - pos < 1) return {done: true}
|
|
40
|
+
|
|
41
|
+
const value = new XMLNode (src.slice (pos), entityResolver)
|
|
42
|
+
|
|
43
|
+
value.trim ()
|
|
44
|
+
|
|
45
|
+
const {length} = value.src; if (length === 0) return {done: true}
|
|
46
|
+
|
|
47
|
+
this.pos += length
|
|
48
|
+
|
|
49
|
+
if (value.isStartElement && value.isSelfEnclosed) this.selfEnclosed = value
|
|
50
|
+
|
|
51
|
+
return {value}
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = XMLIterator
|
package/lib/XMLNode.js
CHANGED
|
@@ -3,7 +3,7 @@ const AttributesMap = require ('./AttributesMap')
|
|
|
3
3
|
const NamespacesMap = require ('./NamespacesMap')
|
|
4
4
|
const MoxyLikeJsonEncoder = require ('./MoxyLikeJsonEncoder')
|
|
5
5
|
|
|
6
|
-
const
|
|
6
|
+
const ENTITY_RESOLVER = Symbol ('_entityResolver')
|
|
7
7
|
const ATTRIBUTES = Symbol ('_attributes')
|
|
8
8
|
const TYPE = Symbol ('_type')
|
|
9
9
|
const PARENT = Symbol ('_parent')
|
|
@@ -16,13 +16,13 @@ const m2o =
|
|
|
16
16
|
|
|
17
17
|
const XMLNode = class extends SAXEvent {
|
|
18
18
|
|
|
19
|
-
constructor (src,
|
|
19
|
+
constructor (src, entityResolver = null, _type) {
|
|
20
20
|
|
|
21
21
|
super (src)
|
|
22
22
|
|
|
23
23
|
this [TYPE] = _type || super.type
|
|
24
24
|
|
|
25
|
-
this [
|
|
25
|
+
this [ENTITY_RESOLVER] = entityResolver
|
|
26
26
|
this [PARENT] = null
|
|
27
27
|
this [LEVEL] = 0
|
|
28
28
|
|
|
@@ -32,7 +32,7 @@ const XMLNode = class extends SAXEvent {
|
|
|
32
32
|
|
|
33
33
|
cloneStart () {
|
|
34
34
|
|
|
35
|
-
let e = new XMLNode (this.src, this [
|
|
35
|
+
let e = new XMLNode (this.src, this [ENTITY_RESOLVER], SAXEvent.TYPES.START_ELEMENT)
|
|
36
36
|
|
|
37
37
|
e [PARENT] = this [PARENT]
|
|
38
38
|
e [LEVEL] = this [LEVEL]
|
|
@@ -110,7 +110,7 @@ const XMLNode = class extends SAXEvent {
|
|
|
110
110
|
|
|
111
111
|
readAttributes () {
|
|
112
112
|
|
|
113
|
-
const m = new AttributesMap (this [
|
|
113
|
+
const m = new AttributesMap (this [ENTITY_RESOLVER], this [NS_MAP])
|
|
114
114
|
|
|
115
115
|
this.writeAttributesToMap (m)
|
|
116
116
|
|
|
@@ -129,22 +129,53 @@ const XMLNode = class extends SAXEvent {
|
|
|
129
129
|
get text () {
|
|
130
130
|
|
|
131
131
|
let s = super.text
|
|
132
|
+
|
|
133
|
+
if (this [TYPE] === SAXEvent.TYPES.CHARACTERS) {
|
|
134
|
+
|
|
135
|
+
const entityResolver = this [ENTITY_RESOLVER]
|
|
136
|
+
|
|
137
|
+
if (entityResolver) return entityResolver.fix (s)
|
|
132
138
|
|
|
133
|
-
|
|
139
|
+
}
|
|
134
140
|
|
|
135
141
|
return s
|
|
136
142
|
|
|
137
143
|
}
|
|
138
144
|
|
|
145
|
+
detach_children (list, o = {}) {
|
|
146
|
+
|
|
147
|
+
if (!Array.isArray (list) || list.length === 0) return []
|
|
148
|
+
|
|
149
|
+
let last = null, a = []; for (const i of list) {
|
|
150
|
+
|
|
151
|
+
const d = i.detach (); if (d === null) continue
|
|
152
|
+
|
|
153
|
+
if (d instanceof String && last instanceof String) {
|
|
154
|
+
|
|
155
|
+
last += d
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
|
|
160
|
+
a.push (last = d)
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return a
|
|
167
|
+
|
|
168
|
+
}
|
|
169
|
+
|
|
139
170
|
detach (o = {}) {
|
|
140
171
|
|
|
141
172
|
switch (this.type) {
|
|
142
|
-
|
|
173
|
+
|
|
143
174
|
case SAXEvent.TYPES.CHARACTERS:
|
|
144
175
|
case SAXEvent.TYPES.CDATA:
|
|
145
176
|
return this.text
|
|
146
177
|
|
|
147
|
-
|
|
178
|
+
case SAXEvent.TYPES.END_ELEMENT:
|
|
148
179
|
|
|
149
180
|
const {localName, namespaceURI, attributes, children, namespacesMap} = this
|
|
150
181
|
|
|
@@ -152,16 +183,46 @@ const XMLNode = class extends SAXEvent {
|
|
|
152
183
|
localName,
|
|
153
184
|
namespaceURI,
|
|
154
185
|
attributes : m2o (attributes),
|
|
155
|
-
children :
|
|
186
|
+
children : this.detach_children (children, o),
|
|
156
187
|
}
|
|
157
188
|
|
|
158
189
|
if (o.nsMap) r.namespacesMap = m2o (namespacesMap || [])
|
|
159
190
|
|
|
160
191
|
return r
|
|
192
|
+
|
|
193
|
+
default:
|
|
161
194
|
|
|
195
|
+
return null
|
|
196
|
+
|
|
162
197
|
}
|
|
163
198
|
|
|
164
199
|
}
|
|
200
|
+
|
|
201
|
+
trim () {
|
|
202
|
+
|
|
203
|
+
const {src, type} = this, ket = SAXEvent.KET.get (type)
|
|
204
|
+
|
|
205
|
+
let pos = src.indexOf (ket)
|
|
206
|
+
|
|
207
|
+
if (ket !== '<') {
|
|
208
|
+
|
|
209
|
+
if (pos === -1) {
|
|
210
|
+
|
|
211
|
+
const max = 20
|
|
212
|
+
|
|
213
|
+
let txt = src; if (txt.length > max) txt = txt.slice (0, max) + '...'
|
|
214
|
+
|
|
215
|
+
throw new Error (`Unfinished ${type}: ${txt}`)
|
|
216
|
+
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
pos += ket.length
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
this.src = src.slice (0, pos)
|
|
224
|
+
|
|
225
|
+
}
|
|
165
226
|
|
|
166
227
|
}
|
|
167
228
|
|
package/lib/XMLParser.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const assert = require ('assert')
|
|
2
|
+
const SAXEvent = require ('./SAXEvent.js')
|
|
3
|
+
const XMLNode = require ('./XMLNode.js')
|
|
4
|
+
const XMLIterator = require ('./XMLIterator.js')
|
|
5
|
+
|
|
6
|
+
const XMLReader = class {
|
|
7
|
+
|
|
8
|
+
constructor (options = {}) {
|
|
9
|
+
|
|
10
|
+
if (!('stripSpace' in options)) options.stripSpace = true
|
|
11
|
+
assert (options.stripSpace === true || options.stripSpace === false, 'options.stripSpace must be boolean, not ' + typeof options.stripSpace)
|
|
12
|
+
|
|
13
|
+
if (!('useEntities' in options)) options.useEntities = true
|
|
14
|
+
assert (options.useEntities === true || options.useEntities === false, 'options.useEntities must be boolean, not ' + typeof options.useEntities)
|
|
15
|
+
|
|
16
|
+
if (!('useNamespaces' in options)) options.useNamespaces = true
|
|
17
|
+
assert (options.useNamespaces === true || options.useNamespaces === false, 'options.useNamespaces must be boolean, not ' + typeof options.useNamespaces)
|
|
18
|
+
|
|
19
|
+
this.stripSpace = options.stripSpace
|
|
20
|
+
this.useEntities = options.useEntities
|
|
21
|
+
this.useNamespaces = options.useNamespaces
|
|
22
|
+
|
|
23
|
+
if (this.useEntities) this.entityResolver = new (require ('./EntityResolver.js')) ()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
process (src) {
|
|
29
|
+
|
|
30
|
+
this.text = ''
|
|
31
|
+
this.document = null
|
|
32
|
+
this.element = null
|
|
33
|
+
|
|
34
|
+
const {entityResolver} = this, nodes = new XMLIterator (src, {entityResolver})
|
|
35
|
+
|
|
36
|
+
for (const node of nodes) {
|
|
37
|
+
|
|
38
|
+
let {type} = node
|
|
39
|
+
|
|
40
|
+
switch (type) {
|
|
41
|
+
|
|
42
|
+
case SAXEvent.TYPES.CHARACTERS:
|
|
43
|
+
case SAXEvent.TYPES.CDATA:
|
|
44
|
+
|
|
45
|
+
this.text += node.text
|
|
46
|
+
continue
|
|
47
|
+
|
|
48
|
+
default:
|
|
49
|
+
|
|
50
|
+
if (this.text.length === 0) break
|
|
51
|
+
if (this.stripSpace) this.text = this.text.trim ()
|
|
52
|
+
if (this.text.length === 0) break
|
|
53
|
+
(new XMLNode (this.text, this.entityResolver, SAXEvent.TYPES.CHARACTERS)).parent = this.element
|
|
54
|
+
this.text = ''
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
switch (type) {
|
|
59
|
+
|
|
60
|
+
case SAXEvent.TYPES.START_ELEMENT:
|
|
61
|
+
|
|
62
|
+
node.children = []
|
|
63
|
+
node.parent = this.element
|
|
64
|
+
if (this.useNamespaces) node.readNamespaces ()
|
|
65
|
+
this.element = node
|
|
66
|
+
if (this.document === null) this.document = node
|
|
67
|
+
break
|
|
68
|
+
|
|
69
|
+
case SAXEvent.TYPES.END_ELEMENT:
|
|
70
|
+
|
|
71
|
+
if (this.element === null) throw new Error (`Unbalanced end element tag "${node.text}" occured at position ${nodes.pos}`)
|
|
72
|
+
this.element.type = type
|
|
73
|
+
this.element = this.element.parent
|
|
74
|
+
break
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return this.document
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
module.exports = XMLReader
|
package/lib/XMLReader.js
CHANGED
|
@@ -123,7 +123,7 @@ const XMLReader = class extends Transform {
|
|
|
123
123
|
|
|
124
124
|
this.flush_text ()
|
|
125
125
|
|
|
126
|
-
this.publish (new XMLNode ('', this), SAXEvent.TYPES.END_DOCUMENT)
|
|
126
|
+
this.publish (new XMLNode ('', this.entityResolver), SAXEvent.TYPES.END_DOCUMENT)
|
|
127
127
|
|
|
128
128
|
callback ()
|
|
129
129
|
|
|
@@ -168,7 +168,7 @@ const XMLReader = class extends Transform {
|
|
|
168
168
|
|
|
169
169
|
if (text.length !== 0) {
|
|
170
170
|
|
|
171
|
-
let e = new XMLNode (text, this, SAXEvent.TYPES.CHARACTERS)
|
|
171
|
+
let e = new XMLNode (text, this.entityResolver, SAXEvent.TYPES.CHARACTERS)
|
|
172
172
|
|
|
173
173
|
e.parent = this.element
|
|
174
174
|
|
|
@@ -179,22 +179,12 @@ const XMLReader = class extends Transform {
|
|
|
179
179
|
this.text = ''
|
|
180
180
|
|
|
181
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
182
|
|
|
193
183
|
_transform (chunk, encoding, callback) {
|
|
194
184
|
|
|
195
185
|
const {length} = chunk; if (length !== 0) {
|
|
196
186
|
|
|
197
|
-
let e = new XMLNode (chunk, this), {type} = e, {element} = this
|
|
187
|
+
let e = new XMLNode (chunk, this.entityResolver), {type} = e, {element} = this
|
|
198
188
|
|
|
199
189
|
switch (type) {
|
|
200
190
|
|
package/lib/XMLSchema.js
CHANGED
|
@@ -23,7 +23,9 @@ const XMLSchema = class extends Map {
|
|
|
23
23
|
|
|
24
24
|
for (const e of children) {
|
|
25
25
|
|
|
26
|
-
const {
|
|
26
|
+
const {attributes} = e; if (!('name' in attributes)) continue
|
|
27
|
+
|
|
28
|
+
const {name} = attributes
|
|
27
29
|
|
|
28
30
|
this.set (name, e)
|
|
29
31
|
|
|
@@ -45,15 +47,23 @@ const XMLSchema = class extends Map {
|
|
|
45
47
|
|
|
46
48
|
}
|
|
47
49
|
|
|
48
|
-
XMLSchema.adjustNode = node => {
|
|
50
|
+
XMLSchema.adjustNode = (node, recurse) => {
|
|
49
51
|
|
|
50
|
-
if (node.children)
|
|
52
|
+
if (node.children) {
|
|
51
53
|
|
|
54
|
+
node.children = node.children.filter (i => i.localName !== 'annotation')
|
|
55
|
+
|
|
56
|
+
if (recurse) node.children = node.children.map (node => XMLSchema.adjustNode (node, true))
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
52
60
|
const {attributes, namespacesMap} = node, splitNs = name => {
|
|
53
61
|
|
|
54
62
|
if (!attributes.has (name)) return
|
|
55
|
-
|
|
56
|
-
const
|
|
63
|
+
|
|
64
|
+
const v = attributes.get (name); if (Array.isArray (v)) return
|
|
65
|
+
|
|
66
|
+
const [local, prefix] = v.split (':').reverse ()
|
|
57
67
|
|
|
58
68
|
attributes.set (name, [local, namespacesMap.get (prefix || '')])
|
|
59
69
|
|
package/lib/XMLSchemata.js
CHANGED
|
@@ -3,6 +3,7 @@ const assert = require ('assert')
|
|
|
3
3
|
const fs = require ('fs')
|
|
4
4
|
const path = require ('path')
|
|
5
5
|
|
|
6
|
+
const XMLParser = require ('./XMLParser.js')
|
|
6
7
|
const XMLReader = require ('./XMLReader.js')
|
|
7
8
|
const XMLNode = require ('./XMLNode.js')
|
|
8
9
|
const XMLSchema = require ('./XMLSchema.js'), {adjustNode} = XMLSchema
|
|
@@ -13,11 +14,17 @@ const IDX = Symbol ('_index')
|
|
|
13
14
|
|
|
14
15
|
const XMLSchemata = class extends Map {
|
|
15
16
|
|
|
16
|
-
constructor () {
|
|
17
|
+
constructor (fn) {
|
|
17
18
|
|
|
18
19
|
super ()
|
|
19
20
|
|
|
20
21
|
this [IDX] = new Map ()
|
|
22
|
+
|
|
23
|
+
if (fn) {
|
|
24
|
+
this.parser = new XMLParser ()
|
|
25
|
+
this.addFileSync (fn)
|
|
26
|
+
delete this.parser
|
|
27
|
+
}
|
|
21
28
|
|
|
22
29
|
}
|
|
23
30
|
|
|
@@ -126,6 +133,46 @@ const XMLSchemata = class extends Map {
|
|
|
126
133
|
|
|
127
134
|
}
|
|
128
135
|
|
|
136
|
+
addSchemaSync (node, options = {}) {
|
|
137
|
+
|
|
138
|
+
if (node.localName !== 'schema' || node.namespaceURI !== XMLSchema.namespaceURI) {
|
|
139
|
+
|
|
140
|
+
for (const i of node.children) this.addSchemaSync (i, options)
|
|
141
|
+
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
node = adjustNode (node, true).detach ()
|
|
147
|
+
|
|
148
|
+
let targetNamespace = node.attributes.targetNamespace || options.targetNamespace
|
|
149
|
+
|
|
150
|
+
if (!this.has (targetNamespace)) this.set (targetNamespace, new XMLSchema (this, targetNamespace))
|
|
151
|
+
|
|
152
|
+
const {addLocation} = options; for (const {localName, namespaceURI, attributes} of node.children)
|
|
153
|
+
|
|
154
|
+
if (localName === 'import' && namespaceURI === XMLSchema.namespaceURI)
|
|
155
|
+
|
|
156
|
+
addLocation (attributes.schemaLocation, attributes.namespace)
|
|
157
|
+
|
|
158
|
+
this.get (targetNamespace).add (node)
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
addFileSync (fn, options = {}) {
|
|
163
|
+
|
|
164
|
+
const dirname = path.dirname (fn), that = this
|
|
165
|
+
|
|
166
|
+
options.addLocation = function (schemaLocation, namespace) {
|
|
167
|
+
|
|
168
|
+
that.addFileSync (path.join (dirname, schemaLocation), {targetNamespace: namespace})
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.addSchemaSync (this.parser.process (fs.readFileSync (fn, 'utf-8')), options)
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
129
176
|
}
|
|
130
177
|
|
|
131
178
|
XMLSchemata.fromFile = async function (fn, options = {}) {
|
package/package.json
CHANGED
package/test/test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require ('fs')
|
|
2
2
|
const assert = require ('assert')
|
|
3
|
-
const {XMLReader, SAXEvent, XMLLexer, AttributesMap, XMLNode, XMLSchemata, SOAP11} = require ('../')
|
|
3
|
+
const {XMLReader, SAXEvent, XMLLexer, AttributesMap, XMLNode, XMLSchemata, SOAP11, EntityResolver, XMLIterator, XMLParser} = require ('../')
|
|
4
4
|
|
|
5
5
|
async function test_001_lexer_sync (fn) {
|
|
6
6
|
|
|
@@ -15,8 +15,15 @@ console.log (xml)
|
|
|
15
15
|
// maxLength: 40,
|
|
16
16
|
// encoding: 'ascii',
|
|
17
17
|
})
|
|
18
|
+
|
|
18
19
|
|
|
19
|
-
lexer.on ('data', data =>
|
|
20
|
+
lexer.on ('data', data => {
|
|
21
|
+
|
|
22
|
+
const e = new SAXEvent (data)
|
|
23
|
+
|
|
24
|
+
console.log ([e, e.type])
|
|
25
|
+
|
|
26
|
+
})
|
|
20
27
|
|
|
21
28
|
// for (let c of xml) lexer.write (c); lexer.end ()
|
|
22
29
|
// for (let c of xml) lexer.write (Buffer.from ([c])); lexer.end ()
|
|
@@ -106,6 +113,7 @@ console.log (xml)
|
|
|
106
113
|
async function test_004_schemata (fn) {
|
|
107
114
|
|
|
108
115
|
let xs = await XMLSchemata.fromFile ('test/dom-gosuslugi-ru-smev3-debt-responses.xsd')
|
|
116
|
+
let xss = new XMLSchemata ('test/dom-gosuslugi-ru-smev3-debt-responses.xsd')
|
|
109
117
|
/*
|
|
110
118
|
const localName = 'ImportDebtRequestsRequest'
|
|
111
119
|
|
|
@@ -120,7 +128,7 @@ async function test_004_schemata (fn) {
|
|
|
120
128
|
}))
|
|
121
129
|
*/
|
|
122
130
|
|
|
123
|
-
|
|
131
|
+
const d = {
|
|
124
132
|
"ExportDebtRequestsResponse": {
|
|
125
133
|
"request-data": {
|
|
126
134
|
"request-id": "bac4c940-6ad3-11eb-9439-0242ac130002",
|
|
@@ -205,7 +213,9 @@ async function test_004_schemata (fn) {
|
|
|
205
213
|
}
|
|
206
214
|
}
|
|
207
215
|
}
|
|
208
|
-
}
|
|
216
|
+
}
|
|
217
|
+
console.log (xs.stringify (d))
|
|
218
|
+
console.log (xss.stringify (d))
|
|
209
219
|
|
|
210
220
|
//getNamespacePrefixesMap
|
|
211
221
|
/*
|
|
@@ -219,6 +229,9 @@ async function test_004_schemata (fn) {
|
|
|
219
229
|
console.log (xs.stringify ({
|
|
220
230
|
"ExportDebtRequestsRequest": {Id: 1}
|
|
221
231
|
}))
|
|
232
|
+
console.log (xss.stringify ({
|
|
233
|
+
"ExportDebtRequestsRequest": {Id: 1}
|
|
234
|
+
}))
|
|
222
235
|
|
|
223
236
|
// console.log (xs.get ('urn:dom.gosuslugi.ru/debt-responses/1.0.0').get ('AttachmentType'))
|
|
224
237
|
|
|
@@ -227,6 +240,7 @@ async function test_004_schemata (fn) {
|
|
|
227
240
|
async function test_005_schemata (fn) {
|
|
228
241
|
|
|
229
242
|
const xs = await XMLSchemata.fromFile ('test/20040.wsdl')
|
|
243
|
+
const xss = new XMLSchemata ('test/20040.wsdl')
|
|
230
244
|
|
|
231
245
|
const data = {
|
|
232
246
|
|
|
@@ -267,26 +281,26 @@ async function test_005_schemata (fn) {
|
|
|
267
281
|
|
|
268
282
|
// const m = xs.createMarshaller ('AppDataChildDotation', 'http://smev.gosuslugi.ru/rev111111')
|
|
269
283
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
AppData: {
|
|
278
|
-
info
|
|
279
|
-
}
|
|
284
|
+
const d = {childDotation2Request: {
|
|
285
|
+
Message: {
|
|
286
|
+
TestMsg: "Тестовый запроc",
|
|
287
|
+
},
|
|
288
|
+
MessageData: {
|
|
289
|
+
AppData: {
|
|
290
|
+
info
|
|
280
291
|
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
|
|
292
|
+
}
|
|
293
|
+
}}
|
|
294
|
+
|
|
295
|
+
console.log (xs.stringify (d))
|
|
296
|
+
console.log (xss.stringify (d))
|
|
284
297
|
|
|
285
298
|
}
|
|
286
299
|
|
|
287
300
|
async function test_006_schemata (fn) {
|
|
288
301
|
|
|
289
302
|
const xs = await XMLSchemata.fromFile ('test/snils-by-additionalData-1.0.1.xsd')
|
|
303
|
+
const xss = new XMLSchemata ('test/snils-by-additionalData-1.0.1.xsd')
|
|
290
304
|
|
|
291
305
|
const data = {
|
|
292
306
|
"SnilsByAdditionalDataRequest": {
|
|
@@ -314,6 +328,7 @@ async function test_006_schemata (fn) {
|
|
|
314
328
|
// const m = xs.createMarshaller ('AppDataChildDotation', 'http://smev.gosuslugi.ru/rev111111')
|
|
315
329
|
|
|
316
330
|
console.log (xs.stringify (data))
|
|
331
|
+
console.log (xss.stringify (data))
|
|
317
332
|
|
|
318
333
|
}
|
|
319
334
|
|
|
@@ -323,115 +338,111 @@ async function test_007_wsdl (fn) {
|
|
|
323
338
|
|
|
324
339
|
console.log (soap.http ({GetForm9Sync: {address: {Region: {Code: 78}}}}))
|
|
325
340
|
|
|
341
|
+
console.log (soap)
|
|
342
|
+
|
|
326
343
|
}
|
|
327
344
|
|
|
328
345
|
async function test_008_schemata (fn) {
|
|
329
346
|
|
|
330
|
-
const xs = await XMLSchemata.fromFile ('test/
|
|
347
|
+
const xs = await XMLSchemata.fromFile ('test/30017.xsd')
|
|
348
|
+
const xss = new XMLSchemata ('test/30017.xsd')
|
|
331
349
|
|
|
332
350
|
const data =
|
|
333
351
|
|
|
334
|
-
{
|
|
335
|
-
|
|
336
|
-
"
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
"
|
|
346
|
-
"
|
|
347
|
-
|
|
348
|
-
"FirstName": "ИВАН",
|
|
349
|
-
"Patronymic": "ИВАНОВИЧ"
|
|
350
|
-
},
|
|
351
|
-
"УдЛичнФЛ": {
|
|
352
|
-
"DocumentCode": "21",
|
|
353
|
-
"SeriesNumber": "0000 000000"
|
|
354
|
-
}
|
|
355
|
-
},
|
|
356
|
-
"СвНА": {
|
|
357
|
-
"СвНАФЛ": {
|
|
358
|
-
"ИННФЛ": "100000000074",
|
|
359
|
-
"ФИО": {
|
|
360
|
-
"FamilyName": "ИВАНОВ",
|
|
361
|
-
"FirstName": "ИВАН",
|
|
362
|
-
"Patronymic": "ИВАНОВИЧ"
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
},
|
|
366
|
-
"СведДох_2НДФЛ": {
|
|
367
|
-
"Ставка": "13",
|
|
368
|
-
"ДохВыч": {
|
|
369
|
-
"СвСумДох": [
|
|
370
|
-
{
|
|
371
|
-
"Месяц": "01",
|
|
372
|
-
"КодДоход": "2000",
|
|
373
|
-
"СумДоход": "1000.12"
|
|
374
|
-
},
|
|
375
|
-
{
|
|
376
|
-
"Месяц": "02",
|
|
377
|
-
"КодДоход": "2000",
|
|
378
|
-
"СумДоход": "2000.12"
|
|
379
|
-
}
|
|
380
|
-
]
|
|
381
|
-
},
|
|
382
|
-
"СГДНалПер": {
|
|
383
|
-
"СумДохОбщ": "3000.24",
|
|
384
|
-
"НалБаза": "3000.24"
|
|
385
|
-
}
|
|
386
|
-
}
|
|
352
|
+
{"FNSINNSingularRequest":
|
|
353
|
+
{
|
|
354
|
+
"СведЮЛ": {
|
|
355
|
+
"ОГРН":"1037843048880",
|
|
356
|
+
"ИННЮЛ":"7825497650",
|
|
357
|
+
"НаимОрг":"Нагрузочное тестирование"
|
|
358
|
+
},
|
|
359
|
+
"СведФЛ": {
|
|
360
|
+
"ДатаРожд":"1973-07-14",
|
|
361
|
+
"МестоРожд":null,
|
|
362
|
+
"ФИО":{
|
|
363
|
+
"Фамилия":"ВАЛЕРЬЕВНА",
|
|
364
|
+
"Имя":"1973-07-14",
|
|
365
|
+
"Отчество":"1973-07-14"
|
|
387
366
|
},
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
"УдЛичнФЛ": {
|
|
398
|
-
"DocumentCode": "21",
|
|
399
|
-
"SeriesNumber": "0000 000000"
|
|
400
|
-
}
|
|
401
|
-
},
|
|
402
|
-
"СвНА": {
|
|
403
|
-
"СвНАЮЛ": {
|
|
404
|
-
"НаимОрг": "ООО ТЕСТ",
|
|
405
|
-
"ИННЮЛ": "1000000002",
|
|
406
|
-
"КПП": "010101001"
|
|
407
|
-
}
|
|
408
|
-
},
|
|
409
|
-
"СведДох_НДПриб": {
|
|
410
|
-
"ДохНалПер": {
|
|
411
|
-
"Ставка": "2",
|
|
412
|
-
"СумДохОбщ": "5000.11",
|
|
413
|
-
"НалБаза": "3000.11"
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
]
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
367
|
+
"УдЛичнФЛ":{
|
|
368
|
+
"КодВидДок":"21",
|
|
369
|
+
"ВыдДок":"11",
|
|
370
|
+
"КодВыдДок":"111 111",
|
|
371
|
+
"ДатаДок":"2022-10-01",
|
|
372
|
+
"СерНомДок":"11 11 111111"}
|
|
373
|
+
},
|
|
374
|
+
"ИдЗапрос":"7daf950d-d71c-ea20-eaa9-5096324ca3b3"
|
|
375
|
+
}
|
|
423
376
|
}
|
|
424
|
-
|
|
377
|
+
|
|
378
|
+
// console.log (xs)
|
|
425
379
|
|
|
426
380
|
console.log (xs.stringify (data))
|
|
381
|
+
console.log (xss.stringify (data))
|
|
427
382
|
|
|
428
383
|
}
|
|
429
384
|
|
|
385
|
+
function test_010_node () {
|
|
386
|
+
|
|
387
|
+
for (const s of
|
|
388
|
+
[
|
|
389
|
+
'<a />zzz',
|
|
390
|
+
'zzz<b>',
|
|
391
|
+
'<!-- 111 -->222',
|
|
392
|
+
'<![CDATA[ >>]>>]]>zzz',
|
|
393
|
+
'<?xml version="3.11"?><a/>',
|
|
394
|
+
]
|
|
395
|
+
) {
|
|
396
|
+
|
|
397
|
+
let n = new XMLNode (s)
|
|
398
|
+
|
|
399
|
+
n.trim ()
|
|
400
|
+
|
|
401
|
+
console.log (n)
|
|
402
|
+
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function test_011_iterator (fn) {
|
|
408
|
+
|
|
409
|
+
const xml = fs.readFileSync (
|
|
410
|
+
'test/' + fn
|
|
411
|
+
, 'utf-8'
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
console.log (xml)
|
|
415
|
+
|
|
416
|
+
for (const i of new XMLIterator (xml)) {
|
|
417
|
+
|
|
418
|
+
console.log ([i, i.detach ()])
|
|
419
|
+
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function test_012_parser (fn) {
|
|
425
|
+
|
|
426
|
+
const xml = fs.readFileSync (
|
|
427
|
+
'test/' + fn
|
|
428
|
+
, 'utf-8'
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
//console.log (new XMLParser ().process (xml).detach ())
|
|
432
|
+
|
|
433
|
+
const parser = new XMLParser ({})
|
|
434
|
+
const doc = parser.process (xml)
|
|
435
|
+
|
|
436
|
+
for (const element of doc.children) {
|
|
437
|
+
console.log (element)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
}
|
|
430
441
|
|
|
431
442
|
async function main () {
|
|
432
443
|
|
|
433
444
|
// await test_001_lexer_sync ('E05a.xml')
|
|
434
|
-
//
|
|
445
|
+
//await test_001_lexer_sync ('not-sa01.xml')
|
|
435
446
|
// await test_001_lexer_sync ('not-sa02.xml')
|
|
436
447
|
// await test_001_lexer_sync ('param_types.xml')
|
|
437
448
|
// await test_002_lexer_stream ('E05a.xml')
|
|
@@ -442,12 +453,19 @@ async function main () {
|
|
|
442
453
|
// await test_003_emitter_sync ('not-sa01.xml')
|
|
443
454
|
// await test_003_emitter_sync ('ent.xml')
|
|
444
455
|
// await test_003_emitter_sync ('soap.xml')
|
|
445
|
-
|
|
456
|
+
await test_004_schemata ()
|
|
446
457
|
// await test_005_schemata ()
|
|
447
458
|
// await test_006_schemata ()
|
|
448
459
|
// await test_007_wsdl ()
|
|
449
|
-
await test_008_schemata ()
|
|
460
|
+
// await test_008_schemata ()
|
|
461
|
+
|
|
462
|
+
// test_010_node ()
|
|
463
|
+
// test_011_iterator ('param_types.xml')
|
|
464
|
+
// test_011_iterator ('20040.wsdl')
|
|
450
465
|
|
|
466
|
+
// test_012_parser ('param_types.xml')
|
|
467
|
+
// test_012_parser ('20040.wsdl')
|
|
468
|
+
|
|
451
469
|
}
|
|
452
470
|
|
|
453
471
|
main ()
|