xml-toolkit 1.0.7 → 1.0.10

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.
@@ -2,53 +2,33 @@ const assert = require ('assert')
2
2
 
3
3
  const NamespacePrefixesMap = class extends Map {
4
4
 
5
- constructor (schemata, o) {
5
+ constructor (schemata) {
6
6
 
7
- assert.strictEqual (typeof o, 'object')
8
-
9
7
  super ()
10
8
 
11
- this.schemata = schemata
9
+ for (const uri of schemata.keys ())
12
10
 
13
- this.add (o)
11
+ this.set (uri, 'ns' + this.size)
14
12
 
15
13
  }
16
-
17
- add (o) {
18
14
 
19
- if (this.isAddedAsNamespaceReference (o)) return
20
-
21
- for (let v of Object.values (o)) if (typeof v === 'object') this.add (v)
22
-
23
- }
24
-
25
- isAddedAsNamespaceReference (a) {
15
+ QName (localName, namespaceURI) {
26
16
 
27
- if (!Array.isArray (a)) return false
28
-
29
- if (a.length !== 2) return false
30
-
31
- const uri = a [1]
32
-
33
- if (!this.schemata.has (uri)) return false
17
+ if (namespaceURI == null) return localName
18
+
19
+ assert (this.has (namespaceURI), 'Unknown target namespace: ' + namespaceURI)
34
20
 
35
- if (this.has (uri)) return true
36
-
37
- this.set (uri, 'ns' + this.size)
38
-
39
- }
40
-
41
- QName (localName, namespaceURI) {
42
-
43
- if (namespaceURI == null || !this.has (namespaceURI)) return localName
44
-
45
21
  return this.get (namespaceURI) + ':' + localName
46
22
 
47
23
  }
48
24
 
49
- appendTo (buf) {
25
+ toString () {
26
+
27
+ let s = ''
50
28
 
51
- for (let [k, v] of this.entries ()) buf [0] += ' xmlns:' + v + '="' + k + '"'
29
+ for (let [k, v] of this.entries ()) s += ' xmlns:' + v + '="' + k + '"'
30
+
31
+ return s
52
32
 
53
33
  }
54
34
 
@@ -1,5 +1,6 @@
1
1
  const assert = require ('assert')
2
2
  const stringEscape = require ('string-escape-map')
3
+ const NamespacePrefixesMap = require ('./NamespacePrefixesMap.js')
3
4
 
4
5
  let esc = [
5
6
  ['<', '&lt;'],
@@ -33,152 +34,184 @@ const XMLMarshaller = class {
33
34
 
34
35
  this.schemaElement = this.schema.get (localName); assert (this.schemaElement, 'No schema element found for namespaceURI = ' + namespaceURI + ', localName = ' + localName)
35
36
 
36
- this.ns = this.xs.getNamespacePrefixesMap (this.schemaElement)
37
+ this.ns = new NamespacePrefixesMap (xs)
38
+
39
+ this.isNsDumped = false
40
+
41
+ this.qNames = []
37
42
 
38
43
  }
39
44
 
40
- stringify (content, name) {
41
-
42
- const qName = this.ns.QName (name || this.schemaElement.name, this.schema.targetNamespace)
45
+ stringify (data, name) {
43
46
 
44
- let {complexType, sequence, choice, all, type} = this.schemaElement, group = sequence || choice || all
47
+ const {schemaElement} = this, {targetNamespace, attributes, children} = schemaElement
45
48
 
46
- if (type) {
49
+ this.buf = ''
47
50
 
48
- type = this.xs.getByReference (type)
51
+ this.appendElement (schemaElement, data, this.ns.QName (name || attributes.name, targetNamespace))
49
52
 
50
- switch (type._type) {
53
+ let xml = this.buf
51
54
 
52
- case 'complexType':
53
- complexType = type
54
- break
55
+ delete this.buf
55
56
 
56
- case 'simpleType':
57
- simpleType = type
58
- break
57
+ return xml
59
58
 
60
- }
59
+ }
60
+
61
+ appendElement (node, data, qName) {
61
62
 
62
- }
63
+ this.appendStartTag (node, data, qName)
64
+
65
+ this.appendElementBody (node, data)
66
+
67
+ this.appendEndTag ()
63
68
 
64
- let buf = ['<' + qName]
69
+ }
70
+
71
+ appendStartTag (node, data, qName) {
72
+
73
+ this.qNames.push (qName)
74
+
75
+ this.buf += '<' + qName
65
76
 
66
- this.ns.appendTo (buf)
77
+ if (!this.isNsDumped) {
67
78
 
68
- if (complexType) this._aComplexType (buf, complexType, content)
79
+ this.buf += this.ns
80
+
81
+ this.isNsDumped = true
69
82
 
70
- buf [0] += '>'
83
+ }
71
84
 
72
- if (complexType) this._bComplexType (buf, complexType, content)
73
- if (group) this._bSequence (buf, group, content)
85
+ this.appendAttributes (node, data)
74
86
 
75
- return buf [0] + '</' + qName + '>'
87
+ this.buf += '>'
76
88
 
77
- }
89
+ }
90
+
91
+ appendEndTag () {
92
+
93
+ this.buf += '</' + this.qNames.pop () + '>'
94
+
95
+ }
96
+
97
+ appendNullElement (node) {
78
98
 
79
- /// _a: attributes
99
+ const {attributes: {name, nillable}, targetNamespace} = node
80
100
 
81
- _aComplexType (buf, complexType, content) {
101
+ if (BOOL.get (nillable) !== 'true') return
82
102
 
83
- const {complexContent, attribute} = complexType
103
+ const qName = this.ns.QName (name, targetNamespace)
84
104
 
85
- if (attribute)
86
- for (const e of Array.isArray (attribute) ? attribute : [attribute])
87
- this._aAttribute (buf, e, content [e.name])
88
-
89
- if (complexContent) this._aComplexContent (buf, complexContent, content)
90
-
91
- }
92
-
93
- _aComplexContent (buf, complexContent, content) {
94
-
95
- const {extension} = complexContent
105
+ this.buf += `<${qName} xsi:nil="true" />`
96
106
 
97
- if (extension) this._aExtension (buf, extension, content)
98
-
99
107
  }
100
108
 
101
- _aExtension (buf, extension, content) {
109
+ appendScalar (node, data, restriction = {}) {
102
110
 
103
- const {base, attribute} = extension
111
+ for (const {localName, attributes, children} of node.children) {
104
112
 
105
- if (base) {
106
-
107
- const [localName, namespaceURI] = base
108
-
109
- const schema = this.xs.get (namespaceURI)
110
-
111
- const type = schema.get (localName)
113
+ if (localName === 'restriction') {
114
+
115
+ for (const {localName, attributes: {value}} of children) restriction [localName] = value
116
+
117
+ return this.appendScalar (this.xs.getByReference (attributes.base), data, restriction)
118
+
119
+ }
112
120
 
113
- if (type._type === 'complexType') this._aComplexType (buf, type, content)
114
-
115
121
  }
116
122
 
117
- if (attribute)
118
- for (const a of Array.isArray (attribute) ? attribute : [attribute])
119
- this._aAttribute (buf, a, content [a.name])
123
+ this.buf += this.to_string (data, node.attributes.name, restriction)
120
124
 
121
- }
125
+ }
122
126
 
123
- _aAttribute (buf, attribute, content) {
127
+ appendElementBody (node, data) {
124
128
 
125
- if (content == null) return
129
+ const {attributes: {type}, children} = node
126
130
 
127
- let {name, targetNamespace, simpleType, type} = attribute
128
-
129
- if (type) {
131
+ if (type) return this.appendContent (this.xs.getByReference (type), data)
130
132
 
131
- type = this.xs.getByReference (type)
133
+ for (const i of children) this.appendContent (i, data)
132
134
 
133
- switch (type._type) {
135
+ }
134
136
 
135
- case 'simpleType':
136
- simpleType = type
137
- break
137
+ appendAttributes (node, data) {
138
138
 
139
- }
139
+ const {localName, namespaceURI, attributes, children, targetNamespace} = node, {name, type, ref} = attributes
140
140
 
141
- }
141
+ if (ref) return this.appendAttributes (this.xs.getByReference (ref), data)
142
+
143
+ switch (localName) {
142
144
 
143
- const qName = this.ns.QName (name, targetNamespace)
144
-
145
- buf [0] += ' ' + qName + '="'
146
-
147
- if (simpleType) this._bSimpleType (buf, simpleType, content)
145
+ case 'attribute':
146
+
147
+ if (!(name in data)) return
148
+
149
+ let v = data [name]; if (v == null) return
150
+
151
+ this.buf += ' ' + this.ns.QName (name, targetNamespace) + '="'
152
+
153
+ this.appendScalar (this.xs.getByReference (type), v)
154
+
155
+ this.buf += '"'
156
+
157
+ break
158
+
159
+ case 'extension':
148
160
 
149
- buf [0] += '"'
161
+ this.appendAttributes (this.xs.getByReference (attributes.base), data)
162
+
163
+ case 'any':
164
+ case 'sequence':
165
+ case 'choice':
166
+ case 'group':
167
+ case 'simpleType':
150
168
 
151
- }
152
-
153
- /// _b: body
154
-
155
- _bComplexType (buf, complexType, content) {
169
+ return
156
170
 
157
- const {complexContent, sequence, choice, all} = complexType, group = sequence || choice || all
171
+ default:
158
172
 
159
- if (group) this._bSequence (buf, group, content)
160
- if (complexContent) this._bComplexContent (buf, complexContent, content)
173
+ for (const i of children) this.appendAttributes (i, data)
174
+
175
+ }
161
176
 
162
177
  }
178
+
179
+ appendContent (node, data) {
163
180
 
164
- _bSimpleType (buf, simpleType, content, _restriction = {}) {
181
+ const {localName, namespaceURI, attributes, children, targetNamespace} = node, {name, type, ref} = attributes
165
182
 
166
- let {restriction} = simpleType; if (restriction) {
183
+ if (ref) return this.appendContent (this.xs.getByReference (ref), data)
167
184
 
168
- for (const [k, v] of Object.entries (_restriction)) switch (k) {
169
- case 'base': case 'targetNamespace': break
170
- default: restriction [k] = v
171
- }
185
+ switch (localName) {
186
+
187
+ case 'simpleType':
188
+
189
+ return this.appendScalar (node, data)
172
190
 
173
- this._bSimpleType (buf, this.xs.getByReference (restriction.base), content, restriction)
191
+ case 'element':
174
192
 
175
- }
176
- else {
193
+ if (!(name in data)) return
194
+
195
+ let v = data [name]; if (v == null) return this.appendNullElement (node)
196
+
197
+ const qName = this.ns.QName (name, targetNamespace)
198
+
199
+ if (!Array.isArray (v)) return this.appendElement (node, v, qName)
200
+
201
+ for (const d of v) this.appendElement (node, d, qName)
177
202
 
178
- buf [0] += this.to_string (content, simpleType.name, _restriction)
203
+ break
204
+
205
+ case 'extension':
206
+
207
+ this.appendContent (this.xs.getByReference (attributes.base), data)
208
+
209
+ default:
179
210
 
211
+ for (const i of children) this.appendContent (i, data)
212
+
180
213
  }
181
-
214
+
182
215
  }
183
216
 
184
217
  to_string (v, type, restriction = {}) {
@@ -277,125 +310,6 @@ const XMLMarshaller = class {
277
310
 
278
311
  }
279
312
 
280
- _bComplexContent (buf, complexContent, content) {
281
-
282
- const {extension} = complexContent
283
-
284
- if (extension) this._bExtension (buf, extension, content)
285
-
286
- }
287
-
288
- _bExtension (buf, _extension, content) {
289
-
290
- const {base, sequence, choice, all} = _extension, group = sequence || choice || all
291
-
292
- if (base) {
293
-
294
- const [localName, namespaceURI] = base
295
-
296
- const schema = this.xs.get (namespaceURI)
297
-
298
- const type = schema.get (localName)
299
-
300
- if (type._type === 'complexType') this._bComplexType (buf, type, content)
301
-
302
- }
303
-
304
- if (group) this._bSequence (buf, group, content)
305
-
306
- }
307
-
308
- _bSequence (buf, _sequence, content) {
309
-
310
- const {element, sequence, choice, all, group} = _sequence, g = sequence || choice || all
311
-
312
- if (g) this._bSequence (buf, g, content)
313
-
314
- if (element) {
315
-
316
- for (let e of Array.isArray (element) ? element : [element]) {
317
-
318
- const {ref} = e; if (ref) e = this.xs.getByReference (ref)
319
-
320
- const c = content [e.name]
321
-
322
- this._bElement (buf, e, c)
323
-
324
- }
325
-
326
- }
327
-
328
- if (group) {
329
-
330
- for (let e of Array.isArray (group) ? group : [group]) {
331
-
332
- const {ref} = e; if (ref) e = this.xs.getByReference (ref)
333
-
334
- this._bSequence (buf, e, content)
335
-
336
- }
337
-
338
- }
339
-
340
- }
341
-
342
- _bElement_null (buf, element) {
343
-
344
- if (BOOL.get (element.nillable) !== 'true') return
345
-
346
- const {name, targetNamespace} = element, qName = this.ns.QName (name, targetNamespace)
347
-
348
- buf [0] += `<${qName} xsi:nil="true" />`
349
-
350
- }
351
-
352
- _bElement (buf, element, content) {
353
-
354
- if (content == null) return this._bElement_null (buf, element)
355
-
356
- if (!Array.isArray (content)) content = [content]
357
-
358
- if (content.length === 0) return
359
-
360
- let {name, targetNamespace, complexType, simpleType, type} = element
361
-
362
- if (type) {
363
-
364
- type = this.xs.getByReference (type)
365
-
366
- switch (type._type) {
367
-
368
- case 'complexType':
369
- complexType = type
370
- break
371
-
372
- case 'simpleType':
373
- simpleType = type
374
- break
375
-
376
- }
377
-
378
- }
379
-
380
- const qName = this.ns.QName (name, targetNamespace)
381
-
382
- for (const i of content) {
383
-
384
- buf [0] += '<' + qName
385
-
386
- if (complexType) this._aComplexType (buf, complexType, content)
387
-
388
- buf [0] += '>'
389
-
390
- if (complexType) this._bComplexType (buf, complexType, i)
391
- if (simpleType) this._bSimpleType (buf, simpleType, i)
392
-
393
- buf [0] += '</' + qName + '>'
394
-
395
- }
396
-
397
- }
398
-
399
313
  }
400
314
 
401
315
  module.exports = XMLMarshaller
package/lib/XMLNode.js CHANGED
@@ -10,6 +10,10 @@ const PARENT = Symbol ('_parent')
10
10
  const LEVEL = Symbol ('_level')
11
11
  const NS_MAP = Symbol ('_ns_map')
12
12
 
13
+ const m2o =
14
+ Object.fromEntries ? m => Object.fromEntries (m.entries ()) :
15
+ m => {let o = {}; for (const [k, v] of m.entries ()) o [k] = v; return o}
16
+
13
17
  const XMLNode = class extends SAXEvent {
14
18
 
15
19
  constructor (src, xmlReader, _type) {
@@ -132,6 +136,33 @@ const XMLNode = class extends SAXEvent {
132
136
 
133
137
  }
134
138
 
139
+ detach (o = {}) {
140
+
141
+ switch (this.type) {
142
+
143
+ case SAXEvent.TYPES.CHARACTERS:
144
+ case SAXEvent.TYPES.CDATA:
145
+ return this.text
146
+
147
+ default:
148
+
149
+ const {localName, namespaceURI, attributes, children, namespacesMap} = this
150
+
151
+ let r = {
152
+ localName,
153
+ namespaceURI,
154
+ attributes : m2o (attributes),
155
+ children : (children || []).map (n => n.detach (o)),
156
+ }
157
+
158
+ if (o.nsMap) r.namespacesMap = m2o (namespacesMap || [])
159
+
160
+ return r
161
+
162
+ }
163
+
164
+ }
165
+
135
166
  }
136
167
 
137
168
  XMLNode.getLocalName = name => {
package/lib/XMLSchema.js CHANGED
@@ -13,57 +13,33 @@ const XMLSchema = class extends Map {
13
13
  }
14
14
 
15
15
  add (node, options = {}) {
16
+
17
+ this.copyTargetNamespace (node)
18
+
19
+ const {attributes, children} = node
16
20
 
17
- if (node.elementFormDefault === 'unqualified') this.isDefaultElementFormQualified = false
18
- if (node.attributeFormDefault === 'qualified') this.isAttributeElementFormQualified = true
19
-
20
- for (const type of [
21
-
22
- 'element',
23
- 'complexType',
24
- 'simpleType',
25
- 'group',
26
-
27
- ]) if (type in node) {
28
-
29
- let list = node [type]
30
-
31
- if (!Array.isArray (list)) list = [list]
21
+ if (attributes.elementFormDefault === 'unqualified') this.isDefaultElementFormQualified = false
22
+ if (attributes.attributeFormDefault === 'qualified') this.isAttributeElementFormQualified = true
23
+
24
+ for (const e of children) {
25
+
26
+ const {name} = e.attributes
32
27
 
33
- for (const item of list) {
28
+ this.set (name, e)
34
29
 
35
- delete item.annotation
36
-
37
- item._type = type
38
-
39
- this.copyTargetNamespace (item)
40
-
41
- this.set (item.name, item)
42
-
43
- this.parent.register (item.name, this.targetNamespace)
44
-
45
- }
46
-
30
+ this.parent.register (name, this.targetNamespace)
31
+
47
32
  }
48
33
 
49
34
  }
50
35
 
51
- copyTargetNamespace (o) {
52
-
53
- if (typeof o !== 'object') return
36
+ copyTargetNamespace (node) {
54
37
 
55
- if (Array.isArray (o)) {
38
+ if (typeof node !== 'object') return
56
39
 
57
- for (const v of o) this.copyTargetNamespace (v)
58
-
59
- }
60
- else {
61
-
62
- o.targetNamespace = this.targetNamespace
40
+ node.targetNamespace = this.targetNamespace
63
41
 
64
- for (const v of Object.values (o)) this.copyTargetNamespace (v)
65
-
66
- }
42
+ for (const e of node.children) this.copyTargetNamespace (e)
67
43
 
68
44
  }
69
45
 
@@ -103,4 +79,6 @@ XMLSchema.adjustNode = node => {
103
79
 
104
80
  }
105
81
 
82
+ XMLSchema.namespaceURI = 'http://www.w3.org/2001/XMLSchema'
83
+
106
84
  module.exports = XMLSchema
@@ -35,9 +35,13 @@ const XMLSchemata = class extends Map {
35
35
 
36
36
  const [localName, namespaceURI] = ref
37
37
 
38
- if (namespaceURI === 'http://www.w3.org/2001/XMLSchema') return {
39
- _type: 'simpleType',
40
- name: localName
38
+ if (namespaceURI === XMLSchema.namespaceURI) return {
39
+ localName: 'simpleType',
40
+ namespaceURI,
41
+ attributes: {name: localName},
42
+ children: [],
43
+ namespacesMap: {},
44
+ targetNamespace: namespaceURI
41
45
  }
42
46
 
43
47
  return this.get (namespaceURI).get (localName)
@@ -55,12 +59,6 @@ const XMLSchemata = class extends Map {
55
59
  for (const uri of ns) return this.get (uri)
56
60
 
57
61
  }
58
-
59
- getNamespacePrefixesMap (o) {
60
-
61
- return new NamespacePrefixesMap (this, o)
62
-
63
- }
64
62
 
65
63
  createMarshaller (localName, namespaceURI) {
66
64
 
@@ -83,21 +81,21 @@ const XMLSchemata = class extends Map {
83
81
  }
84
82
 
85
83
  async addSchema (node, options = {}) {
86
-
87
- let {targetNamespace} = node; if (!targetNamespace) targetNamespace = options.targetNamespace
84
+
85
+ let {targetNamespace} = node.attributes; if (!targetNamespace) targetNamespace = options.targetNamespace
88
86
 
89
87
  if (!this.has (targetNamespace)) this.set (targetNamespace, new XMLSchema (this, targetNamespace))
90
88
 
91
- let imp = node.import; if (imp) {
89
+ const imp = node.children.filter (e => e.localName === 'import' && e.namespaceURI === XMLSchema.namespaceURI)
92
90
 
93
- const {addLocation} = options
91
+ if (imp.length !== 0) await Promise.all (imp.map (i => {
94
92
 
95
- if (!Array.isArray (imp)) imp = [imp]
93
+ const {schemaLocation, namespace} = i.attributes
96
94
 
97
- for (const {schemaLocation, namespace} of imp) await addLocation (schemaLocation, namespace)
95
+ return options.addLocation (schemaLocation, namespace)
96
+
97
+ }))
98
98
 
99
- }
100
-
101
99
  this.get (targetNamespace).add (node)
102
100
 
103
101
  }
@@ -110,12 +108,12 @@ const XMLSchemata = class extends Map {
110
108
 
111
109
  }
112
110
 
113
- const {targetNamespace} = options, mapper = XMLNode.toObject ({})
111
+ const {targetNamespace} = options, mapper = n => n.detach ()
114
112
 
115
113
  for await (const node of
116
114
 
117
115
  new XMLReader ({
118
- filterElements: e => e.namespaceURI === 'http://www.w3.org/2001/XMLSchema',
116
+ filterElements: e => e.namespaceURI === XMLSchema.namespaceURI,
119
117
  map: adjustNode,
120
118
  })
121
119
  .process (fs.createReadStream (fn))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xml-toolkit",
3
- "version": "1.0.7",
3
+ "version": "1.0.10",
4
4
  "description": "Collection of classes for dealing with XML",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/test/test.js CHANGED
@@ -59,12 +59,15 @@ console.log (xml)
59
59
 
60
60
  const sax = new XMLReader ({
61
61
  // stripSpace: true,
62
+ // filterElements: 'root',
63
+ // filterElements: 'PARAMTYPES'
62
64
  filterElements: 'SendRequestRequest',
63
- map: XMLNode.toObject ({
65
+ map: n => n.detach ({nsMap: true}),
66
+ // map: XMLNode.toObject ({
64
67
  // wrap: 1,
65
- getName: (localName, namespaceURI) => (!namespaceURI ? '' : '{' + namespaceURI + '}') + localName,
66
- map: o => Object.fromEntries (Object.entries (o).map (([k, v]) => [k + '111', v]))
67
- })
68
+ // getName: (localName, namespaceURI) => (!namespaceURI ? '' : '{' + namespaceURI + '}') + localName,
69
+ // map: o => Object.fromEntries (Object.entries (o).map (([k, v]) => [k + '111', v]))
70
+ // })
68
71
  })
69
72
 
70
73
  /*
@@ -111,7 +114,12 @@ async function test_004_schemata (fn) {
111
114
  const o = s.get (localName)
112
115
 
113
116
  const nspm = xs.getNamespacePrefixesMap (o)
114
- */
117
+
118
+ console.log (xs.stringify ({
119
+ "ExportDebtRequestsRequest": {Id: 1}
120
+ }))
121
+ */
122
+
115
123
  console.log (xs.stringify ({
116
124
  "ExportDebtRequestsResponse": {
117
125
  "request-data": {
@@ -208,6 +216,12 @@ async function test_004_schemata (fn) {
208
216
  console.log (xs.get ('urn:dom.gosuslugi.ru/debt-requests/1.0.0').get ('ActionType').restriction)
209
217
  */
210
218
 
219
+ console.log (xs.stringify ({
220
+ "ExportDebtRequestsRequest": {Id: 1}
221
+ }))
222
+
223
+ // console.log (xs.get ('urn:dom.gosuslugi.ru/debt-responses/1.0.0').get ('AttachmentType'))
224
+
211
225
  }
212
226
 
213
227
  async function test_005_schemata (fn) {
@@ -315,7 +329,7 @@ async function main () {
315
329
  // await test_003_emitter_sync ('E05a.xml')
316
330
  // await test_003_emitter_sync ('param_types.xml')
317
331
  // await test_003_emitter_sync ('not-sa01.xml')
318
- // await test_003_emitter_sync ('ent.xml')
332
+ // await test_003_emitter_sync ('ent.xml')
319
333
  // await test_003_emitter_sync ('soap.xml')
320
334
  await test_004_schemata ()
321
335
  await test_005_schemata ()