xml-toolkit 1.0.24 → 1.0.26

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  # node-xml-toolkit
2
- Collection of classes for dealing with XML
2
+ XML parsers (synchronous, streaming), marshaller, SOAP adapters (1.1, 1.2)
3
3
 
4
4
  # Installation
5
5
 
@@ -25,7 +25,7 @@ for (const element of document.detach ().children) {
25
25
  }
26
26
  ```
27
27
 
28
- * [Reading a Record List](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Reading-a-Record-List)
28
+ * [Reading a Record List](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Reading-a-Record-List), streaming mode
29
29
 
30
30
  ```js
31
31
  const {XMLReader, XMLNode} = require ('xml-toolkit')
@@ -50,7 +50,7 @@ const records = new XMLReader ({
50
50
  // records.on ('data', record => doSomethingWith (record))
51
51
  ```
52
52
 
53
- * [Getting a Single Element](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Getting-a-Single-Element)
53
+ * [Getting a Single Element](https://github.com/do-/node-xml-toolkit/wiki/Use-Case:-Getting-a-Single-Element), streaming mode
54
54
 
55
55
  ```js
56
56
  const {XMLReader, XMLNode} = require ('xml-toolkit')
@@ -93,13 +93,13 @@ const xml = xs.stringify (data)
93
93
  */
94
94
  ```
95
95
 
96
- * Invoking a [SOAP 1.1](https://github.com/do-/node-xml-toolkit/wiki/SOAP11) Web Service
96
+ * Invoking a [SOAP 1.1](https://github.com/do-/node-xml-toolkit/wiki/SOAP11) or [SOAP 1.2](https://github.com/do-/node-xml-toolkit/wiki/SOAP12) Web Service
97
97
 
98
98
  ```js
99
99
  const http = require ('http')
100
- const {SOAP11} = require ('xml-toolkit')
100
+ const {SOAP11, SOAP12} = require ('xml-toolkit')
101
101
 
102
- const soap = new SOAP11 ('their.wsdl')
102
+ const soap = new SOAP11 ('their.wsdl') // or SOAP12
103
103
 
104
104
  const {method, headers, body} = soap.http ({RequestElementNameOfTheirs: {amount: '0.01'}})
105
105
 
@@ -107,4 +107,4 @@ const rq = http.request (endpointURL, {method, headers})
107
107
  rq.write (body)
108
108
  ```
109
109
 
110
- More information available in [wiki docs](https://github.com/do-/node-xml-toolkit/wiki).
110
+ For more information, see [wiki docs](https://github.com/do-/node-xml-toolkit/wiki).
package/index.js CHANGED
@@ -8,8 +8,10 @@ for (const name of [
8
8
  'XMLNode',
9
9
  'XMLSchemata',
10
10
  'SOAP11',
11
+ 'SOAP12',
11
12
  'EntityResolver',
12
13
  'XMLIterator',
13
14
  'XMLParser',
15
+ 'SOAPFault',
14
16
 
15
17
  ]) module.exports [name] = require ('./lib/' + name)
package/lib/SOAP11.js CHANGED
@@ -1,12 +1,52 @@
1
1
  const fs = require ('fs')
2
+ const path = require ('path')
2
3
 
3
4
  const XMLSchemata = require ('./XMLSchemata.js')
4
5
  const XMLReader = require ('./XMLReader.js')
5
6
  const XMLNode = require ('./XMLNode.js')
6
- const SOAPHTTP = require ('./SOAPHTTP.js')
7
+ const SOAPFault = require ('./SOAPFault.js')
7
8
 
8
9
  const WSDL = {namespaceURI: 'http://schemas.xmlsoap.org/wsdl/'}
9
10
 
11
+ let _xs = null
12
+
13
+ const get_xs = () => {
14
+
15
+ if (_xs === null) _xs = new XMLSchemata (path.join (path.dirname (module.filename), 'soap-1.1.xsd'))
16
+
17
+ return _xs
18
+
19
+ }
20
+
21
+ const _fault_xml = ({code, message, actor, detail}) => {
22
+
23
+ if (typeof code === 'string') code = {localName: code, namespaceURI: 'http://schemas.xmlsoap.org/soap/envelope/'}
24
+
25
+ const Fault = {
26
+ faultstring: message,
27
+ faultcode: code,
28
+ faultactor: actor,
29
+ detail
30
+ }
31
+
32
+ return get_xs ().stringify ({Fault})
33
+
34
+ }
35
+
36
+ const _message = (body, header, o) => {
37
+
38
+ if (!Array.isArray (body)) body = [body, {}]
39
+
40
+ if (body [0] instanceof SOAPFault) body [0] = _fault_xml (body [0])
41
+
42
+ let Envelope = {Body: XMLSchemata.any (body)}
43
+
44
+ if (header != null) Envelope.Header = XMLSchemata.any (header)
45
+
46
+ return get_xs ().stringify ({Envelope}, o)
47
+
48
+ }
49
+
10
50
  const SOAP11 = class {
11
51
 
12
52
  constructor (fn) {
@@ -81,27 +121,29 @@ const SOAP11 = class {
81
121
 
82
122
  }
83
123
 
84
- toSOAPHTTP (o) {
85
-
86
- let rq = new SOAPHTTP ('1.1')
124
+ http (body, header) {
87
125
 
88
- for (const elementLocalName in o) {
126
+ if (!Array.isArray (body)) body = [body, {}]
127
+
128
+ const encoding = 'UTF-8'
129
+
130
+ let headers = {'Content-Type': 'text/xml; charset=' + encoding.toLowerCase ()}
131
+
132
+ for (const elementLocalName in body [0]) {
89
133
 
90
134
  const SOAPAction = this.getSoapActionByElementLocalName (elementLocalName)
91
135
 
92
- if (SOAPAction) rq.http.headers.SOAPAction = SOAPAction
136
+ if (SOAPAction) headers.SOAPAction = SOAPAction
93
137
 
94
138
  }
95
139
 
96
- rq.soap.Body.content = this.xs.stringify (o)
97
-
98
- return rq.build ()
140
+ body [0] = this.xs.stringify (body [0])
99
141
 
100
- }
101
-
102
- http (o) {
103
-
104
- return this.toSOAPHTTP (o).http
142
+ return {
143
+ method: 'POST',
144
+ headers,
145
+ body: _message (body, header, {declaration: {encoding}})
146
+ }
105
147
 
106
148
  }
107
149
 
@@ -127,4 +169,6 @@ SOAP11.fromFile = async function (fn, options = {}) {
127
169
 
128
170
  }
129
171
 
172
+ SOAP11.message = _message
173
+
130
174
  module.exports = SOAP11
package/lib/SOAP12.js ADDED
@@ -0,0 +1,74 @@
1
+ const path = require ('path')
2
+ const XMLSchemata = require ('./XMLSchemata.js')
3
+ const SOAPFault = require ('./SOAPFault.js')
4
+
5
+ let _xs = null
6
+
7
+ const get_xs = () => {
8
+
9
+ if (_xs === null) _xs = new XMLSchemata (path.join (path.dirname (module.filename), 'soap-1.2.xsd'))
10
+
11
+ return _xs
12
+
13
+ }
14
+
15
+ const _fault_xml = ({code, message, actor, detail}) => {
16
+
17
+ if (typeof code === 'string') code = {localName: code, namespaceURI: 'http://www.w3.org/2003/05/soap-envelope'}
18
+
19
+ const Fault = {
20
+ Reason: {Text: message},
21
+ Code: {Value: code},
22
+ Role: actor,
23
+ Detail: detail
24
+ }
25
+
26
+ return get_xs ().stringify ({Fault})
27
+
28
+ }
29
+
30
+ const _message = (body, header, o) => {
31
+
32
+ if (!Array.isArray (body)) body = [body, {}]
33
+
34
+ if (body [0] instanceof SOAPFault) body [0] = _fault_xml (body [0])
35
+
36
+ let Envelope = {Body: XMLSchemata.any (body)}
37
+
38
+ if (header != null) Envelope.Header = XMLSchemata.any (header)
39
+
40
+ return get_xs ().stringify ({Envelope}, o)
41
+
42
+ }
43
+
44
+ const SOAP12 = class {
45
+
46
+ constructor (fn) {
47
+
48
+ this.definitions = []
49
+
50
+ if (fn) this.xs = new XMLSchemata (fn)
51
+
52
+ }
53
+
54
+ http (body, header) {
55
+
56
+ if (!Array.isArray (body)) body = [body, {}]
57
+
58
+ const encoding = 'UTF-8'
59
+
60
+ body [0] = this.xs.stringify (body [0])
61
+
62
+ return {
63
+ method: 'POST',
64
+ headers: {'Content-Type': 'application/soap+xml; charset=' + encoding.toLowerCase ()},
65
+ body: _message (body, header, {declaration: {encoding}})
66
+ }
67
+
68
+ }
69
+
70
+ }
71
+
72
+ SOAP12.message = _message
73
+
74
+ module.exports = SOAP12
@@ -0,0 +1,30 @@
1
+ const XMLSchemata = require ('./XMLSchemata.js')
2
+
3
+ const SOAPFault = class {
4
+
5
+ constructor (message, o) {
6
+
7
+ if (o == null && typeof message === 'object') {
8
+ o = message
9
+ this.message = o.message
10
+ }
11
+ else {
12
+ this.message = message
13
+ }
14
+
15
+ this.code = 'code' in o ? o.code: 'Server'
16
+
17
+ if ('actor' in o) {
18
+ this.actor = o.actor
19
+ }
20
+ else if ('role' in o) {
21
+ this.actor = o.role
22
+ }
23
+
24
+ if ('detail' in o) this.detail = XMLSchemata.any (o.detail)
25
+
26
+ }
27
+
28
+ }
29
+
30
+ module.exports = SOAPFault
@@ -24,6 +24,30 @@ const BOOL = new Map ([
24
24
  ['Y', 'true'],
25
25
  ])
26
26
 
27
+ const XML_DECL = [
28
+ ['version', '1.0'],
29
+ ['encoding', null],
30
+ ['standalone', null]
31
+ ]
32
+
33
+ const _declaration = o => {
34
+
35
+ if (typeof o !== 'object' || o === null) return
36
+
37
+ let s = '<?xml'
38
+
39
+ for (const [name, def] of XML_DECL) {
40
+
41
+ const f = name in o; if (!f && def === null) continue
42
+
43
+ s += ' ' + name + '="' + (f ? o [name] : def) + '"'
44
+
45
+ }
46
+
47
+ return s + '?>'
48
+
49
+ }
50
+
27
51
  const XMLMarshaller = class {
28
52
 
29
53
  constructor (xs, localName, namespaceURI) {
@@ -42,13 +66,15 @@ const XMLMarshaller = class {
42
66
 
43
67
  }
44
68
 
45
- stringify (data, name) {
46
-
69
+ stringify (data, o = {}) {
70
+
47
71
  const {schemaElement} = this, {targetNamespace, attributes, children} = schemaElement
48
72
 
49
- this.buf = ''
73
+ if (typeof o === 'string') o = {localName: o}
50
74
 
51
- this.appendElement (schemaElement, data, this.ns.QName (name || attributes.name, targetNamespace))
75
+ this.buf = 'declaration' in o ? _declaration (o.declaration) : ''
76
+
77
+ this.appendElement (schemaElement, data, this.ns.QName (o.localName || attributes.name, targetNamespace))
52
78
 
53
79
  let xml = this.buf
54
80
 
@@ -246,7 +272,7 @@ const XMLMarshaller = class {
246
272
  to_string (v, type, restriction = {}) {
247
273
 
248
274
  const carp = () => {throw new Error (`Invalid value for ${type} type: ${v} (${typeof v})`)}
249
-
275
+
250
276
  switch (type) {
251
277
 
252
278
  case 'boolean':
@@ -332,6 +358,9 @@ const XMLMarshaller = class {
332
358
  if (typeof v === 'number') return fractionDigits ? v.toFixed (fractionDigits.value) : '' + v
333
359
  carp ()
334
360
 
361
+ case 'QName':
362
+ if (typeof v === 'object' && 'localName' in v) v = this.ns.QName (v.localName, v.namespaceURI)
363
+
335
364
  default:
336
365
  return XML_ATTR.escape ('' + v)
337
366
 
@@ -341,4 +370,6 @@ const XMLMarshaller = class {
341
370
 
342
371
  }
343
372
 
373
+ XMLMarshaller.declaration = _declaration
374
+
344
375
  module.exports = XMLMarshaller
@@ -85,15 +85,15 @@ const XMLSchemata = class extends Map {
85
85
 
86
86
  }
87
87
 
88
- stringify (o) {
88
+ stringify (data, o) {
89
89
 
90
- assert.strictEqual (typeof o, 'object')
90
+ assert.strictEqual (typeof data, 'object')
91
91
 
92
- assert.strictEqual (Object.keys (o).length, 1)
92
+ assert.strictEqual (Object.keys (data).length, 1)
93
93
 
94
- for (let [localName, content] of Object.entries (o))
94
+ for (let [localName, content] of Object.entries (data))
95
95
 
96
- return this.createMarshaller (localName).stringify (content)
96
+ return this.createMarshaller (localName).stringify (content, o)
97
97
 
98
98
  }
99
99
 
@@ -199,4 +199,20 @@ XMLSchemata.fromFile = async function (fn, options = {}) {
199
199
 
200
200
  }
201
201
 
202
+ XMLSchemata.any = (xml, attributes) => {
203
+
204
+ if (attributes == null && Array.isArray (xml) && xml.length === 2) {
205
+
206
+ attributes = xml [1]
207
+
208
+ xml = xml [0]
209
+
210
+ }
211
+
212
+ if (attributes == null) attributes = {}
213
+
214
+ return {null: {[xml]: attributes}}
215
+
216
+ }
217
+
202
218
  module.exports = XMLSchemata
File without changes
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xml-toolkit",
3
- "version": "1.0.24",
3
+ "version": "1.0.26",
4
4
  "description": "Collection of classes for dealing with XML",
5
5
  "main": "index.js",
6
6
  "scripts": {
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, EntityResolver, XMLIterator, XMLParser} = require ('../')
3
+ const {XMLReader, SAXEvent, XMLLexer, AttributesMap, XMLNode, XMLSchemata, SOAP11, SOAP12, EntityResolver, XMLIterator, XMLParser, SOAPFault} = require ('../')
4
4
 
5
5
  async function test_001_lexer_sync (fn) {
6
6
 
@@ -332,17 +332,15 @@ async function test_006_schemata (fn) {
332
332
 
333
333
  }
334
334
 
335
- async function test_007_wsdl (fn) {
335
+ function test_007_wsdl (fn) {
336
336
 
337
- const soap = await SOAP11.fromFile ('test/20186.wsdl')
338
- const soaps = new SOAP11 ('test/20186.wsdl')
337
+ const soap11 = new SOAP11 ('test/20186.wsdl')
338
+ const soap12 = new SOAP12 ('test/20186.wsdl')
339
339
 
340
340
  const d = {GetForm9Sync: {address: {Region: {Code: 78}}}}
341
341
 
342
- console.log (soap.http (d))
343
- console.log (soaps.http (d))
344
-
345
- // console.log (soap)
342
+ console.log (soap11.http (d))
343
+ console.log (soap12.http (d))
346
344
 
347
345
  }
348
346
 
@@ -455,105 +453,22 @@ for (const element of doc.children) {
455
453
 
456
454
  function test_013_soap () {
457
455
 
458
- const xs11 = new XMLSchemata ('test/soap-1.1.xsd')
459
-
460
- // console.log (xs.get ('http://schemas.xmlsoap.org/soap/envelope/'))
461
- // console.log (xs.get ('http://schemas.xmlsoap.org/soap/envelope/').getType ('Fault').children[0].children)
462
- // console.log (xs.getType ('Fault'))
463
-
464
- /*
465
- console.log (xs.stringify ({
466
- Envelope: {
467
- Body: {null: {'<foo>bar</foo>': {Id: 1}}},
468
- }
469
- }))
470
-
471
-
472
- <faultcode>SOAP-ENV:Client</faultcode>
473
- <faultstring>Message does not have necessary info</faultstring>
474
- <faultactor>http://gizmos.com/order</faultactor>
475
- <detail>
476
- <PO:order xmlns:PO="http://gizmos.com/orders/">Quantity element does not have a value</PO:order>
477
- <PO:confirmation xmlns:PO="http://gizmos.com/confirm">Incomplete address: no zip code</PO:confirmation>
478
- </detail>
479
-
480
-
481
- */
482
-
483
- let Fault = {
484
- faultcode: 'SOAP-ENV:Client',
485
- faultstring: 'Message does not have necessary info',
486
- faultactor: 'http://gizmos.com/order',
487
- detail: {
488
- null: {
489
- [`
490
- <PO:order xmlns:PO="http://gizmos.com/orders/">Quantity element does not have a value</PO:order>
491
- <PO:confirmation xmlns:PO="http://gizmos.com/confirm">Incomplete address: no zip code</PO:confirmation>
492
- `]: {}
493
- }
494
- }
495
- }
496
-
497
- const soap11 = {
498
- Envelope: {
499
- Body: {
500
- null: {
501
- [xs11.stringify ({Fault})]: {}
502
- }
503
- }
504
- }
505
- }
506
-
507
- /*
508
- <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
509
- <env:Header/>
510
- <env:Body>
511
- <env:Fault>
512
- <env:Code>
513
- <env:Value>env:Sender</env:Value>
514
- </env:Code>
515
- <env:Reason>
516
- <env:Text xml:lang="en-US">Message does not have necessary info</env:Text>
517
- </env:Reason>
518
- <env:Role>http://gizmos.com/order</env:Role>
519
- <env:Detail>
520
- <PO:order xmlns:PO="http://gizmos.com/orders/">Quantity element does not have a value</PO:order>
521
- <PO:confirmation xmlns:PO="http://gizmos.com/confirm">Incomplete address: no zip code</PO:confirmation>
522
- </env:Detail>
523
- </env:Fault>
524
- </env:Body>
525
- </env:Envelope>
526
- */
456
+ const xs11 = new XMLSchemata ('lib/soap-1.1.xsd')
527
457
 
528
- console.log (xs11.stringify (soap11))
458
+ const detail = `
459
+ <PO:order xmlns:PO="http://gizmos.com/orders/">Quantity element does not have a value</PO:order>
460
+ <PO:confirmation xmlns:PO="http://gizmos.com/confirm">Incomplete address: no zip code</PO:confirmation>
461
+ `
529
462
 
530
- const xs12 = new XMLSchemata ('test/soap-1.2.xsd')
531
-
532
- Fault = {
533
- Code: {Value: 'env:Sender'},
534
- Reason: {Text: 'Message does not have necessary info'},
535
- Role: 'http://gizmos.com/order',
536
- Detail: {
537
- null: {
538
- [`
539
- <PO:order xmlns:PO="http://gizmos.com/orders/">Quantity element does not have a value</PO:order>
540
- <PO:confirmation xmlns:PO="http://gizmos.com/confirm">Incomplete address: no zip code</PO:confirmation>
541
- `]: {}
542
- }
543
- }
544
- }
463
+ const f =
464
+ new SOAPFault ('Message does not have necessary info', {
465
+ code: 'Client',
466
+ actor: 'http://gizmos.com/order',
467
+ detail
468
+ })
545
469
 
546
- const soap12 = {
547
- Envelope: {
548
- Body: {
549
- null: {
550
- [xs12.stringify ({Fault})]: {}
551
- }
552
- }
553
- }
554
- }
555
-
556
- console.log (xs12.stringify (soap12))
470
+ console.log (SOAP11.message (f))
471
+ console.log (SOAP12.message (f))
557
472
 
558
473
  }
559
474
 
@@ -576,7 +491,7 @@ async function main () {
576
491
  // await test_004_schemata ()
577
492
  // await test_005_schemata ()
578
493
  // await test_006_schemata ()
579
- // await test_007_wsdl ()
494
+ test_007_wsdl ()
580
495
  // await test_008_schemata ()
581
496
 
582
497
  // test_009_schemata ('smev-message-exchange-service-1.1.xsd')
@@ -589,7 +504,7 @@ async function main () {
589
504
  // test_012_parser ('param_types.xml')
590
505
  // test_012_parser ('20040.wsdl')
591
506
 
592
- test_013_soap ()
507
+ // test_013_soap ()
593
508
 
594
509
  }
595
510
 
package/lib/SOAPHTTP.js DELETED
@@ -1,84 +0,0 @@
1
- const zlib = require ('zlib')
2
-
3
- const VER = {
4
-
5
- '1.1': {
6
- contentType : 'text/xml',
7
- namespaceURI : 'http://schemas.xmlsoap.org/soap/envelope/',
8
- },
9
-
10
- '1.2': {
11
- contentType : 'application/soap+xml',
12
- namespaceURI : 'http://www.w3.org/2003/05/soap-envelope',
13
- },
14
-
15
- }
16
-
17
- const SOAPHTTP = class {
18
-
19
- constructor (versionNumber) {
20
-
21
- if (!(versionNumber in VER)) throw new Exception ('Unknown SOAP version: ' + version)
22
-
23
- const {contentType, namespaceURI} = VER [versionNumber]
24
-
25
- this.charset = 'utf-8'
26
-
27
- this.http = {
28
- method : 'POST',
29
- headers : {"Content-Type": contentType},
30
- }
31
-
32
- this.soap = {
33
- Envelope: {attributes: `xmlns:soap="${namespaceURI}"`},
34
- Header: {attributes: '', content: ''},
35
- Body: {attributes: '', content: ''},
36
- }
37
-
38
- }
39
-
40
- el (name) {
41
-
42
- const {attributes, content} = this.soap [name]
43
-
44
- const qName = 'soap:' + name
45
-
46
- let s = '<' + qName
47
-
48
- if (attributes) s += ' ' + attributes
49
-
50
- if (!content) return s + '/>'
51
-
52
- return s + '>' + content + '</' + qName + '>'
53
-
54
- }
55
-
56
- build () {
57
-
58
- this.http.headers ['Content-Type'] += '; charset=' + this.charset
59
-
60
- this.soap.Envelope.content = this.el ('Header') + this.el ('Body')
61
-
62
- this.http.body = '<?xml version="1.0" encoding="' + this.charset + '"?>' + this.el ('Envelope')
63
-
64
- return this
65
-
66
- }
67
-
68
- gzip (options = {}) {
69
-
70
- if (!('level' in options)) options.level = 9
71
-
72
- this.http.body = zlib.gzipSync (this.http.body, options)
73
-
74
- this.http.headers ['Content-Encoding'] = 'gzip'
75
-
76
- this.http.headers ['Content-Length'] = this.http.body.length
77
-
78
- return this
79
-
80
- }
81
-
82
- }
83
-
84
- module.exports = SOAPHTTP