xml-toolkit 0.0.1
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/LICENSE +21 -0
- package/README.md +4 -0
- package/index.js +5 -0
- package/lib/SAXEvent.js +166 -0
- package/lib/SAXEventEmitter.js +42 -0
- package/lib/XMLLexer.js +292 -0
- package/package.json +22 -0
- package/test/E05a.xml +5 -0
- package/test/not-sa01.xml +10 -0
- package/test/not-sa02.xml +30 -0
- package/test/param_types.xml +1 -0
- package/test/test.js +105 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 do-
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
package/index.js
ADDED
package/lib/SAXEvent.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const assert = require ('assert')
|
|
2
|
+
|
|
3
|
+
const CH_LT = '<'.charCodeAt (0)
|
|
4
|
+
const CH_EXCLAMATION = '!'.charCodeAt (0)
|
|
5
|
+
const CH_QUESTION = '?'.charCodeAt (0)
|
|
6
|
+
const CH_SLASH = '/'.charCodeAt (0)
|
|
7
|
+
const CH_MINUS = '-'.charCodeAt (0)
|
|
8
|
+
|
|
9
|
+
const STR_XML = 'XML'
|
|
10
|
+
const STR_CDATA = '[CDATA['
|
|
11
|
+
const STR_DOCTYPE = 'DOCTYPE'
|
|
12
|
+
|
|
13
|
+
const START_DOCUMENT = 'StartDocument'
|
|
14
|
+
const PROCESSING_INSTRUCTION = 'ProcessingInstruction'
|
|
15
|
+
const COMMENT = 'Comment'
|
|
16
|
+
const DTD = 'DTD'
|
|
17
|
+
const START_ELEMENT = 'StartElement'
|
|
18
|
+
const CHARACTERS = 'Characters'
|
|
19
|
+
const END_ELEMENT = 'EndElement'
|
|
20
|
+
const END_DOCUMENT = 'EndDocument'
|
|
21
|
+
const CDATA = 'CDATA'
|
|
22
|
+
|
|
23
|
+
const SAXEvent = class {
|
|
24
|
+
|
|
25
|
+
constructor (src) {
|
|
26
|
+
|
|
27
|
+
this.src = src
|
|
28
|
+
|
|
29
|
+
this._afterName = 0
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get type () {
|
|
34
|
+
|
|
35
|
+
const {src} = this
|
|
36
|
+
|
|
37
|
+
switch (src.charCodeAt (0)) {
|
|
38
|
+
|
|
39
|
+
case CH_LT:
|
|
40
|
+
|
|
41
|
+
switch (src.charCodeAt (1)) {
|
|
42
|
+
|
|
43
|
+
case CH_SLASH:
|
|
44
|
+
|
|
45
|
+
return END_ELEMENT
|
|
46
|
+
|
|
47
|
+
case CH_QUESTION:
|
|
48
|
+
|
|
49
|
+
switch (src.slice (2, 5).toLowerCase ()) {
|
|
50
|
+
|
|
51
|
+
case STR_XML: return START_DOCUMENT
|
|
52
|
+
|
|
53
|
+
default: return PROCESSING_INSTRUCTION
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
case CH_EXCLAMATION:
|
|
58
|
+
|
|
59
|
+
if (src.charCodeAt (2) === CH_MINUS) return COMMENT
|
|
60
|
+
|
|
61
|
+
switch (src.slice (2, 9)) {
|
|
62
|
+
|
|
63
|
+
case STR_CDATA: return CDATA
|
|
64
|
+
|
|
65
|
+
case STR_DOCTYPE: return DTD
|
|
66
|
+
|
|
67
|
+
default: return null
|
|
68
|
+
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
default: return START_ELEMENT
|
|
72
|
+
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
break
|
|
76
|
+
|
|
77
|
+
default:
|
|
78
|
+
|
|
79
|
+
return CHARACTERS
|
|
80
|
+
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get text () {
|
|
86
|
+
|
|
87
|
+
const {src} = this
|
|
88
|
+
|
|
89
|
+
switch (src.charCodeAt (0)) {
|
|
90
|
+
|
|
91
|
+
case CH_LT: return src.slice (9, -3)
|
|
92
|
+
|
|
93
|
+
default: return src
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get attributes () {
|
|
100
|
+
|
|
101
|
+
const m = new Map ()
|
|
102
|
+
|
|
103
|
+
this.writeAttributesToMap (m)
|
|
104
|
+
|
|
105
|
+
return m
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
writeAttributesToMap (m) {
|
|
110
|
+
|
|
111
|
+
const {src} = this
|
|
112
|
+
|
|
113
|
+
let start = this._afterName; while (true) {
|
|
114
|
+
|
|
115
|
+
const eq = src.indexOf ('=', start); if (eq === -1) break
|
|
116
|
+
|
|
117
|
+
const q = src.indexOf (src.charAt (eq + 1), eq + 2); if (q === -1) break
|
|
118
|
+
|
|
119
|
+
let k = src.slice (start, eq)
|
|
120
|
+
|
|
121
|
+
if (start === 0) {
|
|
122
|
+
|
|
123
|
+
let p = k.length - 2; while (p !== 0 && k.charCodeAt (p) <= 32) p --
|
|
124
|
+
|
|
125
|
+
k = k.slice (this._afterName = p)
|
|
126
|
+
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
|
|
130
|
+
k = k.trim ()
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
m.set (k, src.slice (eq + 2, q))
|
|
135
|
+
|
|
136
|
+
start = q + 1
|
|
137
|
+
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return m
|
|
141
|
+
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
get isSelfEnclosed () {
|
|
145
|
+
|
|
146
|
+
const {src} = this
|
|
147
|
+
|
|
148
|
+
return src.charCodeAt (src.length - 2) === CH_SLASH
|
|
149
|
+
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
SAXEvent.TYPES = {
|
|
155
|
+
START_DOCUMENT,
|
|
156
|
+
PROCESSING_INSTRUCTION,
|
|
157
|
+
COMMENT,
|
|
158
|
+
DTD,
|
|
159
|
+
START_ELEMENT,
|
|
160
|
+
CHARACTERS,
|
|
161
|
+
END_ELEMENT,
|
|
162
|
+
END_DOCUMENT,
|
|
163
|
+
CDATA,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = SAXEvent
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
package/lib/XMLLexer.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
const assert = require ('assert')
|
|
2
|
+
const {Transform} = require ('stream')
|
|
3
|
+
const {StringDecoder} = require('string_decoder')
|
|
4
|
+
|
|
5
|
+
const ST_TEXT = 0
|
|
6
|
+
const ST_LT = 1
|
|
7
|
+
const ST_LT_X = 2
|
|
8
|
+
const ST_TAG = 3
|
|
9
|
+
const ST_TAG_X = 4
|
|
10
|
+
|
|
11
|
+
const CH_EXCLAMATION = '!'.charCodeAt (0)
|
|
12
|
+
const CH_QUESTION = '?'.charCodeAt (0)
|
|
13
|
+
const CH_MINUS = '-'.charCodeAt (0)
|
|
14
|
+
const CH_SQUARE = '['.charCodeAt (0)
|
|
15
|
+
const CH_GT = '>'.charCodeAt (0)
|
|
16
|
+
|
|
17
|
+
const CL_DEAFULT = Buffer.from ('')
|
|
18
|
+
const CL_PI = Buffer.from ('?', 'ascii')
|
|
19
|
+
const CL_COMMENT = Buffer.from ('--', 'ascii')
|
|
20
|
+
const CL_SQ_1 = Buffer.from (']', 'ascii')
|
|
21
|
+
const CL_SQ_2 = Buffer.from (']]', 'ascii')
|
|
22
|
+
|
|
23
|
+
const S_ENCODING = Symbol ('encoding')
|
|
24
|
+
|
|
25
|
+
const XMLLexer = class extends Transform {
|
|
26
|
+
|
|
27
|
+
constructor (options = {}) {
|
|
28
|
+
|
|
29
|
+
options.readableObjectMode = true
|
|
30
|
+
options.decodeStrings = false
|
|
31
|
+
|
|
32
|
+
let encoding = options.encoding; delete options.encoding
|
|
33
|
+
if (encoding == null) encoding = 'utf8'
|
|
34
|
+
|
|
35
|
+
let maxLength = options.maxLength; delete options.maxLength
|
|
36
|
+
if (maxLength == null) maxLength = 1 << 20
|
|
37
|
+
|
|
38
|
+
assert (Number.isInteger (maxLength), 'maxLength must be integer, not ' + maxLength)
|
|
39
|
+
assert (maxLength > 0, 'maxLength must be positive, not ' + maxLength)
|
|
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
|
+
super (options)
|
|
45
|
+
|
|
46
|
+
this.decoder = new StringDecoder ('utf8')
|
|
47
|
+
|
|
48
|
+
this.stripSpace = options.stripSpace
|
|
49
|
+
this.body = ''
|
|
50
|
+
this.start = 0
|
|
51
|
+
this.setState (ST_TEXT)
|
|
52
|
+
this.beforeBody = 0n
|
|
53
|
+
|
|
54
|
+
this [S_ENCODING] = encoding
|
|
55
|
+
this.maxLength = maxLength
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
isClosing (pos) {
|
|
60
|
+
|
|
61
|
+
const {awaited} = this, {length} = awaited; if (length === 0) return true
|
|
62
|
+
|
|
63
|
+
let from = pos - length; if (from < this.start) return false
|
|
64
|
+
|
|
65
|
+
if (this.body.charCodeAt (from) !== awaited [0]) return false
|
|
66
|
+
|
|
67
|
+
if (length === 2 && this.body.charCodeAt (from + 1) !== awaited [1]) return false
|
|
68
|
+
|
|
69
|
+
return true
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
setState (state, awaited = null) {
|
|
74
|
+
|
|
75
|
+
switch (state) {
|
|
76
|
+
|
|
77
|
+
case ST_TAG:
|
|
78
|
+
case ST_TAG_X:
|
|
79
|
+
assert (awaited != null, 'ST_TAG[_X]: awaited is mandatory')
|
|
80
|
+
break
|
|
81
|
+
|
|
82
|
+
default:
|
|
83
|
+
assert (awaited === null, 'not ST_TAG[_X]: awaited must be null')
|
|
84
|
+
this.position = 0
|
|
85
|
+
break
|
|
86
|
+
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.state = state
|
|
90
|
+
this.awaited = awaited
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
parse () {
|
|
95
|
+
|
|
96
|
+
outer: while (true) {
|
|
97
|
+
|
|
98
|
+
const {start, body} = this
|
|
99
|
+
|
|
100
|
+
switch (this.state) {
|
|
101
|
+
|
|
102
|
+
case ST_TEXT:
|
|
103
|
+
|
|
104
|
+
{
|
|
105
|
+
|
|
106
|
+
const pos = body.indexOf ('<', start); switch (pos) {
|
|
107
|
+
|
|
108
|
+
case -1:
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
case 0:
|
|
112
|
+
this.setState (ST_LT)
|
|
113
|
+
break
|
|
114
|
+
|
|
115
|
+
default:
|
|
116
|
+
this.publishTo (pos - 1)
|
|
117
|
+
this.setState (ST_LT)
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
case ST_LT:
|
|
126
|
+
|
|
127
|
+
{
|
|
128
|
+
|
|
129
|
+
const pos = start + 1; if (pos >= body.length) return null
|
|
130
|
+
|
|
131
|
+
switch (body.charCodeAt (pos)) {
|
|
132
|
+
|
|
133
|
+
case CH_EXCLAMATION:
|
|
134
|
+
this.setState (ST_LT_X)
|
|
135
|
+
break
|
|
136
|
+
|
|
137
|
+
case CH_QUESTION:
|
|
138
|
+
this.setState (ST_TAG, CL_PI)
|
|
139
|
+
break
|
|
140
|
+
|
|
141
|
+
default:
|
|
142
|
+
this.setState (ST_TAG, CL_DEAFULT)
|
|
143
|
+
break
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
break
|
|
150
|
+
|
|
151
|
+
case ST_LT_X:
|
|
152
|
+
|
|
153
|
+
{
|
|
154
|
+
|
|
155
|
+
const pos = start + 2; if (pos >= body.length) return null
|
|
156
|
+
|
|
157
|
+
switch (body.charCodeAt (pos)) {
|
|
158
|
+
|
|
159
|
+
case CH_MINUS:
|
|
160
|
+
this.setState (ST_TAG, CL_COMMENT)
|
|
161
|
+
break
|
|
162
|
+
|
|
163
|
+
default:
|
|
164
|
+
this.setState (ST_TAG_X, CL_DEAFULT)
|
|
165
|
+
this.position = pos
|
|
166
|
+
break
|
|
167
|
+
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
break
|
|
173
|
+
|
|
174
|
+
case ST_TAG:
|
|
175
|
+
|
|
176
|
+
let pos = start; while (true) {
|
|
177
|
+
|
|
178
|
+
pos = body.indexOf ('>', pos + 1); if (pos === -1) return
|
|
179
|
+
|
|
180
|
+
if (!this.isClosing (pos)) continue
|
|
181
|
+
|
|
182
|
+
this.publishTo (pos)
|
|
183
|
+
|
|
184
|
+
this.setState (ST_TEXT)
|
|
185
|
+
|
|
186
|
+
continue outer
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
case ST_TAG_X:
|
|
191
|
+
|
|
192
|
+
for (let pos = this.position + 1; pos < body.length; pos ++) {
|
|
193
|
+
|
|
194
|
+
switch (body.charCodeAt (pos)) {
|
|
195
|
+
|
|
196
|
+
case CH_SQUARE:
|
|
197
|
+
|
|
198
|
+
switch (this.awaited) {
|
|
199
|
+
|
|
200
|
+
case CL_DEAFULT:
|
|
201
|
+
this.awaited = CL_SQ_1
|
|
202
|
+
break
|
|
203
|
+
|
|
204
|
+
case CL_SQ_1:
|
|
205
|
+
this.awaited = CL_SQ_2
|
|
206
|
+
break
|
|
207
|
+
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
this.position = pos
|
|
211
|
+
break
|
|
212
|
+
|
|
213
|
+
case CH_GT:
|
|
214
|
+
if (!this.isClosing (pos)) break
|
|
215
|
+
this.publishTo (pos)
|
|
216
|
+
this.setState (ST_TEXT)
|
|
217
|
+
continue outer
|
|
218
|
+
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
default:
|
|
226
|
+
throw new Error ('Invalid state: ' + this.state)
|
|
227
|
+
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
publishTo (pos) {
|
|
235
|
+
|
|
236
|
+
let lexeme = this.body.slice (this.start, ++ pos)
|
|
237
|
+
|
|
238
|
+
this.start = pos
|
|
239
|
+
|
|
240
|
+
if (this.stripSpace) lexeme = lexeme.trim ()
|
|
241
|
+
|
|
242
|
+
if (lexeme.length !== 0) this.push (lexeme)
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
_flush (callback) {
|
|
247
|
+
|
|
248
|
+
this.publishTo (this.body.length - 1)
|
|
249
|
+
|
|
250
|
+
callback ()
|
|
251
|
+
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
getPosition () {
|
|
255
|
+
|
|
256
|
+
let {beforeBody, start} = this
|
|
257
|
+
|
|
258
|
+
return start === 0 ? beforeBody : beforeBody + BigInt (start)
|
|
259
|
+
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
checkMaxLength () {
|
|
263
|
+
|
|
264
|
+
const {body, maxLength} = this, size = body.length - this.start;
|
|
265
|
+
|
|
266
|
+
if (size <= maxLength) return
|
|
267
|
+
|
|
268
|
+
const s = body.slice (0, size - 1), dump = JSON.stringify ([s])
|
|
269
|
+
|
|
270
|
+
this.destroy (new Error (`The fragment ${dump} at position ${this.getPosition ()} exceeds maxLength=${maxLength}`))
|
|
271
|
+
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
_transform (chunk, encoding, callback) {
|
|
275
|
+
|
|
276
|
+
if (Buffer.isBuffer (chunk)) chunk = this.decoder.write (chunk)
|
|
277
|
+
|
|
278
|
+
this.body = this.body.slice (this.start) + chunk
|
|
279
|
+
this.start = 0
|
|
280
|
+
|
|
281
|
+
this.parse ()
|
|
282
|
+
|
|
283
|
+
if (this.start > 0) this.beforeBody += BigInt (this.start)
|
|
284
|
+
this.checkMaxLength ()
|
|
285
|
+
|
|
286
|
+
callback ()
|
|
287
|
+
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
module.exports = XMLLexer
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "xml-toolkit",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Collection of classes for dealing with XML",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node test/test.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/do-/node-xml-toolkit.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"xml sax stax"
|
|
15
|
+
],
|
|
16
|
+
"author": "Dmitry Ovsyanko",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/do-/node-xml-toolkit/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/do-/node-xml-toolkit#readme"
|
|
22
|
+
}
|
package/test/E05a.xml
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<?xml version='1.0' standalone='no'?>
|
|
2
|
+
|
|
3
|
+
<!DOCTYPE attributes SYSTEM "../valid/sa.dtd" [
|
|
4
|
+
<!ENTITY internal " number99">
|
|
5
|
+
]>
|
|
6
|
+
|
|
7
|
+
<!-- sync with ../invalid/not-sa02.xml -->
|
|
8
|
+
|
|
9
|
+
<!--
|
|
10
|
+
lots of normalized/defaulted attributes
|
|
11
|
+
keep this from being standalone
|
|
12
|
+
|
|
13
|
+
XXX not the best basis for negative tests!!
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
<attributes
|
|
17
|
+
notation = " nonce "
|
|
18
|
+
nmtoken = " this-gets-normalized "
|
|
19
|
+
nmtokens = " this
|
|
20
|
+
also gets normalized "
|
|
21
|
+
id = " &internal; "
|
|
22
|
+
idref = " &internal;
|
|
23
|
+
"
|
|
24
|
+
idrefs = " &internal; &internal; &internal;"
|
|
25
|
+
entity = " unparsed-1 "
|
|
26
|
+
entities = "unparsed-1
|
|
27
|
+
unparsed-2
|
|
28
|
+
"
|
|
29
|
+
cdata = "nothing happens to this one!"
|
|
30
|
+
/>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><PARAMTYPES><PARAMTYPE ID="1" NAME="ИФНС ФЛ" DESC="ИФНС ФЛ" CODE="IFNSFL" ISACTIVE="true" UPDATEDATE="2018-06-15" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="2" NAME="ИФНС ЮЛ" DESC="ИФНС ЮЛ" CODE="IFNSUL" ISACTIVE="true" UPDATEDATE="2018-06-15" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="3" NAME="ИНН ФЛ ТЕР УЧ" DESC="Территориальный участок ИФНС ЮЛ" CODE="territorialifnsflcode" ISACTIVE="true" UPDATEDATE="2018-06-15" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="4" NAME="ИФНС ЮЛ ТЕР УЧ" DESC="Территориальный участок ИФНС ФЛ" CODE="territorialifnsulcode" ISACTIVE="true" UPDATEDATE="2018-06-15" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="5" NAME="Почтовый индекс" DESC="Информация о почтовом индексе" CODE="PostIndex" ISACTIVE="true" UPDATEDATE="2018-06-15" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="6" NAME="ОКАТО" DESC="ОКАТО" CODE="OKATO" ISACTIVE="true" UPDATEDATE="2018-06-19" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="7" NAME="OKTMO" DESC="OKTMO" CODE="OKTMO" ISACTIVE="true" UPDATEDATE="2018-06-19" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="8" NAME="Кадастровый номер" DESC="Кадастровый номер" CODE="CadastrNum" ISACTIVE="true" UPDATEDATE="2018-06-19" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="10" NAME="Код КЛАДР" DESC="Код адресного объекта одной строкой с признаком актуальности" CODE="CODE" ISACTIVE="true" UPDATEDATE="2018-06-21" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="11" NAME="Код КЛАДР без признака актуальности" DESC="Код адресного объекта одной строкой без признака актуальности" CODE="PLAINCODE" ISACTIVE="true" UPDATEDATE="2018-06-21" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="12" NAME="Код региона" DESC="Код региона" CODE="REGIONCODE" ISACTIVE="true" UPDATEDATE="2018-06-21" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="13" NAME="Реестровый номер" DESC="Реестровый номер адресного объекта" CODE="ReestrNum" ISACTIVE="true" UPDATEDATE="2018-11-12" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="14" NAME="Признак присвоения адреса" DESC="Признак в каком делении присвоен адрес, муниципальном/административном" CODE="DivisionType" ISACTIVE="true" UPDATEDATE="2018-12-14" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="15" NAME="Порядковый номер" DESC="Порядковый номер обьекта в рамках родителя" CODE="Counter" ISACTIVE="true" UPDATEDATE="2018-12-14" STARTDATE="2011-11-01" ENDDATE="2079-06-06" /><PARAMTYPE ID="16" NAME="Официальное наименование" DESC="Официальное наименование объекта(Региона)" CODE="Official" ISACTIVE="true" UPDATEDATE="2019-12-04" STARTDATE="2019-12-04" ENDDATE="2079-06-06" /></PARAMTYPES>
|
package/test/test.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const fs = require ('fs')
|
|
2
|
+
const assert = require ('assert')
|
|
3
|
+
const {SAXEventEmitter, SAXEvent, XMLLexer} = require ('../')
|
|
4
|
+
|
|
5
|
+
async function test_001_lexer_sync (fn) {
|
|
6
|
+
|
|
7
|
+
const xml = fs.readFileSync (
|
|
8
|
+
'test/' + fn
|
|
9
|
+
// , 'utf-8'
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
console.log (xml)
|
|
13
|
+
|
|
14
|
+
const lexer = new XMLLexer ({
|
|
15
|
+
// maxLength: 40,
|
|
16
|
+
// encoding: 'ascii',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
lexer.on ('data', data => console.log (new SAXEvent (data).attributes))
|
|
20
|
+
|
|
21
|
+
// for (let c of xml) lexer.write (c); lexer.end ()
|
|
22
|
+
// for (let c of xml) lexer.write (Buffer.from ([c])); lexer.end ()
|
|
23
|
+
|
|
24
|
+
lexer.end (xml)
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function test_002_lexer_stream (fn) {
|
|
29
|
+
|
|
30
|
+
const is = fs.createReadStream ('test/' + fn, {
|
|
31
|
+
// encoding: 'utf8',
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const lexer = new XMLLexer ({
|
|
35
|
+
// maxLength: 40,
|
|
36
|
+
// encoding: 'ascii',
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
is.pipe (lexer)
|
|
40
|
+
|
|
41
|
+
for await (const i of lexer)
|
|
42
|
+
// if (/^<PARAMTYPE /.test (i))
|
|
43
|
+
{
|
|
44
|
+
console.log ({i})
|
|
45
|
+
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
async function test_003_emitter_sync (fn) {
|
|
52
|
+
|
|
53
|
+
const xml = fs.readFileSync (
|
|
54
|
+
'test/' + fn
|
|
55
|
+
// , 'utf-8'
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
console.log (xml)
|
|
59
|
+
|
|
60
|
+
const lex = new XMLLexer ({
|
|
61
|
+
// maxLength: 40,
|
|
62
|
+
// encoding: 'ascii',
|
|
63
|
+
stripSpace: true,
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const sax = new SAXEventEmitter ({})
|
|
67
|
+
|
|
68
|
+
lex.pipe (sax)
|
|
69
|
+
|
|
70
|
+
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}))
|
|
82
|
+
|
|
83
|
+
// for (let c of xml) lexer.write (c); lexer.end ()
|
|
84
|
+
// for (let c of xml) lexer.write (Buffer.from ([c])); lexer.end ()
|
|
85
|
+
|
|
86
|
+
lex.end (xml)
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function main () {
|
|
91
|
+
|
|
92
|
+
// await test_001_lexer_sync ('E05a.xml')
|
|
93
|
+
// await test_001_lexer_sync ('not-sa01.xml')
|
|
94
|
+
// await test_001_lexer_sync ('not-sa02.xml')
|
|
95
|
+
await test_001_lexer_sync ('param_types.xml')
|
|
96
|
+
// await test_002_lexer_stream ('E05a.xml')
|
|
97
|
+
// await test_002_lexer_stream ('param_types.xml')
|
|
98
|
+
// await test_002_lexer_stream ('not-sa02.xml')
|
|
99
|
+
// await test_003_emitter_sync ('E05a.xml')
|
|
100
|
+
// await test_003_emitter_sync ('param_types.xml')
|
|
101
|
+
// await test_003_emitter_sync ('not-sa01.xml')
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
main ()
|