xml-toolkit 0.0.4 → 0.0.5

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.
@@ -12,9 +12,9 @@ const set = (o, k, nv) => {
12
12
 
13
13
  const xform = ({children, attributes}) => {
14
14
 
15
- let o = Object.fromEntries (attributes.entries ())
15
+ let o = attributes == null ? {} : Object.fromEntries (attributes.entries ())
16
16
 
17
- if (children !== null) for (const child of children) switch (child.type) {
17
+ if (children != null) for (const child of children) switch (child.type) {
18
18
 
19
19
  case SAXEvent.TYPES.CHARACTERS: return child.text
20
20
 
package/lib/XMLReader.js CHANGED
@@ -2,8 +2,8 @@ const assert = require ('assert')
2
2
  const {Transform} = require ('stream')
3
3
  const SAXEvent = require ('./SAXEvent.js')
4
4
  const XMLNode = require ('./XMLNode.js')
5
+ const XMLLexer = require ('./XMLLexer.js')
5
6
 
6
- const OPT_ONCE = Symbol ('_once')
7
7
  const OPT_SRC = Symbol ('_src')
8
8
  const OPT_SAX = Symbol ('_sax')
9
9
 
@@ -23,8 +23,30 @@ const XMLReader = class extends Transform {
23
23
  if (!('useNamespaces' in options)) options.useNamespaces = true
24
24
  assert (options.useNamespaces === true || options.useNamespaces === false, 'options.useNamespaces must be boolean, not ' + typeof options.useNamespaces)
25
25
 
26
- const {collect} = options; delete options.collect
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
27
48
  assert (collect == null || typeof collect === 'function', 'options.collect must be a function, not ' + typeof collect)
49
+ if (collect == null && filterElements != null) collect = filterElements
28
50
 
29
51
  const {filter} = options; delete options.filter
30
52
  assert (filter == null || typeof filter === 'function', 'options.filter must be a function, not ' + typeof filter)
@@ -32,19 +54,14 @@ const XMLReader = class extends Transform {
32
54
  const {map} = options; delete options.map
33
55
  assert (map == null || typeof map === 'function', 'options.map must be a function, not ' + typeof map)
34
56
 
35
- const {find} = options; delete options.find
36
- assert (filter == null || find == null, 'filter & find options cannot be set together')
37
- assert (find == null || typeof find === 'function', 'options.find must be a function, not ' + typeof find)
38
-
39
57
  super (options)
40
58
 
41
59
  this.stripSpace = options.stripSpace
42
60
  this.useEntities = options.useEntities
43
61
  this.useNamespaces = options.useNamespaces
44
62
  this.collect = collect || null
45
- this.filter = filter || find || null
63
+ this.filter = filter || null
46
64
  this.map = map || null
47
- this [OPT_ONCE] = find != null
48
65
 
49
66
  if (this.useEntities) this.entityResolver = new (require ('./EntityResolver.js')) ()
50
67
 
@@ -57,6 +74,50 @@ const XMLReader = class extends Transform {
57
74
  this [OPT_SAX] = null
58
75
 
59
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
+ }
60
121
 
61
122
  _flush (callback) {
62
123
 
@@ -72,7 +133,7 @@ const XMLReader = class extends Transform {
72
133
 
73
134
  const v = this [OPT_SAX]; if (v !== null) return v
74
135
 
75
- for (const type in SAXEvent.TYPES) if (this.listenerCount (type) !== 0) return this [OPT_SAX] = true
136
+ for (const type of Object.values (SAXEvent.TYPES)) if (this.listenerCount (type) !== 0) return this [OPT_SAX] = true
76
137
 
77
138
  return this [OPT_SAX] = false
78
139
 
@@ -97,14 +158,6 @@ const XMLReader = class extends Transform {
97
158
 
98
159
  }
99
160
 
100
- if (this [OPT_ONCE]) {
101
-
102
- const src = this [OPT_SRC]; if (src !== null) src.unpipe (this)
103
-
104
- this.destroy ()
105
-
106
- }
107
-
108
161
  }
109
162
 
110
163
  flush_text () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xml-toolkit",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Collection of classes for dealing with XML",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/test/test.js CHANGED
@@ -57,74 +57,43 @@ async function test_003_emitter_sync (fn) {
57
57
 
58
58
  console.log (xml)
59
59
 
60
- const lex = new XMLLexer ({
61
- // maxLength: 40,
62
- // encoding: 'ascii',
63
- // stripSpace: true,
64
- })
65
-
66
60
  const sax = new XMLReader ({
67
61
  stripSpace: true,
68
- collect: e => true,
69
- find: e => true
70
- // && e.type === SAXEvent.TYPES.CHARACTERS
71
- && e.localName === 'SendRequestRequest'
72
- && e.type === SAXEvent.TYPES.END_ELEMENT
73
- // && e.level === 6
74
- ,
62
+ filterElements: 'SendRequestRequest',
75
63
  map: MoxyLikeJsonEncoder ({wrap: 1})
76
- // useEntities: false,
77
64
  })
78
65
 
79
- lex.pipe (sax)
80
-
81
-
66
+ /*
82
67
  for (let event of [
83
- 'StartDocument',
84
- 'ProcessingInstruction',
85
- 'Comment',
86
- 'DTD',
87
- 'StartElement',
88
- 'Characters',
89
- 'EndElement',
90
- 'EndDocument',
68
+ 'data',
69
+ 'close',
70
+ 'end',
71
+ 'finish',
72
+ // 'EndElement',
91
73
  ]) sax.on (event, data => {
92
-
93
- // console.log ([event, data])
94
-
95
- console.log (JSON.stringify (data, null, 2))
96
-
97
- /*
98
- console.log ([event, data, data.name, data.localName, data.namespaceURI])
99
-
100
- const {attributes} = data; for (const [k, v] of attributes.entries ()) {
101
-
102
- console.log ([k, attributes.getLocalName (k), attributes.getNamespaceURI (k), v])
103
-
104
- console.log ([attributes.get ('ns0:foo')])
105
74
 
106
- console.log ([attributes.get ('foo')])
107
-
108
- console.log ([attributes.get ('foo', 'urn:dom.gosuslugi.ru/common/1.2.0')])
109
-
110
- }
111
- */
75
+ console.log ([JSON.stringify (data, null, 2), event])
76
+
112
77
  })
113
-
78
+ */
79
+
80
+
81
+ // sax.process (fs.createReadStream ('test/' + fn))
114
82
 
83
+ sax.process (xml)
115
84
 
85
+ //console.log (sax)
86
+ //console.log (sax.isSAX)
116
87
 
117
88
  /*
118
- sax.on ('StartElement', event => {
119
- console.log ([event, event.attributes])
120
- })
89
+ for await (const e of sax) {
90
+ console.log (e)
91
+ }
121
92
  */
122
- // lexer.on ('data', data => console.log ({data}))
123
-
124
- // for (let c of xml) lexer.write (c); lexer.end ()
125
- // for (let c of xml) lexer.write (Buffer.from ([c])); lexer.end ()
126
93
 
127
- lex.end (xml)
94
+ const v = await sax.findFirst ()
95
+
96
+ console.log (JSON.stringify (v, null, 2))
128
97
 
129
98
  }
130
99