xml-twig 1.6.1 → 1.7.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/package.json +1 -1
- package/twig.js +68 -61
package/package.json
CHANGED
package/twig.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
const SAX = 'sax';
|
|
2
2
|
const EXPAT = ['expat', 'node-expat'];
|
|
3
3
|
|
|
4
|
-
let tree;
|
|
5
|
-
let current;
|
|
6
|
-
|
|
7
4
|
/**
|
|
8
5
|
* @external XMLWriter
|
|
9
6
|
* @see {@link https://www.npmjs.com/package/xml-writer|xml-writer}
|
|
@@ -124,6 +121,9 @@ const Any = new AnyHandler();
|
|
|
124
121
|
* @typedef Parser
|
|
125
122
|
* @property {number} [currentLine] - The currently processed line in the XML-File.
|
|
126
123
|
* @property {number} [currentColumn] - The currently processed column in the XML-File.
|
|
124
|
+
* @property {string} [file] - The name of file to be parsed. Just used for information and logging purpose.
|
|
125
|
+
* @property {object} [twig] - Object with XML tree and current XML element
|
|
126
|
+
* @property {string} [method] - The underlying parser. Either `'sax'`, `'expat'`.
|
|
127
127
|
* @returns {external:sax|external:node-expat} The parser Object
|
|
128
128
|
*/
|
|
129
129
|
|
|
@@ -160,7 +160,7 @@ function createParser(handler, options = {}) {
|
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
parser.on("closetag", onClose.bind(null, handler, parser, options));
|
|
163
|
-
parser.on("opentagstart", onStart.bind(null, {
|
|
163
|
+
parser.on("opentagstart", onStart.bind(null, parser, {
|
|
164
164
|
handler: Array.isArray(handler) ? handler : [handler],
|
|
165
165
|
options: options,
|
|
166
166
|
namespaces: namespaces
|
|
@@ -174,14 +174,14 @@ function createParser(handler, options = {}) {
|
|
|
174
174
|
let [k, v] = item.split('=');
|
|
175
175
|
declaration[k] = v.replaceAll('"', '').replaceAll("'", '');
|
|
176
176
|
}
|
|
177
|
-
tree = new Twig(null);
|
|
178
|
-
Object.defineProperty(tree, 'declaration', {
|
|
177
|
+
parser.twig.tree = new Twig(parser, null);
|
|
178
|
+
Object.defineProperty(parser.twig.tree, 'declaration', {
|
|
179
179
|
value: declaration,
|
|
180
180
|
writable: false,
|
|
181
181
|
enumerable: true
|
|
182
182
|
});
|
|
183
|
-
} else if (tree.PI === undefined) {
|
|
184
|
-
Object.defineProperty(tree, 'PI', {
|
|
183
|
+
} else if (parser.twig.tree.PI === undefined) {
|
|
184
|
+
Object.defineProperty(parser.twig.tree, 'PI', {
|
|
185
185
|
value: { target: pi.name, data: pi.body },
|
|
186
186
|
writable: false,
|
|
187
187
|
enumerable: true
|
|
@@ -192,26 +192,25 @@ function createParser(handler, options = {}) {
|
|
|
192
192
|
parser.on("attribute", function (attr) {
|
|
193
193
|
if (options.xmlns && (attr.uri ?? '') !== '' && attr.local !== undefined) {
|
|
194
194
|
namespaces[attr.local] = attr.uri;
|
|
195
|
-
if (current.name.includes(':')) {
|
|
196
|
-
Object.defineProperty(current, 'namespace', {
|
|
195
|
+
if (parser.twig.current.name.includes(':')) {
|
|
196
|
+
Object.defineProperty(parser.twig.current, 'namespace', {
|
|
197
197
|
value: { local: attr.local, uri: attr.uri },
|
|
198
198
|
writable: false,
|
|
199
199
|
enumerable: true
|
|
200
200
|
});
|
|
201
201
|
} else {
|
|
202
|
-
current.attribute(attr.name, attr.value);
|
|
202
|
+
parser.twig.current.attribute(attr.name, attr.value);
|
|
203
203
|
}
|
|
204
204
|
} else {
|
|
205
|
-
current.attribute(attr.name, attr.value);
|
|
205
|
+
parser.twig.current.attribute(attr.name, attr.value);
|
|
206
206
|
}
|
|
207
207
|
});
|
|
208
208
|
parser.on("cdata", function (str) {
|
|
209
|
-
current.text = options.trim ? str.trim() : str;
|
|
209
|
+
parser.twig.current.text = options.trim ? str.trim() : str;
|
|
210
210
|
});
|
|
211
211
|
|
|
212
212
|
parser.on('end', function () {
|
|
213
|
-
|
|
214
|
-
current = undefined;
|
|
213
|
+
parser.twig = { current: null, tree: null };
|
|
215
214
|
parser.emit("finish");
|
|
216
215
|
parser.emit("close");
|
|
217
216
|
});
|
|
@@ -228,19 +227,19 @@ function createParser(handler, options = {}) {
|
|
|
228
227
|
});
|
|
229
228
|
|
|
230
229
|
parser.on("endElement", onClose.bind(null, handler, parser, options));
|
|
231
|
-
parser.on("startElement", onStart.bind(null, {
|
|
230
|
+
parser.on("startElement", onStart.bind(null, parser, {
|
|
232
231
|
handler: Array.isArray(handler) ? handler : [handler],
|
|
233
232
|
options: options,
|
|
234
233
|
namespaces: namespaces
|
|
235
234
|
}));
|
|
236
235
|
|
|
237
236
|
parser.on('xmlDecl', function (version, encoding, standalone) {
|
|
238
|
-
tree = new Twig(null);
|
|
237
|
+
parser.twig.tree = new Twig(parser, null);
|
|
239
238
|
let dec = {};
|
|
240
239
|
if (version !== undefined) dec.version = version;
|
|
241
240
|
if (encoding !== undefined) dec.encoding = encoding;
|
|
242
241
|
if (standalone !== undefined) dec.standalone = standalone;
|
|
243
|
-
Object.defineProperty(tree, 'declaration', {
|
|
242
|
+
Object.defineProperty(parser.twig.tree, 'declaration', {
|
|
244
243
|
value: dec,
|
|
245
244
|
writable: false,
|
|
246
245
|
enumerable: true
|
|
@@ -248,12 +247,11 @@ function createParser(handler, options = {}) {
|
|
|
248
247
|
});
|
|
249
248
|
|
|
250
249
|
parser.on('processingInstruction', function (target, data) {
|
|
251
|
-
tree.PI = { target: target, data: data };
|
|
250
|
+
parser.twig.tree.PI = { target: target, data: data };
|
|
252
251
|
});
|
|
253
252
|
|
|
254
253
|
parser.on('end', function () {
|
|
255
|
-
|
|
256
|
-
current = undefined;
|
|
254
|
+
parser.twig = { current: null, tree: null };
|
|
257
255
|
parser.emit("finish");
|
|
258
256
|
});
|
|
259
257
|
|
|
@@ -261,6 +259,12 @@ function createParser(handler, options = {}) {
|
|
|
261
259
|
throw new UnsupportedParser(options.method);
|
|
262
260
|
}
|
|
263
261
|
|
|
262
|
+
Object.defineProperty(parser, 'twig', {
|
|
263
|
+
enumerable: true,
|
|
264
|
+
value: { current: null, tree: null },
|
|
265
|
+
writable: true
|
|
266
|
+
});
|
|
267
|
+
|
|
264
268
|
Object.defineProperty(parser, 'method', {
|
|
265
269
|
value: options.method,
|
|
266
270
|
writable: false,
|
|
@@ -277,19 +281,19 @@ function createParser(handler, options = {}) {
|
|
|
277
281
|
|
|
278
282
|
// Common events
|
|
279
283
|
parser.on('text', function (str) {
|
|
280
|
-
if (current ===
|
|
281
|
-
current.text = options.trim ? str.trim() : str;
|
|
284
|
+
if (parser.twig.current === null) return;
|
|
285
|
+
parser.twig.current.text = options.trim ? str.trim() : str;
|
|
282
286
|
});
|
|
283
287
|
|
|
284
288
|
parser.on("comment", function (str) {
|
|
285
|
-
if (current.hasOwnProperty('comment')) {
|
|
286
|
-
if (typeof current.comment === 'string') {
|
|
287
|
-
current.comment = [current.comment, str.trim()];
|
|
289
|
+
if (parser.twig.current.hasOwnProperty('comment')) {
|
|
290
|
+
if (typeof parser.twig.current.comment === 'string') {
|
|
291
|
+
parser.twig.current.comment = [parser.twig.current.comment, str.trim()];
|
|
288
292
|
} else {
|
|
289
|
-
current.comment.push(str.trim());
|
|
293
|
+
parser.twig.current.comment.push(str.trim());
|
|
290
294
|
}
|
|
291
295
|
} else {
|
|
292
|
-
Object.defineProperty(current, 'comment', {
|
|
296
|
+
Object.defineProperty(parser.twig.current, 'comment', {
|
|
293
297
|
value: str.trim(),
|
|
294
298
|
writable: true,
|
|
295
299
|
enumerable: true,
|
|
@@ -312,11 +316,12 @@ function createParser(handler, options = {}) {
|
|
|
312
316
|
|
|
313
317
|
/**
|
|
314
318
|
* Common Event hanlder for starting tag
|
|
319
|
+
* @param {Parser} parser - The main parser object
|
|
315
320
|
* @param {object} binds - Additional parameter object
|
|
316
321
|
* @param {object|string} node - Node or Node name
|
|
317
322
|
* @param {object} attrs - Node Attributes
|
|
318
323
|
*/
|
|
319
|
-
function onStart(binds, node, attrs) {
|
|
324
|
+
function onStart(parser, binds, node, attrs) {
|
|
320
325
|
|
|
321
326
|
const name = typeof node === 'string' ? node : node.name;
|
|
322
327
|
const handler = binds.handler;
|
|
@@ -329,17 +334,17 @@ function onStart(binds, node, attrs) {
|
|
|
329
334
|
attrNS[key] = attrs[key];
|
|
330
335
|
}
|
|
331
336
|
|
|
332
|
-
if (tree ===
|
|
333
|
-
tree = new Twig(name, current, options.xmlns ? attrNS : attrs);
|
|
337
|
+
if (parser.twig.tree === null) {
|
|
338
|
+
parser.twig.tree = new Twig(parser, name, parser.twig.current, options.xmlns ? attrNS : attrs);
|
|
334
339
|
} else {
|
|
335
|
-
if (current.isRoot && current.name === undefined) {
|
|
336
|
-
current.setRoot(name);
|
|
340
|
+
if (parser.twig.current.isRoot && parser.twig.current.name === undefined) {
|
|
341
|
+
parser.twig.current.setRoot(name);
|
|
337
342
|
if (attrs !== undefined) {
|
|
338
343
|
for (let [key, val] of Object.entries(options.xmlns ? attrNS : attrs))
|
|
339
|
-
current.attribute(key, val);
|
|
344
|
+
parser.twig.current.attribute(key, val);
|
|
340
345
|
}
|
|
341
346
|
} else {
|
|
342
|
-
let elt = new Twig(name, current, options.xmlns ? attrNS : attrs);
|
|
347
|
+
let elt = new Twig(parser, name, parser.twig.current, options.xmlns ? attrNS : attrs);
|
|
343
348
|
if (options.partial) {
|
|
344
349
|
for (let hndl of handler) {
|
|
345
350
|
if (typeof hndl.tag === 'string' && name === hndl.tag) {
|
|
@@ -351,7 +356,7 @@ function onStart(binds, node, attrs) {
|
|
|
351
356
|
} else if (hndl.tag instanceof RegExp && hndl.tag.test(name)) {
|
|
352
357
|
elt.pin();
|
|
353
358
|
break;
|
|
354
|
-
} else if (typeof hndl.tag === 'function' && hndl.tag(name, current ?? tree)) {
|
|
359
|
+
} else if (typeof hndl.tag === 'function' && hndl.tag(name, parser.twig.current ?? parser.twig.tree)) {
|
|
355
360
|
elt.pin();
|
|
356
361
|
break;
|
|
357
362
|
}
|
|
@@ -368,7 +373,7 @@ function onStart(binds, node, attrs) {
|
|
|
368
373
|
if (name.includes(':')) {
|
|
369
374
|
let prefix = name.split(':')[0];
|
|
370
375
|
if (namespaces[prefix] !== undefined) {
|
|
371
|
-
Object.defineProperty(current, 'namespace', {
|
|
376
|
+
Object.defineProperty(parser.twig.current, 'namespace', {
|
|
372
377
|
value: { local: prefix, uri: namespaces[prefix] },
|
|
373
378
|
writable: false,
|
|
374
379
|
enumerable: true
|
|
@@ -381,45 +386,46 @@ function onStart(binds, node, attrs) {
|
|
|
381
386
|
/**
|
|
382
387
|
* Common Event hanlder for closing tag. On closed elements it either calls the Handler function or emits the specified event.
|
|
383
388
|
* @param {TwigHandler|TwigHandler[]} handler - Object or array of element specification and function to handle elements
|
|
389
|
+
* @param {Parser} parser - The main parser object
|
|
384
390
|
* @param {external:sax|external:node-expat} parser - SAXStream or node-expat Stream object
|
|
385
391
|
* @param {ParserOptions} options - Object of optional options
|
|
386
392
|
* @param {string} name - Event handler parameter
|
|
387
393
|
*/
|
|
388
394
|
function onClose(handler, parser, options, name) {
|
|
389
|
-
current.close();
|
|
395
|
+
parser.twig.current.close();
|
|
390
396
|
let purge = true;
|
|
391
397
|
|
|
392
398
|
for (let hndl of Array.isArray(handler) ? handler : [handler]) {
|
|
393
399
|
if (hndl.tag instanceof AnyHandler) {
|
|
394
|
-
if (typeof hndl.function === 'function') hndl.function(current ?? tree, parser);
|
|
395
|
-
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
400
|
+
if (typeof hndl.function === 'function') hndl.function(parser.twig.current ?? parser.twig.tree, parser);
|
|
401
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, parser.twig.current ?? parser.twig.tree);
|
|
396
402
|
purge = false;
|
|
397
|
-
} else if (hndl.tag instanceof RootHandler && current.isRoot) {
|
|
398
|
-
if (typeof hndl.function === 'function') hndl.function(tree, parser);
|
|
399
|
-
if (typeof hndl.event === 'string') parser.emit(hndl.event, tree);
|
|
403
|
+
} else if (hndl.tag instanceof RootHandler && parser.twig.current.isRoot) {
|
|
404
|
+
if (typeof hndl.function === 'function') hndl.function(parser.twig.tree, parser);
|
|
405
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, parser.twig.tree);
|
|
400
406
|
purge = false;
|
|
401
407
|
} else if (Array.isArray(hndl.tag) && hndl.tag.includes(name)) {
|
|
402
|
-
if (typeof hndl.function === 'function') hndl.function(current ?? tree, parser);
|
|
403
|
-
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
408
|
+
if (typeof hndl.function === 'function') hndl.function(parser.twig.current ?? parser.twig.tree, parser);
|
|
409
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, parser.twig.current ?? parser.twig.tree);
|
|
404
410
|
purge = false;
|
|
405
411
|
} else if (typeof hndl.tag === 'string' && name === hndl.tag) {
|
|
406
|
-
if (typeof hndl.function === 'function') hndl.function(current ?? tree, parser);
|
|
407
|
-
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
412
|
+
if (typeof hndl.function === 'function') hndl.function(parser.twig.current ?? parser.twig.tree, parser);
|
|
413
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, parser.twig.current ?? parser.twig.tree);
|
|
408
414
|
purge = false;
|
|
409
415
|
} else if (hndl.tag instanceof RegExp && hndl.tag.test(name)) {
|
|
410
|
-
if (typeof hndl.function === 'function') hndl.function(current ?? tree, parser);
|
|
411
|
-
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
416
|
+
if (typeof hndl.function === 'function') hndl.function(parser.twig.current ?? parser.twig.tree, parser);
|
|
417
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, parser.twig.current ?? parser.twig.tree);
|
|
412
418
|
purge = false;
|
|
413
|
-
} else if (typeof hndl.tag === 'function' && hndl.tag(name, current ?? tree)) {
|
|
414
|
-
if (typeof hndl.function === 'function') hndl.function(current ?? tree, parser);
|
|
415
|
-
if (typeof hndl.event === 'string') parser.emit(hndl.event, current ?? tree);
|
|
419
|
+
} else if (typeof hndl.tag === 'function' && hndl.tag(name, parser.twig.current ?? parser.twig.tree)) {
|
|
420
|
+
if (typeof hndl.function === 'function') hndl.function(parser.twig.current ?? parser.twig.tree, parser);
|
|
421
|
+
if (typeof hndl.event === 'string') parser.emit(hndl.event, parser.twig.current ?? parser.twig.tree);
|
|
416
422
|
purge = false;
|
|
417
423
|
}
|
|
418
424
|
}
|
|
419
425
|
|
|
420
|
-
if (options.partial && purge && !current.pinned && !current.isRoot)
|
|
421
|
-
current.purge();
|
|
422
|
-
current = current.parent();
|
|
426
|
+
if (options.partial && purge && !parser.twig.current.pinned && !parser.twig.current.isRoot)
|
|
427
|
+
parser.twig.parser.twig.current.purge();
|
|
428
|
+
parser.twig.current = parser.twig.current.parent();
|
|
423
429
|
|
|
424
430
|
}
|
|
425
431
|
|
|
@@ -502,25 +508,26 @@ class Twig {
|
|
|
502
508
|
|
|
503
509
|
/**
|
|
504
510
|
* Create a new Twig object
|
|
511
|
+
* @param {Parser} parser - The main parser object
|
|
505
512
|
* @param {?string} name - The name of the XML element
|
|
506
513
|
* @param {Twig} [parent] - The parent object
|
|
507
514
|
* @param {object} [attributes] - Attribute object
|
|
508
515
|
* @param {string|number} [index] - Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last'
|
|
509
516
|
*/
|
|
510
|
-
constructor(name, parent, attributes, index) {
|
|
517
|
+
constructor(parser, name, parent, attributes, index) {
|
|
511
518
|
if (index === undefined)
|
|
512
|
-
current = this;
|
|
519
|
+
parser.twig.current = this;
|
|
513
520
|
|
|
514
521
|
if (name === null) {
|
|
515
522
|
// Root element not available yet
|
|
516
|
-
tree = this;
|
|
523
|
+
parser.twig.tree = this;
|
|
517
524
|
} else {
|
|
518
525
|
this.#name = name;
|
|
519
526
|
if (attributes !== undefined)
|
|
520
527
|
this.#attributes = attributes;
|
|
521
528
|
if (parent === undefined) {
|
|
522
529
|
// Root element
|
|
523
|
-
tree = this;
|
|
530
|
+
parser.twig.tree = this;
|
|
524
531
|
} else {
|
|
525
532
|
this.#parent = parent;
|
|
526
533
|
if (this.#parent.#pinned)
|
|
@@ -1216,8 +1223,8 @@ class Twig {
|
|
|
1216
1223
|
* @param {name|number} [position] - Position name 'first', 'last' or the position in the `children`
|
|
1217
1224
|
* @returns {Twig} - The appended element
|
|
1218
1225
|
*/
|
|
1219
|
-
addElement = function (name, text, attributes, position) {
|
|
1220
|
-
let twig = new Twig(name, this, attributes ?? {}, position ?? 'last');
|
|
1226
|
+
addElement = function (parser, name, text, attributes, position) {
|
|
1227
|
+
let twig = new Twig(parser, name, this, attributes ?? {}, position ?? 'last');
|
|
1221
1228
|
twig.#text = text ?? null;
|
|
1222
1229
|
twig.close();
|
|
1223
1230
|
return twig;
|