xml-twig 1.0.6 → 1.1.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/README.md +85 -88
- package/doc/twig.md +187 -144
- package/package.json +3 -2
- package/{demo → samples}/memory-test.js +3 -2
- package/samples/sample.js +88 -0
- package/{demo → samples}/speed-test.js +4 -3
- package/twig.js +164 -187
- package/demo/demo.js +0 -18
package/twig.js
CHANGED
|
@@ -4,27 +4,57 @@ const EXPAT = 'expat';
|
|
|
4
4
|
let tree;
|
|
5
5
|
let current;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class RootHandler { }
|
|
10
|
+
class AnyHandler { }
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @constant {RootHandler} Root
|
|
15
|
+
* @type {RootHandler}
|
|
16
|
+
`*/
|
|
17
|
+
const Root = new RootHandler();
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @constant {AnyHandler} Any
|
|
21
|
+
* @type {AnyHandler}
|
|
22
|
+
*/
|
|
23
|
+
const Any = new AnyHandler();
|
|
19
24
|
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
27
|
+
* Optional settings for the Twig parser
|
|
28
|
+
* @typedef ParserOptions
|
|
29
|
+
* @param {string} method - The underlying parser. Either `'sax'` or `'expat'`.
|
|
30
|
+
* @param {string} encoding - Encoding of the XML File. Applies only to `expat` parser.
|
|
31
|
+
* @param {boolean} xmlns - If `true`, then namespaces are accessible by `namespace` property.
|
|
32
|
+
* @param {boolean} trim - If `true`, then turn any whitespace into a single space. Text and comments are trimmed.
|
|
33
|
+
* @param {boolean} resumeAfterError - If `true` then parser continues reading after an error. Otherwise it throws exception.
|
|
34
|
+
* @param {boolean} partial - It `true` then unhandled elements are purged.
|
|
35
|
+
* @example { encoding: 'UTF-8', xmlns: true }
|
|
36
|
+
* @default { method: 'sax', encoding: 'UTF-8', xmlns: false, trim: true, resumeAfterError: false, partial: false }
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Reference to handler functions for Twig objects.<br>
|
|
41
|
+
* Element can be specified as string, Regular Expression, custom function, `Twig.Root` or `Twig.Any`<br>
|
|
42
|
+
* You can specify a `function` or a `event` name
|
|
25
43
|
* @typedef TwigHandler
|
|
26
|
-
* @param {
|
|
27
|
-
* @param {
|
|
44
|
+
* @param {HandlerCondition} tag - Element specification
|
|
45
|
+
* @param {?HandlerFunction} function - Definition of handler function, either anonymous or explicit function
|
|
46
|
+
* @param {?string} event - Type of the event to be emitted
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Condition to specify when handler shall be called<br>
|
|
51
|
+
* - If `undefined`, then all elements are returned.<br>
|
|
52
|
+
* - If `string` then the element name must be equal to the string
|
|
53
|
+
* - If `RegExp` then the element name must match the Regular Expression
|
|
54
|
+
* - If [HandlerConditionFilter](#HandlerConditionFilter) then function must return `true`
|
|
55
|
+
* - Use `Twig.Root` to call the handler on root element, i.e. when the end of document is reached
|
|
56
|
+
* - Use `Twig.Any` to call the handler on every element
|
|
57
|
+
* @typedef {string|RegExp|HandlerConditionFilter|RootHandler|AnyHandler} HandlerCondition
|
|
28
58
|
*/
|
|
29
59
|
|
|
30
60
|
/**
|
|
@@ -33,6 +63,13 @@ let current;
|
|
|
33
63
|
* @param {Twig} elt - The current Twig element on which the function was called.
|
|
34
64
|
*/
|
|
35
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Custom filter function to specify when handler shall be called
|
|
68
|
+
* @typedef {function} HandlerConditionFilter
|
|
69
|
+
* @param {string} name - Name of the element
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
|
|
36
73
|
|
|
37
74
|
|
|
38
75
|
/**
|
|
@@ -40,37 +77,54 @@ let current;
|
|
|
40
77
|
* - If `undefined`, then all elements are returned.<br>
|
|
41
78
|
* - If `string` then the element name must be equal to the string
|
|
42
79
|
* - If `RegExp` then the element name must match the Regular Expression
|
|
43
|
-
* - If [ElementConditionFilter](#ElementConditionFilter) then
|
|
44
|
-
* - Use [Twig](#Twig) object to find a specific element
|
|
80
|
+
* - If [ElementConditionFilter](#ElementConditionFilter) then function must return `true`
|
|
81
|
+
* - Use [Twig](#Twig) object to find a specific element
|
|
45
82
|
* @typedef {string|RegExp|ElementConditionFilter|Twig} ElementCondition
|
|
46
83
|
*/
|
|
47
84
|
|
|
48
85
|
/**
|
|
49
|
-
*
|
|
50
|
-
* Custom filter function to get desired elements
|
|
86
|
+
* Custom filter function to select desired elements
|
|
51
87
|
* @typedef {function} ElementConditionFilter
|
|
52
88
|
* @param {string} name - Name of the element
|
|
53
|
-
* @param {Twig} elt - The
|
|
89
|
+
* @param {Twig} elt - The Twig object
|
|
54
90
|
*/
|
|
55
91
|
|
|
56
92
|
|
|
93
|
+
|
|
57
94
|
/**
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
95
|
+
* Create a new Twig parser
|
|
96
|
+
* @param {TwigHandler|TwigHandler[]} handler - Object or array of element specification and function to handle elements
|
|
97
|
+
* @param {?ParserOptions} options - Object of optional options
|
|
98
|
+
* @throws {UnsupportedParser} - For an unsupported parser. Currently `expat` and `sax` (default) are supported.
|
|
99
|
+
*/
|
|
63
100
|
function createParser(handler, options) {
|
|
64
101
|
options = Object.assign({ method: SAX, encoding: 'UTF-8', xmlns: false, trim: true, resumeAfterError: false, partial: false }, options)
|
|
65
102
|
let parser;
|
|
66
103
|
let namespaces = {};
|
|
67
104
|
let closeEvent;
|
|
68
105
|
|
|
106
|
+
if (options.partial) {
|
|
107
|
+
let hndl = Array.isArray(handler) ? handler : [handler];
|
|
108
|
+
let any = hndl.find(x => x.tag instanceof AnyHandler);
|
|
109
|
+
if (any !== undefined)
|
|
110
|
+
console.warn(`Using option '{ partial: true }' and handler '{ tag: Any, function: ${any.function.toString()} }' does not make much sense`);
|
|
111
|
+
}
|
|
112
|
+
|
|
69
113
|
// `parser.on("...", err => {...}` does not work, because I need access to 'this'
|
|
70
114
|
if (options.method === SAX) {
|
|
71
|
-
// Set options to have the same
|
|
115
|
+
// Set options to have the same behavior as in expat
|
|
72
116
|
parser = require("sax").createStream(true, { strictEntities: true, position: true, xmlns: options.xmlns, trim: options.trim });
|
|
73
117
|
|
|
118
|
+
Object.defineProperty(parser, 'currentLine', {
|
|
119
|
+
enumerable: true,
|
|
120
|
+
get() { return parser._parser.line + 1 }
|
|
121
|
+
});
|
|
122
|
+
Object.defineProperty(parser, 'currentColumn', {
|
|
123
|
+
enumerable: true,
|
|
124
|
+
get() { return parser._parser.column + 1 }
|
|
125
|
+
});
|
|
126
|
+
parser.underlyingParser = parser._parser;
|
|
127
|
+
|
|
74
128
|
closeEvent = "closetag";
|
|
75
129
|
parser.on("opentagstart", function (node) {
|
|
76
130
|
if (tree === undefined) {
|
|
@@ -82,13 +136,13 @@ function createParser(handler, options) {
|
|
|
82
136
|
let elt = new Twig(node.name, current);
|
|
83
137
|
if (options.partial) {
|
|
84
138
|
for (let hndl of Array.isArray(handler) ? handler : [handler]) {
|
|
85
|
-
if (typeof hndl.
|
|
139
|
+
if (typeof hndl.tag === 'string' && node.name === hndl.tag) {
|
|
86
140
|
elt.pin();
|
|
87
141
|
break;
|
|
88
|
-
} else if (hndl.
|
|
142
|
+
} else if (hndl.tag instanceof RegExp && hndl.tag.test(node.name)) {
|
|
89
143
|
elt.pin();
|
|
90
144
|
break;
|
|
91
|
-
} else if (typeof hndl.
|
|
145
|
+
} else if (typeof hndl.tag === 'function' && hndl.tag(node.name, current ?? tree)) {
|
|
92
146
|
elt.pin();
|
|
93
147
|
break;
|
|
94
148
|
}
|
|
@@ -148,15 +202,26 @@ function createParser(handler, options) {
|
|
|
148
202
|
current.text = str;
|
|
149
203
|
})
|
|
150
204
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
205
|
+
let hndl = Array.isArray(handler) ? handler : [handler];
|
|
206
|
+
let rootHandler = hndl.find(x => x.tag instanceof RootHandler);
|
|
207
|
+
parser.on("end", function () {
|
|
208
|
+
if (typeof rootHandler?.function === 'function') rootHandler.function(tree);
|
|
209
|
+
if (typeof rootHandler?.event === 'string') parser.emit(rootHandler.event, tree);
|
|
210
|
+
})
|
|
211
|
+
|
|
157
212
|
} else if (options.method === EXPAT) {
|
|
158
213
|
parser = require("node-expat").createParser();
|
|
159
214
|
parser.encoding = options.encoding;
|
|
215
|
+
|
|
216
|
+
Object.defineProperty(parser, 'currentLine', {
|
|
217
|
+
enumerable: true,
|
|
218
|
+
get() { return parser.parser.getCurrentLineNumber() }
|
|
219
|
+
});
|
|
220
|
+
Object.defineProperty(parser, 'currentColumn', {
|
|
221
|
+
enumerable: true,
|
|
222
|
+
get() { return parser.parser.getCurrentColumnNumber() }
|
|
223
|
+
});
|
|
224
|
+
parser.underlyingParser = parser.parser;
|
|
160
225
|
closeEvent = "endElement";
|
|
161
226
|
|
|
162
227
|
parser.on("startElement", function (name, attrs) {
|
|
@@ -169,13 +234,13 @@ function createParser(handler, options) {
|
|
|
169
234
|
let elt = new Twig(name, current, attrs);
|
|
170
235
|
if (options.partial) {
|
|
171
236
|
for (let hndl of Array.isArray(handler) ? handler : [handler]) {
|
|
172
|
-
if (typeof hndl.
|
|
237
|
+
if (typeof hndl.tag === 'string' && name === hndl.tag) {
|
|
173
238
|
elt.pin();
|
|
174
239
|
break;
|
|
175
|
-
} else if (hndl.
|
|
240
|
+
} else if (hndl.tag instanceof RegExp && hndl.tag.test(name)) {
|
|
176
241
|
elt.pin();
|
|
177
242
|
break;
|
|
178
|
-
} else if (typeof hndl.
|
|
243
|
+
} else if (typeof hndl.tag === 'function' && hndl.tag(name, current ?? tree)) {
|
|
179
244
|
elt.pin();
|
|
180
245
|
break;
|
|
181
246
|
}
|
|
@@ -220,33 +285,30 @@ function createParser(handler, options) {
|
|
|
220
285
|
}
|
|
221
286
|
|
|
222
287
|
parser.on(closeEvent, function (name) {
|
|
223
|
-
|
|
224
|
-
if (options.method === SAX) {
|
|
225
|
-
pos = { line: this._parser.line + 1, column: this._parser.column + 1 };
|
|
226
|
-
} else if (options.method === EXPAT) {
|
|
227
|
-
pos = { line: this.parser.getCurrentLineNumber(), column: this.parser.getCurrentColumnNumber() };
|
|
228
|
-
}
|
|
229
|
-
current.close(pos);
|
|
288
|
+
current.close();
|
|
230
289
|
let purge = true;
|
|
231
290
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
291
|
+
for (let hndl of Array.isArray(handler) ? handler : [handler]) {
|
|
292
|
+
if (hndl.tag instanceof AnyHandler) {
|
|
293
|
+
if (typeof hndl.function === 'function') hndl.function(current ?? tree);
|
|
294
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
295
|
+
purge = false;
|
|
296
|
+
} else if (hndl.tag instanceof RootHandler && options.method === EXPAT && current.isRoot) {
|
|
297
|
+
if (typeof hndl.function === 'function') hndl.function(tree);
|
|
298
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, tree);
|
|
299
|
+
purge = false;
|
|
300
|
+
} else if (typeof hndl.tag === 'string' && name === hndl.tag) {
|
|
301
|
+
if (typeof hndl.function === 'function') hndl.function(current ?? tree);
|
|
302
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
303
|
+
purge = false;
|
|
304
|
+
} else if (hndl.tag instanceof RegExp && hndl.tag.test(name)) {
|
|
305
|
+
if (typeof hndl.function === 'function') hndl.function(current ?? tree);
|
|
306
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
307
|
+
purge = false;
|
|
308
|
+
} else if (typeof hndl.tag === 'function' && hndl.tag(name, current ?? tree)) {
|
|
309
|
+
if (typeof hndl.function === 'function') hndl.function(current ?? tree);
|
|
310
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
311
|
+
purge = false;
|
|
250
312
|
}
|
|
251
313
|
}
|
|
252
314
|
|
|
@@ -254,7 +316,6 @@ function createParser(handler, options) {
|
|
|
254
316
|
current.purge();
|
|
255
317
|
current = current.parent();
|
|
256
318
|
|
|
257
|
-
|
|
258
319
|
})
|
|
259
320
|
|
|
260
321
|
// Common events
|
|
@@ -281,17 +342,10 @@ function createParser(handler, options) {
|
|
|
281
342
|
})
|
|
282
343
|
|
|
283
344
|
parser.on('error', function (err) {
|
|
284
|
-
|
|
285
|
-
if (options.method === SAX) {
|
|
286
|
-
p = this._parser;
|
|
287
|
-
console.error(`error at line [${p.line + 1}], column [${p.column + 1}]`, err);
|
|
288
|
-
} else if (options.method === EXPAT) {
|
|
289
|
-
p = this.parser;
|
|
290
|
-
console.error(`error at line [${p.getCurrentLineNumber()}], column [${p.getCurrentColumnNumber()}]`, err);
|
|
291
|
-
}
|
|
345
|
+
console.error(`error at line [${parser.currentLine}], column [${parser.currentColumn}]`, err);
|
|
292
346
|
if (options.resumeAfterError) {
|
|
293
|
-
|
|
294
|
-
|
|
347
|
+
parser.underlyingParser.error = null;
|
|
348
|
+
parser.underlyingParser.resume();
|
|
295
349
|
}
|
|
296
350
|
});
|
|
297
351
|
|
|
@@ -370,18 +424,6 @@ class Twig {
|
|
|
370
424
|
*/
|
|
371
425
|
#parent;
|
|
372
426
|
|
|
373
|
-
/**
|
|
374
|
-
* @property {object} #postion - The postion of the element in #children array
|
|
375
|
-
* @private
|
|
376
|
-
*/
|
|
377
|
-
#postion = {};
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* @property {number} #level - Root element is level 0, children have 1 and so on
|
|
381
|
-
* @private
|
|
382
|
-
*/
|
|
383
|
-
#level;
|
|
384
|
-
|
|
385
427
|
/**
|
|
386
428
|
* @property {boolean} #pinned - Determines whether twig is needed in partial load
|
|
387
429
|
* @private
|
|
@@ -392,14 +434,13 @@ class Twig {
|
|
|
392
434
|
* Create a new Twig object
|
|
393
435
|
* @param {string} name - The name of the XML element
|
|
394
436
|
* @param {Twig} parent - The parent object
|
|
395
|
-
* @param {?object} attributes -
|
|
437
|
+
* @param {?object} attributes - Attribute object
|
|
396
438
|
*/
|
|
397
439
|
constructor(name, parent, attributes) {
|
|
398
440
|
current = this;
|
|
399
441
|
if (name === null) {
|
|
400
442
|
// Root element not available yet
|
|
401
443
|
tree = this;
|
|
402
|
-
this.#level = 0;
|
|
403
444
|
} else {
|
|
404
445
|
this.#name = name;
|
|
405
446
|
if (attributes !== undefined)
|
|
@@ -407,10 +448,8 @@ class Twig {
|
|
|
407
448
|
if (parent === undefined) {
|
|
408
449
|
// Root element
|
|
409
450
|
tree = this;
|
|
410
|
-
this.#level = 0;
|
|
411
451
|
} else {
|
|
412
452
|
this.#parent = parent;
|
|
413
|
-
this.#level = this.#parent.#level + 1;
|
|
414
453
|
if (this.#parent.#pinned)
|
|
415
454
|
this.#pinned = true;
|
|
416
455
|
parent.#children.push(this);
|
|
@@ -472,7 +511,13 @@ class Twig {
|
|
|
472
511
|
* @returns {number} The level of the element.
|
|
473
512
|
*/
|
|
474
513
|
get level() {
|
|
475
|
-
|
|
514
|
+
let ret = 0;
|
|
515
|
+
let p = this.#parent;
|
|
516
|
+
while (p !== undefined) {
|
|
517
|
+
p = p.#parent;
|
|
518
|
+
ret++;
|
|
519
|
+
}
|
|
520
|
+
return ret;
|
|
476
521
|
}
|
|
477
522
|
|
|
478
523
|
/**
|
|
@@ -491,22 +536,6 @@ class Twig {
|
|
|
491
536
|
return this.#children.length > 0;
|
|
492
537
|
}
|
|
493
538
|
|
|
494
|
-
/**
|
|
495
|
-
* Returns the line where current element is closed
|
|
496
|
-
* @returns {number} Current line
|
|
497
|
-
*/
|
|
498
|
-
get line() {
|
|
499
|
-
return this.#postion.line;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* Returns the column where current element is closed
|
|
504
|
-
* @returns {number} Current column
|
|
505
|
-
*/
|
|
506
|
-
get column() {
|
|
507
|
-
return this.#postion.column;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
539
|
/**
|
|
511
540
|
* The position in `#children` array. For root object 0
|
|
512
541
|
* @returns {number} Position of element in parent
|
|
@@ -578,10 +607,8 @@ class Twig {
|
|
|
578
607
|
|
|
579
608
|
/**
|
|
580
609
|
* Closes the element
|
|
581
|
-
* @param {object} pos - The current possion (line and column) in the XML document
|
|
582
610
|
*/
|
|
583
|
-
close = function (
|
|
584
|
-
this.#postion = pos;
|
|
611
|
+
close = function () {
|
|
585
612
|
Object.seal(this);
|
|
586
613
|
}
|
|
587
614
|
|
|
@@ -593,8 +620,8 @@ class Twig {
|
|
|
593
620
|
#addChild = function (xw, childArray) {
|
|
594
621
|
for (let elt of childArray) {
|
|
595
622
|
xw.startElement(elt.name);
|
|
596
|
-
for (let key
|
|
597
|
-
xw.writeAttribute(key,
|
|
623
|
+
for (let [key, val] of Object.entries(elt.attributes))
|
|
624
|
+
xw.writeAttribute(key, val);
|
|
598
625
|
if (elt.text !== null)
|
|
599
626
|
xw.text(elt.text);
|
|
600
627
|
this.#addChild(xw, elt.children());
|
|
@@ -613,8 +640,8 @@ class Twig {
|
|
|
613
640
|
let xw = par instanceof XMLWriter ? par : new XMLWriter(par);
|
|
614
641
|
|
|
615
642
|
xw.startElement(this.#name);
|
|
616
|
-
for (let key
|
|
617
|
-
xw.writeAttribute(key,
|
|
643
|
+
for (let [key, val] of Object.entries(this.#attributes))
|
|
644
|
+
xw.writeAttribute(key, val);
|
|
618
645
|
if (this.#text !== null)
|
|
619
646
|
xw.text(this.#text);
|
|
620
647
|
this.#addChild(xw, this.#children);
|
|
@@ -623,10 +650,10 @@ class Twig {
|
|
|
623
650
|
}
|
|
624
651
|
|
|
625
652
|
/**
|
|
626
|
-
* Returns
|
|
653
|
+
* Returns attribute value or `null` if not found.<br>
|
|
627
654
|
* If more than one matches the condition, then it returns object as [attribute()](#attribute)
|
|
628
655
|
* @param {?AttributeCondition} condition - Optional condition to select attribute
|
|
629
|
-
* @returns {string|number|object} - The value of the
|
|
656
|
+
* @returns {string|number|object} - The value of the attribute or `null` if the does not exist
|
|
630
657
|
*/
|
|
631
658
|
attr = function (condition) {
|
|
632
659
|
let attr = this.attribute(condition);
|
|
@@ -638,7 +665,7 @@ class Twig {
|
|
|
638
665
|
|
|
639
666
|
/**
|
|
640
667
|
* Returns all attributes of the element
|
|
641
|
-
* @returns {
|
|
668
|
+
* @returns {object} All XML Attributes
|
|
642
669
|
*/
|
|
643
670
|
get attributes() {
|
|
644
671
|
return this.#attributes;
|
|
@@ -726,45 +753,44 @@ class Twig {
|
|
|
726
753
|
|
|
727
754
|
/**
|
|
728
755
|
* Common function to filter Twig elements from array
|
|
729
|
-
* @param {Twig|Twig[]}
|
|
756
|
+
* @param {Twig|Twig[]} elements - Array of elements you like to filter or a single element
|
|
730
757
|
* @param {?ElementCondition} condition - The filter condition
|
|
731
758
|
* @returns {Twig[]} List of matching elements or empty array
|
|
732
759
|
*/
|
|
733
|
-
filterElements(
|
|
734
|
-
if (!Array.isArray(
|
|
735
|
-
return filterElements([
|
|
760
|
+
filterElements(elements, condition) {
|
|
761
|
+
if (!Array.isArray(elements))
|
|
762
|
+
return filterElements([elements], condition);
|
|
736
763
|
|
|
737
764
|
if (condition === undefined) {
|
|
738
|
-
return
|
|
765
|
+
return elements;
|
|
739
766
|
} else if (typeof condition === 'string') {
|
|
740
|
-
return
|
|
741
|
-
//return this.filterElements(elts, x => { return x === condition });
|
|
767
|
+
return elements.filter(x => x.name === condition);
|
|
742
768
|
} else if (condition instanceof RegExp) {
|
|
743
|
-
return
|
|
769
|
+
return elements.filter(x => x.condition.test(x.name));
|
|
744
770
|
} else if (condition instanceof Twig) {
|
|
745
|
-
return
|
|
771
|
+
return elements.filter(x => Object.is(x, condition));
|
|
746
772
|
} else if (typeof condition === 'function') {
|
|
747
|
-
return
|
|
773
|
+
return elements.filter(x => condition(x.name, x));
|
|
748
774
|
}
|
|
749
775
|
}
|
|
750
776
|
|
|
751
777
|
/**
|
|
752
778
|
* Common function to filter Twig element
|
|
753
|
-
* @param {Twig}
|
|
779
|
+
* @param {Twig} element - Element you like to filter
|
|
754
780
|
* @param {?ElementCondition} condition - The filter condition
|
|
755
781
|
* @returns {boolean} `true` if the condition matches
|
|
756
782
|
*/
|
|
757
|
-
testElement(
|
|
783
|
+
testElement(element, condition) {
|
|
758
784
|
if (condition === undefined) {
|
|
759
785
|
return true;
|
|
760
786
|
} else if (typeof condition === 'string') {
|
|
761
|
-
return
|
|
787
|
+
return element.name === condition;
|
|
762
788
|
} else if (condition instanceof RegExp) {
|
|
763
|
-
return condition.test(
|
|
789
|
+
return condition.test(element.name);
|
|
764
790
|
} else if (condition instanceof Twig) {
|
|
765
|
-
return Object.is(
|
|
791
|
+
return Object.is(element, condition);
|
|
766
792
|
} else if (typeof condition === 'function') {
|
|
767
|
-
return condition(
|
|
793
|
+
return condition(element.name, element);
|
|
768
794
|
}
|
|
769
795
|
return false;
|
|
770
796
|
}
|
|
@@ -826,7 +852,7 @@ class Twig {
|
|
|
826
852
|
}
|
|
827
853
|
|
|
828
854
|
/**
|
|
829
|
-
* Returns the first matching element. This is
|
|
855
|
+
* Returns the first matching element. This is usually the root element
|
|
830
856
|
* @param {?ElementCondition} condition - Optional condition
|
|
831
857
|
* @returns {Twig} - The first element
|
|
832
858
|
*/
|
|
@@ -837,7 +863,7 @@ class Twig {
|
|
|
837
863
|
}
|
|
838
864
|
|
|
839
865
|
/**
|
|
840
|
-
* Returns the last matching element.
|
|
866
|
+
* Returns the last matching element.
|
|
841
867
|
* @param {?ElementCondition} condition - Optional condition
|
|
842
868
|
* @returns {Twig} - The last element
|
|
843
869
|
*/
|
|
@@ -1086,54 +1112,5 @@ class UnsupportedCondition extends TypeError {
|
|
|
1086
1112
|
}
|
|
1087
1113
|
}
|
|
1088
1114
|
|
|
1115
|
+
module.exports = { createParser, Twig, Any, Root };
|
|
1089
1116
|
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
module.exports = { createParser, Twig };
|
|
1094
|
-
|
|
1095
|
-
/*
|
|
1096
|
-
// All events emit with a single argument. To listen to an event, assign a function to on<eventname>.
|
|
1097
|
-
sax.EVENTS = [
|
|
1098
|
-
'text',
|
|
1099
|
-
'processinginstruction',
|
|
1100
|
-
'sgmldeclaration',
|
|
1101
|
-
'doctype',
|
|
1102
|
-
'comment',
|
|
1103
|
-
'opentagstart',
|
|
1104
|
-
'attribute',
|
|
1105
|
-
'opentag',
|
|
1106
|
-
'closetag',
|
|
1107
|
-
'opencdata',
|
|
1108
|
-
'cdata',
|
|
1109
|
-
'closecdata',
|
|
1110
|
-
'error',
|
|
1111
|
-
'end',
|
|
1112
|
-
'ready',
|
|
1113
|
-
'script',
|
|
1114
|
-
'opennamespace',
|
|
1115
|
-
'closenamespace'
|
|
1116
|
-
]
|
|
1117
|
-
parser.onerror = function (e) {
|
|
1118
|
-
// an error happened.
|
|
1119
|
-
};
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
node-expat.events = {
|
|
1125
|
-
#on('startElement' function (name, attrs) {})
|
|
1126
|
-
#on('endElement' function (name) {})
|
|
1127
|
-
#on('text' function (text) {})
|
|
1128
|
-
#on('processingInstruction', function (target, data) {})
|
|
1129
|
-
#on('comment', function (s) {})
|
|
1130
|
-
#on('xmlDecl', function (version, encoding, standalone) {})
|
|
1131
|
-
#on('startCdata', function () {})
|
|
1132
|
-
#on('endCdata', function () {})
|
|
1133
|
-
#on('entityDecl', function (entityName, isParameterEntity, value, base, systemId, publicId, notationName) {})
|
|
1134
|
-
#on('error', function (e) {})
|
|
1135
|
-
#stop() pauses
|
|
1136
|
-
#resume() resumes
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
*/
|
package/demo/demo.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const process = require('process');
|
|
3
|
-
|
|
4
|
-
const parser = require('xml-twig').createParser({ name: /book$/, function: bookHandler }, { method: 'sax' })
|
|
5
|
-
fs.createReadStream(`${__dirname}/../samples/bookstore.xml`).pipe(parser)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function bookHandler(elt) {
|
|
9
|
-
console.log(`${elt.attr("category")} ${elt.name} at line ${elt.line}`)
|
|
10
|
-
elt.purge()
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function rootHandler(elt) {
|
|
15
|
-
console.log(`${elt.name} finished after ${elt.line} lines`);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|