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 CHANGED
@@ -1,5 +1,7 @@
1
- const XMLLexer = require ('./lib/XMLLexer')
2
- const SAXEventEmitter = require ('./lib/SAXEventEmitter')
3
- const SAXEvent = require ('./lib/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 = {SAXEventEmitter, XMLLexer, SAXEvent}
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).toLowerCase ()) {
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
- k = k.slice (this._afterName = p)
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
@@ -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.1",
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 sax stax"
14
+ "xml",
15
+ "sax",
16
+ "stax"
15
17
  ],
16
18
  "author": "Dmitry Ovsyanko",
17
19
  "license": "MIT",
package/test/ent.xml ADDED
@@ -0,0 +1,6 @@
1
+ <doc>
2
+ <p>&amp;</p>
3
+ <p>ss&32;ss&#20;ss&33;</p>
4
+ <p>&lt;&gt;&quot;&apos;</p>
5
+ <a name="&lt;"/>
6
+ </doc>
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 {SAXEventEmitter, SAXEvent, XMLLexer} = require ('../')
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
- // , 'utf-8'
55
+ , 'utf-8'
56
56
  )
57
57
 
58
58
  console.log (xml)
59
59
 
60
- const lex = new XMLLexer ({
61
- // maxLength: 40,
62
- // encoding: 'ascii',
63
- stripSpace: true,
60
+ const sax = new XMLReader ({
61
+ // stripSpace: true,
62
+ // filterElements: 'SendRequestRequest',
63
+ // map: MoxyLikeJsonEncoder ({wrap: 1})
64
64
  })
65
65
 
66
- const sax = new SAXEventEmitter ({})
67
-
68
- lex.pipe (sax)
69
-
66
+ /*
70
67
  for (let event of [
71
- 'StartDocument',
72
- 'ProcessingInstruction',
73
- 'Comment',
74
- 'DTD',
75
- 'StartElement',
76
- 'Characters',
77
- 'EndElement',
78
- 'EndDocument',
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
- // for (let c of xml) lexer.write (c); lexer.end ()
84
- // for (let c of xml) lexer.write (Buffer.from ([c])); lexer.end ()
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
- lex.end (xml)
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
 
@@ -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