xml-twig 1.7.12 → 1.9.0

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.
Files changed (4) hide show
  1. package/README.md +18 -18
  2. package/doc/twig.md +180 -114
  3. package/package.json +6 -7
  4. package/twig.js +62 -42
package/README.md CHANGED
@@ -4,27 +4,29 @@ Node module for processing huge XML documents in tree mode
4
4
  Inspired by Perl module [XML::Twig](https://metacpan.org/pod/XML::Twig)
5
5
 
6
6
 
7
- ## When should I use this, motivation of this module
8
- When you need to read a XML file, then you have two principles:
7
+ ## When to Use This Module and Its Motivation
8
+ When you need to read an XML file, there are two primary approaches:
9
9
 
10
- * The **Document Object Model (DOM)** style. These parser read the entire XML document into memory. Usually they provide easy methods to navigate in the document tree or make modifications.
10
+ 1. **The Document Object Model (DOM) Style**
11
11
 
12
- DOM parsers are perfect for rather small files, for example configuration files or (X-)HTML pages. However, for bigger XML files you may run into memory limits. When you parse a XML-File as DOM, then the footprint in RAM can be easily 10-20 times the size of the raw XML-String. If the XML-File is greater than [Buffer.constants.MAX_STRING_LENGTH](https://nodejs.org/api/buffer.html#bufferconstantsmax_string_length) (typically 512 MiB), then a DOM parser may throw error "Cannot create a string longer than 0x1fffffe8 characters".
12
+ These parsers read the entire XML document into memory. They usually provide convenient methods for navigating the document tree or making modifications. DOM parsers are ideal for smaller files, such as configuration files or (X-)HTML pages. However, for larger XML files, you may run into memory limitations. Parsing an XML file using the DOM method can cause memory usage to increase by 10-20 times the size of the raw XML string. If the XML file exceeds the size of [Buffer.constants.MAX_STRING_LENGTH](https://nodejs.org/api/buffer.html#bufferconstantsmax_string_length) (typically 512 MB), the DOM parser may throw an error: "Cannot create a string longer than 0x1fffffe8 characters."
13
13
 
14
- * The **stream** or **event** based parsers. These parser read the XML file "line by line". The biggest advantage of such a parser is, there is no limit in the size of the XML file. You can read XML files having a size of many terabytes, because you read always just a single node.
14
+ 1. **Stream or Event-Based Parsers**
15
15
 
16
- The backside: By default you cannot navigate in the document tree, you know only the current node.
16
+ These parsers read the XML file "line by line" or node by node. The main advantage of this approach is that there is no size limitation for the XML file. You can read XML files of several terabytes because only a single node is read into memory at a time.
17
+
18
+ The downside is that, by default, you cannot navigate the document tree - you can only access the current node.
17
19
 
18
- This module tries to combine both principles. The XML document can be read in chunks and within a chunk you have all the nice features and functions you know from a DOM based parser.
20
+ This module aims to combine both approaches. It reads the XML document in chunks, and within each chunk, you can utilize the familiar features and functions of a DOM-based parser.
19
21
 
20
22
  ## Dependencies
21
- XML documents are read either with [sax](https://www.npmjs.com/package/sax) or [node-expat](https://www.npmjs.com/package/node-expat) parser. More parser may be added in future releases. By default the `sax` parser is used. However, I clearly recommend using the `node-expat` parser. All other parsers I tested, are not compliant to XML standards.
23
+ XML documents are parsed using either the [sax](https://www.npmjs.com/package/sax) or [node-expat](https://www.npmjs.com/package/node-expat) parser. parsers. Additional parsers may be added in future releases. By default, the `sax` parser is used. However, I strongly recommend using the `node-expat` parser, as other parsers I tested are not fully compliant with XML standards.
22
24
 
23
- **NOTE: The `node-expat` module is not automatically installed with this module. Install the parser by yourself, if you like to use it**
25
+ **NOTE: The `node-expat` module is not automatically installed with this module. If you wish to use it, you must install it manually.**
24
26
 
25
27
  ## Installation
26
28
 
27
- Install module like any other node module and optionally `node-expat`:
29
+ To install the module, use the standard Node.js installation process. Optionally, you can also install the `node-expat` parser:
28
30
  ```bash
29
31
  npm install xml-twig
30
32
 
@@ -32,7 +34,7 @@ npm install xml-twig
32
34
  npm install node-expat
33
35
 
34
36
  ```
35
- In my tests I parsed a 900 MB big XML file, the `node-expat` is faster than `sax` (node-expat: around 2:30 Minutes, sax: around 3:40 Minutes). However, you may run into problems when you try to install the `node-expat` parser. That's the reason why `node-expat` parser is not installed automatically.
37
+ In my tests, I parsed a 900 MB XML file, and the `node-expat`t parser was faster than `sax` (`node-expat`: around 2:30 minutes, `sax`: around 3:40 minutes). However, you may encounter issues when installing the `node-expat` parser, which is why it's not installed automatically.
36
38
 
37
39
  ## How to use it
38
40
 
@@ -72,10 +74,9 @@ API Documentation: see [Twig](./doc/twig.md)
72
74
 
73
75
  - **Read XML Document in chucks**
74
76
 
75
- The key feature of this module is to read and process XML files in chunks. You need to create handler functions for elements you like to process.<br>
76
- The most notable difference to other parsers is the `purge()` and `purgeUpTo()` method. The parser reads the element and you decide how long you need to keep it in the memory.
77
- In many cases you will purge it immediately after you have used it but in some cases you may keep the element for later use. The parser knows the element position in the XML-Tree.
77
+ The key feature of this module is the ability to read and process XML files in chunks. You need to define handler functions for the elements you want to process.
78
78
 
79
+ A major difference compared to other parsers is the `purge()` and `purgeUpTo()` methods. The parser reads an element, and you decide how long to keep it in memory. In many cases, you will purge the element immediately after processing it, but in some situations, you might want to retain it for later use. The parser keeps track of the element’s position within the XML tree.
79
80
 
80
81
  ```js
81
82
  function bookHandler(elt, parserObj) {
@@ -146,10 +147,6 @@ API Documentation: see [Twig](./doc/twig.md)
146
147
 
147
148
  ```
148
149
 
149
- Be aware if you run methods like `elt.followingSibling()`, `elt.descendant()`, `elt.next()`, etc. on the current element. Such calls return empty result, because following element are not yet read from the XML file. You must navigate to an earlier element, e.g.<br>
150
- `elt.root().children()[0].followingSibling()`
151
-
152
-
153
150
  - **Read only parts from XML Document**
154
151
 
155
152
  If you like to read only certain elements, use option `partial: true`. The `root` element is always read.
@@ -294,6 +291,9 @@ Here are some examples the get attribute and values:
294
291
 
295
292
  `.writer(indented|xw)` - **XMLWriter**: Returns a [XMLWriter](https://www.npmjs.com/package/xml-writer) object you can use to print the currently loaded XML tree.<br>Instead of providing an indented parameter (`true`, `false` or indent character) you can also provide an `XMLWriter` object which adds more flexibility.
296
293
 
294
+ Be aware if you call methods like `elt.followingSibling()`, `elt.descendant()`, `elt.next()`, etc. on the current element, they will return empty results. This is because the following elements have not yet been read from the XML file. To navigate to an earlier element, you can use a method like:<br>
295
+ `elt.root().children()[0].followingSibling()`
296
+
297
297
  **condition** Parameter
298
298
 
299
299
  You can specify condition on above methods. You can filter elements by following conditions:
package/doc/twig.md CHANGED
@@ -33,7 +33,7 @@
33
33
  ## Functions
34
34
 
35
35
  <dl>
36
- <dt><a href="#createParser">createParser(handler, [options])</a> ⇒ <code><a href="#Parser">Parser</a></code></dt>
36
+ <dt><a href="#createParser">createParser(handler, options)</a> ⇒ <code><a href="#Parser">Parser</a></code></dt>
37
37
  <dd><p>Create a new Twig parser</p>
38
38
  </dd>
39
39
  <dt><a href="#onStart">onStart(parser, binds, node, attrs)</a></dt>
@@ -120,7 +120,7 @@ You can specify a <code>function</code> or a <code>event</code> name</p>
120
120
 
121
121
  * [Twig](#Twig)
122
122
  * [new Twig()](#new_Twig_new)
123
- * [new Twig(parser, name, [parent], [attributes], [index])](#new_Twig_new)
123
+ * [new Twig(parser, name, parent, attributes, index)](#new_Twig_new)
124
124
  * [.attributes](#Twig+attributes) : <code>object</code> ℗
125
125
  * [.text](#Twig+text) : <code>string</code> \| <code>number</code> ℗
126
126
  * [.name](#Twig+name) : <code>string</code> ℗
@@ -156,6 +156,8 @@ You can specify a <code>function</code> or a <code>event</code> name</p>
156
156
  * [.parent](#Twig+parent) ⇒ [<code>Twig</code>](#Twig)
157
157
  * [.self](#Twig+self) ⇒ [<code>Twig</code>](#Twig)
158
158
  * [.children](#Twig+children) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
159
+ * [.firstChild](#Twig+firstChild) ⇒ [<code>Twig</code>](#Twig)
160
+ * [.lastChild](#Twig+lastChild) ⇒ [<code>Twig</code>](#Twig)
159
161
  * [.next](#Twig+next) ⇒ [<code>Twig</code>](#Twig)
160
162
  * [.previous](#Twig+previous) ⇒ [<code>Twig</code>](#Twig)
161
163
  * [.first](#Twig+first) ⇒ [<code>Twig</code>](#Twig)
@@ -176,8 +178,8 @@ You can specify a <code>function</code> or a <code>event</code> name</p>
176
178
  * [.addElement](#Twig+addElement) ⇒ [<code>Twig</code>](#Twig)
177
179
  * [.delete](#Twig+delete)
178
180
  * [.setRoot(name)](#Twig+setRoot) ℗
179
- * [.filterElements(elements, [condition])](#Twig+filterElements) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
180
- * [.testElement(element, [condition])](#Twig+testElement) ⇒ <code>boolean</code>
181
+ * [.filterElements(elements, condition)](#Twig+filterElements) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
182
+ * [.testElement(element, condition)](#Twig+testElement) ⇒ <code>boolean</code>
181
183
 
182
184
  <a name="new_Twig_new"></a>
183
185
 
@@ -186,7 +188,7 @@ Generic class modeling a XML Node
186
188
 
187
189
  <a name="new_Twig_new"></a>
188
190
 
189
- ### new Twig(parser, name, [parent], [attributes], [index])
191
+ ### new Twig(parser, name, parent, attributes, index)
190
192
  Create a new Twig object
191
193
 
192
194
 
@@ -194,9 +196,9 @@ Create a new Twig object
194
196
  | --- | --- | --- |
195
197
  | parser | [<code>Parser</code>](#Parser) | The main parser object |
196
198
  | name | <code>string</code> | The name of the XML element |
197
- | [parent] | [<code>Twig</code>](#Twig) | The parent object |
198
- | [attributes] | <code>object</code> | Attribute object |
199
- | [index] | <code>string</code> \| <code>number</code> | Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last' |
199
+ | parent | [<code>Twig</code>](#Twig) | The parent object |
200
+ | attributes | <code>object</code> | Attribute object |
201
+ | index | <code>string</code> \| <code>number</code> | Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last' |
200
202
 
201
203
  <a name="Twig+attributes"></a>
202
204
 
@@ -249,13 +251,14 @@ Purges the current, typically used after element has been processed.<br>The root
249
251
  <a name="Twig+purgeUpTo"></a>
250
252
 
251
253
  ### twig.purgeUpTo
252
- Purges up to the elt element. This allows you to keep part of the tree in memory when you purge.<br>
254
+ Purges up to the elt element. This allows you to keep part of the tree in memory when you purge.<br>
255
+ The `elt` object is not purged. If you like to purge including `elt`, use `.purgeUpTo(elt.previous())`
253
256
 
254
257
  **Kind**: instance property of [<code>Twig</code>](#Twig)
255
258
 
256
259
  | Param | Type | Description |
257
260
  | --- | --- | --- |
258
- | [elt] | [<code>Twig</code>](#Twig) | Up to this element the tree will be purged. If `undefined` then the current element is purged (i.e. `purge()`) |
261
+ | elt | [<code>Twig</code>](#Twig) | Up to this element the tree will be purged. If `undefined` then the current element is purged (i.e. `purge()`) |
259
262
 
260
263
  <a name="Twig+escapeEntity"></a>
261
264
 
@@ -271,7 +274,8 @@ Escapes special XML characters. According W3C specification these are only `&, <
271
274
  <a name="Twig+isEmpty"></a>
272
275
 
273
276
  ### twig.isEmpty ⇒ <code>boolean</code>
274
- Returns `true` if the element is empty, otherwise `false`.
277
+ Returns `true` if the element is empty, otherwise `false`.
278
+ An empty element has no text nor any child elements, however empty elements can have attributes.
275
279
 
276
280
  **Kind**: instance property of [<code>Twig</code>](#Twig)
277
281
  **Returns**: <code>boolean</code> - true if empty element
@@ -306,7 +310,8 @@ The position in `#children` array. For root object 0
306
310
  <a name="Twig+path"></a>
307
311
 
308
312
  ### twig.path ⇒ <code>string</code>
309
- The X-Path position of the element
313
+ The X-Path position of the element
314
+ NOTE: Applies only to currently loaded elements.
310
315
 
311
316
  **Kind**: instance property of [<code>Twig</code>](#Twig)
312
317
  **Returns**: <code>string</code> - X-Path
@@ -406,14 +411,15 @@ Creates xml-writer from current element
406
411
  <a name="Twig+attr"></a>
407
412
 
408
413
  ### twig.attr ⇒ <code>string</code> \| <code>number</code> \| <code>object</code>
409
- Returns attribute value or `null` if not found.<br>
414
+ Returns attribute value or `null` if not found.<br>
415
+ If more than one matches the condition, then it returns object as [attribute()](#attribute)
410
416
 
411
417
  **Kind**: instance property of [<code>Twig</code>](#Twig)
412
418
  **Returns**: <code>string</code> \| <code>number</code> \| <code>object</code> - - The value of the attribute or `null` if the does not exist
413
419
 
414
420
  | Param | Type | Description |
415
421
  | --- | --- | --- |
416
- | [condition] | [<code>AttributeCondition</code>](#AttributeCondition) | Optional condition to select attribute |
422
+ | condition | [<code>AttributeCondition</code>](#AttributeCondition) | Optional condition to select attribute |
417
423
 
418
424
  <a name="Twig+attributes"></a>
419
425
 
@@ -444,12 +450,15 @@ Retrieve or update XML attribute. For update, the condition must be a string, i.
444
450
 
445
451
  | Param | Type | Description |
446
452
  | --- | --- | --- |
447
- | [condition] | [<code>AttributeCondition</code>](#AttributeCondition) | Optional condition to select attributes |
448
- | [value] | <code>string</code> \| <code>number</code> \| <code>bigint</code> \| <code>boolean</code> | New value of the attribute.<br>If `undefined` then existing attributes is returned. |
453
+ | condition | [<code>AttributeCondition</code>](#AttributeCondition) | Optional condition to select attributes |
454
+ | value | <code>string</code> \| <code>number</code> \| <code>bigint</code> \| <code>boolean</code> | New value of the attribute.<br>If `undefined` then existing attributes is returned. |
449
455
 
450
456
  **Example**
451
457
  ```js
452
- attribute((name, val) => { return name === 'age' && val > 50})
458
+ attribute((name, val) => { return name === 'age' && val > 50})
459
+ attribute((name) => { return ['firstName', 'lastName'].includes(name) })
460
+ attribute('firstName')
461
+ attribute(/name/i)
453
462
  ```
454
463
  <a name="Twig+deleteAttribute"></a>
455
464
 
@@ -490,7 +499,29 @@ All children, optionally matching `condition` of the current element or empty ar
490
499
 
491
500
  | Param | Type | Description |
492
501
  | --- | --- | --- |
493
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
502
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
503
+
504
+ <a name="Twig+firstChild"></a>
505
+
506
+ ### twig.firstChild ⇒ [<code>Twig</code>](#Twig)
507
+ The first matching child, optionally matching `condition` of the current element or null
508
+
509
+ **Kind**: instance property of [<code>Twig</code>](#Twig)
510
+
511
+ | Param | Type | Description |
512
+ | --- | --- | --- |
513
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
514
+
515
+ <a name="Twig+lastChild"></a>
516
+
517
+ ### twig.lastChild ⇒ [<code>Twig</code>](#Twig)
518
+ The last matching child, optionally matching `condition` of the current element or null
519
+
520
+ **Kind**: instance property of [<code>Twig</code>](#Twig)
521
+
522
+ | Param | Type | Description |
523
+ | --- | --- | --- |
524
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
494
525
 
495
526
  <a name="Twig+next"></a>
496
527
 
@@ -503,7 +534,7 @@ Returns the next matching element.
503
534
 
504
535
  | Param | Type | Description |
505
536
  | --- | --- | --- |
506
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
537
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
507
538
 
508
539
  <a name="Twig+previous"></a>
509
540
 
@@ -516,7 +547,7 @@ Returns the previous matching element.
516
547
 
517
548
  | Param | Type | Description |
518
549
  | --- | --- | --- |
519
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
550
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
520
551
 
521
552
  <a name="Twig+first"></a>
522
553
 
@@ -528,7 +559,7 @@ Returns the first matching element. This is usually the root element
528
559
 
529
560
  | Param | Type | Description |
530
561
  | --- | --- | --- |
531
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
562
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
532
563
 
533
564
  <a name="Twig+last"></a>
534
565
 
@@ -540,7 +571,7 @@ Returns the last matching element.
540
571
 
541
572
  | Param | Type | Description |
542
573
  | --- | --- | --- |
543
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
574
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
544
575
 
545
576
  <a name="Twig+isFirstChild"></a>
546
577
 
@@ -566,7 +597,7 @@ Returns descendants (children, grandchildren, etc.) of the current element
566
597
 
567
598
  | Param | Type | Description |
568
599
  | --- | --- | --- |
569
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
600
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
570
601
 
571
602
  <a name="Twig+descendantOrSelf"></a>
572
603
 
@@ -578,7 +609,7 @@ Returns descendants (children, grandchildren, etc.) of the current element and t
578
609
 
579
610
  | Param | Type | Description |
580
611
  | --- | --- | --- |
581
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
612
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
582
613
 
583
614
  <a name="Twig+ancestor"></a>
584
615
 
@@ -590,7 +621,7 @@ Returns ancestors (parent, grandparent, etc.) of the current element
590
621
 
591
622
  | Param | Type | Description |
592
623
  | --- | --- | --- |
593
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
624
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
594
625
 
595
626
  <a name="Twig+ancestorOrSelf"></a>
596
627
 
@@ -602,7 +633,7 @@ Returns ancestors (parent, grandparent, etc.) of the current element and the cu
602
633
 
603
634
  | Param | Type | Description |
604
635
  | --- | --- | --- |
605
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
636
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
606
637
 
607
638
  <a name="Twig+sibling"></a>
608
639
 
@@ -614,7 +645,7 @@ Returns all sibling element of the current element
614
645
 
615
646
  | Param | Type | Description |
616
647
  | --- | --- | --- |
617
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
648
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
618
649
 
619
650
  <a name="Twig+siblingOrSelf"></a>
620
651
 
@@ -626,7 +657,7 @@ Returns all sibling element of the current element and the current element itsel
626
657
 
627
658
  | Param | Type | Description |
628
659
  | --- | --- | --- |
629
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
660
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
630
661
 
631
662
  <a name="Twig+followingSibling"></a>
632
663
 
@@ -638,7 +669,7 @@ Returns all following sibling element of the current element
638
669
 
639
670
  | Param | Type | Description |
640
671
  | --- | --- | --- |
641
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
672
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
642
673
 
643
674
  <a name="Twig+precedingSibling"></a>
644
675
 
@@ -650,7 +681,7 @@ Returns all preceding sibling element of the current element
650
681
 
651
682
  | Param | Type | Description |
652
683
  | --- | --- | --- |
653
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
684
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
654
685
 
655
686
  <a name="Twig+nextSibling"></a>
656
687
 
@@ -662,7 +693,7 @@ Returns next sibling element of the current element
662
693
 
663
694
  | Param | Type | Description |
664
695
  | --- | --- | --- |
665
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
696
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
666
697
 
667
698
  <a name="Twig+prevSibling"></a>
668
699
 
@@ -674,7 +705,7 @@ Returns previous sibling element of the current element
674
705
 
675
706
  | Param | Type | Description |
676
707
  | --- | --- | --- |
677
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
708
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
678
709
 
679
710
  <a name="Twig+find"></a>
680
711
 
@@ -699,9 +730,9 @@ Add a new element in the current element
699
730
  | Param | Type | Description |
700
731
  | --- | --- | --- |
701
732
  | name | <code>string</code> | The tag name |
702
- | [text] | <code>string</code> | Text of the element |
703
- | [attributes] | <code>object</code> | Element attributes |
704
- | [position] | <code>name</code> \| <code>number</code> | Position name 'first', 'last' or the position in the `children` |
733
+ | text | <code>string</code> | Text of the element |
734
+ | attributes | <code>object</code> | Element attributes |
735
+ | position | <code>name</code> \| <code>number</code> | Position name 'first', 'last' or the position in the `children` |
705
736
 
706
737
  <a name="Twig+delete"></a>
707
738
 
@@ -712,7 +743,8 @@ Deletes the current element from tree, same as `purge()`. The root object cannot
712
743
  <a name="Twig+setRoot"></a>
713
744
 
714
745
  ### twig.setRoot(name) ℗
715
- Sets the name of root element. In some cases the root is created before the XML-Root element is available<br>
746
+ Sets the name of root element. In some cases the root is created before the XML-Root element is available<br>
747
+ Used internally!
716
748
 
717
749
  **Kind**: instance method of [<code>Twig</code>](#Twig)
718
750
  **Access**: private
@@ -723,7 +755,7 @@ Sets the name of root element. In some cases the root is created before the XML-
723
755
 
724
756
  <a name="Twig+filterElements"></a>
725
757
 
726
- ### twig.filterElements(elements, [condition]) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
758
+ ### twig.filterElements(elements, condition) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
727
759
  Common function to filter Twig elements from array
728
760
 
729
761
  **Kind**: instance method of [<code>Twig</code>](#Twig)
@@ -732,11 +764,11 @@ Common function to filter Twig elements from array
732
764
  | Param | Type | Description |
733
765
  | --- | --- | --- |
734
766
  | elements | [<code>Twig</code>](#Twig) \| [<code>Array.&lt;Twig&gt;</code>](#Twig) | Array of elements you like to filter or a single element |
735
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | The filter condition |
767
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | The filter condition |
736
768
 
737
769
  <a name="Twig+testElement"></a>
738
770
 
739
- ### twig.testElement(element, [condition]) ⇒ <code>boolean</code>
771
+ ### twig.testElement(element, condition) ⇒ <code>boolean</code>
740
772
  Common function to filter Twig element
741
773
 
742
774
  **Kind**: instance method of [<code>Twig</code>](#Twig)
@@ -745,7 +777,7 @@ Common function to filter Twig element
745
777
  | Param | Type | Description |
746
778
  | --- | --- | --- |
747
779
  | element | [<code>Twig</code>](#Twig) | Element you like to filter |
748
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | The filter condition |
780
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | The filter condition |
749
781
 
750
782
  <a name="Twig"></a>
751
783
 
@@ -754,7 +786,7 @@ Common function to filter Twig element
754
786
 
755
787
  * [Twig](#Twig)
756
788
  * [new Twig()](#new_Twig_new)
757
- * [new Twig(parser, name, [parent], [attributes], [index])](#new_Twig_new)
789
+ * [new Twig(parser, name, parent, attributes, index)](#new_Twig_new)
758
790
  * [.attributes](#Twig+attributes) : <code>object</code> ℗
759
791
  * [.text](#Twig+text) : <code>string</code> \| <code>number</code> ℗
760
792
  * [.name](#Twig+name) : <code>string</code> ℗
@@ -790,6 +822,8 @@ Common function to filter Twig element
790
822
  * [.parent](#Twig+parent) ⇒ [<code>Twig</code>](#Twig)
791
823
  * [.self](#Twig+self) ⇒ [<code>Twig</code>](#Twig)
792
824
  * [.children](#Twig+children) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
825
+ * [.firstChild](#Twig+firstChild) ⇒ [<code>Twig</code>](#Twig)
826
+ * [.lastChild](#Twig+lastChild) ⇒ [<code>Twig</code>](#Twig)
793
827
  * [.next](#Twig+next) ⇒ [<code>Twig</code>](#Twig)
794
828
  * [.previous](#Twig+previous) ⇒ [<code>Twig</code>](#Twig)
795
829
  * [.first](#Twig+first) ⇒ [<code>Twig</code>](#Twig)
@@ -810,8 +844,8 @@ Common function to filter Twig element
810
844
  * [.addElement](#Twig+addElement) ⇒ [<code>Twig</code>](#Twig)
811
845
  * [.delete](#Twig+delete)
812
846
  * [.setRoot(name)](#Twig+setRoot) ℗
813
- * [.filterElements(elements, [condition])](#Twig+filterElements) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
814
- * [.testElement(element, [condition])](#Twig+testElement) ⇒ <code>boolean</code>
847
+ * [.filterElements(elements, condition)](#Twig+filterElements) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
848
+ * [.testElement(element, condition)](#Twig+testElement) ⇒ <code>boolean</code>
815
849
 
816
850
  <a name="new_Twig_new"></a>
817
851
 
@@ -820,7 +854,7 @@ Generic class modeling a XML Node
820
854
 
821
855
  <a name="new_Twig_new"></a>
822
856
 
823
- ### new Twig(parser, name, [parent], [attributes], [index])
857
+ ### new Twig(parser, name, parent, attributes, index)
824
858
  Create a new Twig object
825
859
 
826
860
 
@@ -828,9 +862,9 @@ Create a new Twig object
828
862
  | --- | --- | --- |
829
863
  | parser | [<code>Parser</code>](#Parser) | The main parser object |
830
864
  | name | <code>string</code> | The name of the XML element |
831
- | [parent] | [<code>Twig</code>](#Twig) | The parent object |
832
- | [attributes] | <code>object</code> | Attribute object |
833
- | [index] | <code>string</code> \| <code>number</code> | Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last' |
865
+ | parent | [<code>Twig</code>](#Twig) | The parent object |
866
+ | attributes | <code>object</code> | Attribute object |
867
+ | index | <code>string</code> \| <code>number</code> | Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last' |
834
868
 
835
869
  <a name="Twig+attributes"></a>
836
870
 
@@ -883,13 +917,14 @@ Purges the current, typically used after element has been processed.<br>The root
883
917
  <a name="Twig+purgeUpTo"></a>
884
918
 
885
919
  ### twig.purgeUpTo
886
- Purges up to the elt element. This allows you to keep part of the tree in memory when you purge.<br>
920
+ Purges up to the elt element. This allows you to keep part of the tree in memory when you purge.<br>
921
+ The `elt` object is not purged. If you like to purge including `elt`, use `.purgeUpTo(elt.previous())`
887
922
 
888
923
  **Kind**: instance property of [<code>Twig</code>](#Twig)
889
924
 
890
925
  | Param | Type | Description |
891
926
  | --- | --- | --- |
892
- | [elt] | [<code>Twig</code>](#Twig) | Up to this element the tree will be purged. If `undefined` then the current element is purged (i.e. `purge()`) |
927
+ | elt | [<code>Twig</code>](#Twig) | Up to this element the tree will be purged. If `undefined` then the current element is purged (i.e. `purge()`) |
893
928
 
894
929
  <a name="Twig+escapeEntity"></a>
895
930
 
@@ -905,7 +940,8 @@ Escapes special XML characters. According W3C specification these are only `&, <
905
940
  <a name="Twig+isEmpty"></a>
906
941
 
907
942
  ### twig.isEmpty ⇒ <code>boolean</code>
908
- Returns `true` if the element is empty, otherwise `false`.
943
+ Returns `true` if the element is empty, otherwise `false`.
944
+ An empty element has no text nor any child elements, however empty elements can have attributes.
909
945
 
910
946
  **Kind**: instance property of [<code>Twig</code>](#Twig)
911
947
  **Returns**: <code>boolean</code> - true if empty element
@@ -940,7 +976,8 @@ The position in `#children` array. For root object 0
940
976
  <a name="Twig+path"></a>
941
977
 
942
978
  ### twig.path ⇒ <code>string</code>
943
- The X-Path position of the element
979
+ The X-Path position of the element
980
+ NOTE: Applies only to currently loaded elements.
944
981
 
945
982
  **Kind**: instance property of [<code>Twig</code>](#Twig)
946
983
  **Returns**: <code>string</code> - X-Path
@@ -1040,14 +1077,15 @@ Creates xml-writer from current element
1040
1077
  <a name="Twig+attr"></a>
1041
1078
 
1042
1079
  ### twig.attr ⇒ <code>string</code> \| <code>number</code> \| <code>object</code>
1043
- Returns attribute value or `null` if not found.<br>
1080
+ Returns attribute value or `null` if not found.<br>
1081
+ If more than one matches the condition, then it returns object as [attribute()](#attribute)
1044
1082
 
1045
1083
  **Kind**: instance property of [<code>Twig</code>](#Twig)
1046
1084
  **Returns**: <code>string</code> \| <code>number</code> \| <code>object</code> - - The value of the attribute or `null` if the does not exist
1047
1085
 
1048
1086
  | Param | Type | Description |
1049
1087
  | --- | --- | --- |
1050
- | [condition] | [<code>AttributeCondition</code>](#AttributeCondition) | Optional condition to select attribute |
1088
+ | condition | [<code>AttributeCondition</code>](#AttributeCondition) | Optional condition to select attribute |
1051
1089
 
1052
1090
  <a name="Twig+attributes"></a>
1053
1091
 
@@ -1078,12 +1116,15 @@ Retrieve or update XML attribute. For update, the condition must be a string, i.
1078
1116
 
1079
1117
  | Param | Type | Description |
1080
1118
  | --- | --- | --- |
1081
- | [condition] | [<code>AttributeCondition</code>](#AttributeCondition) | Optional condition to select attributes |
1082
- | [value] | <code>string</code> \| <code>number</code> \| <code>bigint</code> \| <code>boolean</code> | New value of the attribute.<br>If `undefined` then existing attributes is returned. |
1119
+ | condition | [<code>AttributeCondition</code>](#AttributeCondition) | Optional condition to select attributes |
1120
+ | value | <code>string</code> \| <code>number</code> \| <code>bigint</code> \| <code>boolean</code> | New value of the attribute.<br>If `undefined` then existing attributes is returned. |
1083
1121
 
1084
1122
  **Example**
1085
1123
  ```js
1086
- attribute((name, val) => { return name === 'age' && val > 50})
1124
+ attribute((name, val) => { return name === 'age' && val > 50})
1125
+ attribute((name) => { return ['firstName', 'lastName'].includes(name) })
1126
+ attribute('firstName')
1127
+ attribute(/name/i)
1087
1128
  ```
1088
1129
  <a name="Twig+deleteAttribute"></a>
1089
1130
 
@@ -1124,7 +1165,29 @@ All children, optionally matching `condition` of the current element or empty ar
1124
1165
 
1125
1166
  | Param | Type | Description |
1126
1167
  | --- | --- | --- |
1127
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1168
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1169
+
1170
+ <a name="Twig+firstChild"></a>
1171
+
1172
+ ### twig.firstChild ⇒ [<code>Twig</code>](#Twig)
1173
+ The first matching child, optionally matching `condition` of the current element or null
1174
+
1175
+ **Kind**: instance property of [<code>Twig</code>](#Twig)
1176
+
1177
+ | Param | Type | Description |
1178
+ | --- | --- | --- |
1179
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1180
+
1181
+ <a name="Twig+lastChild"></a>
1182
+
1183
+ ### twig.lastChild ⇒ [<code>Twig</code>](#Twig)
1184
+ The last matching child, optionally matching `condition` of the current element or null
1185
+
1186
+ **Kind**: instance property of [<code>Twig</code>](#Twig)
1187
+
1188
+ | Param | Type | Description |
1189
+ | --- | --- | --- |
1190
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1128
1191
 
1129
1192
  <a name="Twig+next"></a>
1130
1193
 
@@ -1137,7 +1200,7 @@ Returns the next matching element.
1137
1200
 
1138
1201
  | Param | Type | Description |
1139
1202
  | --- | --- | --- |
1140
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1203
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1141
1204
 
1142
1205
  <a name="Twig+previous"></a>
1143
1206
 
@@ -1150,7 +1213,7 @@ Returns the previous matching element.
1150
1213
 
1151
1214
  | Param | Type | Description |
1152
1215
  | --- | --- | --- |
1153
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1216
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1154
1217
 
1155
1218
  <a name="Twig+first"></a>
1156
1219
 
@@ -1162,7 +1225,7 @@ Returns the first matching element. This is usually the root element
1162
1225
 
1163
1226
  | Param | Type | Description |
1164
1227
  | --- | --- | --- |
1165
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1228
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1166
1229
 
1167
1230
  <a name="Twig+last"></a>
1168
1231
 
@@ -1174,7 +1237,7 @@ Returns the last matching element.
1174
1237
 
1175
1238
  | Param | Type | Description |
1176
1239
  | --- | --- | --- |
1177
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1240
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1178
1241
 
1179
1242
  <a name="Twig+isFirstChild"></a>
1180
1243
 
@@ -1200,7 +1263,7 @@ Returns descendants (children, grandchildren, etc.) of the current element
1200
1263
 
1201
1264
  | Param | Type | Description |
1202
1265
  | --- | --- | --- |
1203
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1266
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1204
1267
 
1205
1268
  <a name="Twig+descendantOrSelf"></a>
1206
1269
 
@@ -1212,7 +1275,7 @@ Returns descendants (children, grandchildren, etc.) of the current element and t
1212
1275
 
1213
1276
  | Param | Type | Description |
1214
1277
  | --- | --- | --- |
1215
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1278
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1216
1279
 
1217
1280
  <a name="Twig+ancestor"></a>
1218
1281
 
@@ -1224,7 +1287,7 @@ Returns ancestors (parent, grandparent, etc.) of the current element
1224
1287
 
1225
1288
  | Param | Type | Description |
1226
1289
  | --- | --- | --- |
1227
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1290
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1228
1291
 
1229
1292
  <a name="Twig+ancestorOrSelf"></a>
1230
1293
 
@@ -1236,7 +1299,7 @@ Returns ancestors (parent, grandparent, etc.) of the current element and the cu
1236
1299
 
1237
1300
  | Param | Type | Description |
1238
1301
  | --- | --- | --- |
1239
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1302
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1240
1303
 
1241
1304
  <a name="Twig+sibling"></a>
1242
1305
 
@@ -1248,7 +1311,7 @@ Returns all sibling element of the current element
1248
1311
 
1249
1312
  | Param | Type | Description |
1250
1313
  | --- | --- | --- |
1251
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1314
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1252
1315
 
1253
1316
  <a name="Twig+siblingOrSelf"></a>
1254
1317
 
@@ -1260,7 +1323,7 @@ Returns all sibling element of the current element and the current element itsel
1260
1323
 
1261
1324
  | Param | Type | Description |
1262
1325
  | --- | --- | --- |
1263
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1326
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1264
1327
 
1265
1328
  <a name="Twig+followingSibling"></a>
1266
1329
 
@@ -1272,7 +1335,7 @@ Returns all following sibling element of the current element
1272
1335
 
1273
1336
  | Param | Type | Description |
1274
1337
  | --- | --- | --- |
1275
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1338
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1276
1339
 
1277
1340
  <a name="Twig+precedingSibling"></a>
1278
1341
 
@@ -1284,7 +1347,7 @@ Returns all preceding sibling element of the current element
1284
1347
 
1285
1348
  | Param | Type | Description |
1286
1349
  | --- | --- | --- |
1287
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1350
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1288
1351
 
1289
1352
  <a name="Twig+nextSibling"></a>
1290
1353
 
@@ -1296,7 +1359,7 @@ Returns next sibling element of the current element
1296
1359
 
1297
1360
  | Param | Type | Description |
1298
1361
  | --- | --- | --- |
1299
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1362
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1300
1363
 
1301
1364
  <a name="Twig+prevSibling"></a>
1302
1365
 
@@ -1308,7 +1371,7 @@ Returns previous sibling element of the current element
1308
1371
 
1309
1372
  | Param | Type | Description |
1310
1373
  | --- | --- | --- |
1311
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1374
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | Optional condition |
1312
1375
 
1313
1376
  <a name="Twig+find"></a>
1314
1377
 
@@ -1333,9 +1396,9 @@ Add a new element in the current element
1333
1396
  | Param | Type | Description |
1334
1397
  | --- | --- | --- |
1335
1398
  | name | <code>string</code> | The tag name |
1336
- | [text] | <code>string</code> | Text of the element |
1337
- | [attributes] | <code>object</code> | Element attributes |
1338
- | [position] | <code>name</code> \| <code>number</code> | Position name 'first', 'last' or the position in the `children` |
1399
+ | text | <code>string</code> | Text of the element |
1400
+ | attributes | <code>object</code> | Element attributes |
1401
+ | position | <code>name</code> \| <code>number</code> | Position name 'first', 'last' or the position in the `children` |
1339
1402
 
1340
1403
  <a name="Twig+delete"></a>
1341
1404
 
@@ -1346,7 +1409,8 @@ Deletes the current element from tree, same as `purge()`. The root object cannot
1346
1409
  <a name="Twig+setRoot"></a>
1347
1410
 
1348
1411
  ### twig.setRoot(name) ℗
1349
- Sets the name of root element. In some cases the root is created before the XML-Root element is available<br>
1412
+ Sets the name of root element. In some cases the root is created before the XML-Root element is available<br>
1413
+ Used internally!
1350
1414
 
1351
1415
  **Kind**: instance method of [<code>Twig</code>](#Twig)
1352
1416
  **Access**: private
@@ -1357,7 +1421,7 @@ Sets the name of root element. In some cases the root is created before the XML-
1357
1421
 
1358
1422
  <a name="Twig+filterElements"></a>
1359
1423
 
1360
- ### twig.filterElements(elements, [condition]) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
1424
+ ### twig.filterElements(elements, condition) ⇒ [<code>Array.&lt;Twig&gt;</code>](#Twig)
1361
1425
  Common function to filter Twig elements from array
1362
1426
 
1363
1427
  **Kind**: instance method of [<code>Twig</code>](#Twig)
@@ -1366,11 +1430,11 @@ Common function to filter Twig elements from array
1366
1430
  | Param | Type | Description |
1367
1431
  | --- | --- | --- |
1368
1432
  | elements | [<code>Twig</code>](#Twig) \| [<code>Array.&lt;Twig&gt;</code>](#Twig) | Array of elements you like to filter or a single element |
1369
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | The filter condition |
1433
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | The filter condition |
1370
1434
 
1371
1435
  <a name="Twig+testElement"></a>
1372
1436
 
1373
- ### twig.testElement(element, [condition]) ⇒ <code>boolean</code>
1437
+ ### twig.testElement(element, condition) ⇒ <code>boolean</code>
1374
1438
  Common function to filter Twig element
1375
1439
 
1376
1440
  **Kind**: instance method of [<code>Twig</code>](#Twig)
@@ -1379,7 +1443,7 @@ Common function to filter Twig element
1379
1443
  | Param | Type | Description |
1380
1444
  | --- | --- | --- |
1381
1445
  | element | [<code>Twig</code>](#Twig) | Element you like to filter |
1382
- | [condition] | [<code>ElementCondition</code>](#ElementCondition) | The filter condition |
1446
+ | condition | [<code>ElementCondition</code>](#ElementCondition) | The filter condition |
1383
1447
 
1384
1448
  <a name="NotImplementedYet"></a>
1385
1449
 
@@ -1446,7 +1510,7 @@ Generic error for unsupported condition
1446
1510
 
1447
1511
  ## SAX
1448
1512
  **Kind**: global constant
1449
- **Version:**: 1.7.11
1513
+ **Version:**: 1.9.0
1450
1514
  **Author:**: Wernfried Domscheit
1451
1515
  **Copyright:**: Copyright (c) 2025 Wernfried Domscheit. All rights reserved.
1452
1516
  **Website:**: https://www.npmjs.com/package/xml-twig
@@ -1460,7 +1524,7 @@ Generic error for unsupported condition
1460
1524
  **Kind**: global constant
1461
1525
  <a name="createParser"></a>
1462
1526
 
1463
- ## createParser(handler, [options]) ⇒ [<code>Parser</code>](#Parser)
1527
+ ## createParser(handler, options) ⇒ [<code>Parser</code>](#Parser)
1464
1528
  Create a new Twig parser
1465
1529
 
1466
1530
  **Kind**: global function
@@ -1473,7 +1537,7 @@ Create a new Twig parser
1473
1537
  | Param | Type | Description |
1474
1538
  | --- | --- | --- |
1475
1539
  | handler | [<code>TwigHandler</code>](#TwigHandler) \| [<code>Array.&lt;TwigHandler&gt;</code>](#TwigHandler) | Object or array of element specification and function to handle elements |
1476
- | [options] | [<code>ParserOptions</code>](#ParserOptions) | Object of optional options |
1540
+ | options | [<code>ParserOptions</code>](#ParserOptions) | Object of optional options |
1477
1541
 
1478
1542
  <a name="onStart"></a>
1479
1543
 
@@ -1515,12 +1579,12 @@ Optional settings for the Twig parser
1515
1579
 
1516
1580
  | Name | Type | Description |
1517
1581
  | --- | --- | --- |
1518
- | [method] | <code>&#x27;sax&#x27;</code> \| <code>&#x27;expat&#x27;</code> | The underlying parser. Either `'sax'`, `'expat'`. |
1519
- | [xmlns] | <code>boolean</code> | If `true`, then namespaces are accessible by `namespace` property. |
1520
- | [trim] | <code>boolean</code> | If `true`, then turn any whitespace into a single space. Text and comments are trimmed. |
1521
- | [resumeAfterError] | <code>boolean</code> | If `true` then parser continues reading after an error. Otherwise it throws exception. |
1522
- | [partial] | <code>boolean</code> | If `true` then unhandled elements are purged. |
1523
- | [file] | <code>string</code> | Optional. The name of file to be parsed. Just used for information and logging purpose. |
1582
+ | method | <code>&#x27;sax&#x27;</code> \| <code>&#x27;expat&#x27;</code> | The underlying parser. Either `'sax'`, `'expat'`. |
1583
+ | xmlns | <code>boolean</code> | If `true`, then namespaces are accessible by `namespace` property. |
1584
+ | trim | <code>boolean</code> | If `true`, then turn any whitespace into a single space. Text and comments are trimmed. |
1585
+ | resumeAfterError | <code>boolean</code> | If `true` then parser continues reading after an error. Otherwise it throws exception. |
1586
+ | partial | <code>boolean</code> | If `true` then unhandled elements are purged. |
1587
+ | file | <code>string</code> | Optional. The name of file to be parsed. Just used for information and logging purpose. |
1524
1588
 
1525
1589
  **Example**
1526
1590
  ```js
@@ -1529,7 +1593,9 @@ Optional settings for the Twig parser
1529
1593
  <a name="TwigHandler"></a>
1530
1594
 
1531
1595
  ## TwigHandler
1532
- Reference to handler functions for Twig objects.<br>
1596
+ Reference to handler functions for Twig objects.<br>
1597
+ Element can be specified as string, Regular Expression, custom function, `Twig.Root` or `Twig.Any`<br>
1598
+ You can specify a `function` or a `event` name
1533
1599
 
1534
1600
  **Kind**: global typedef
1535
1601
  **Properties**
@@ -1537,13 +1603,19 @@ Reference to handler functions for Twig objects.<br>
1537
1603
  | Name | Type | Description |
1538
1604
  | --- | --- | --- |
1539
1605
  | tag | [<code>HandlerCondition</code>](#HandlerCondition) | Element specification |
1540
- | [function] | [<code>HandlerFunction</code>](#HandlerFunction) | Definition of handler function, either anonymous or explicit function |
1541
- | [event] | <code>string</code> | Type of the event to be emitted |
1606
+ | function | [<code>HandlerFunction</code>](#HandlerFunction) | Definition of handler function, either anonymous or explicit function |
1607
+ | event | <code>string</code> | Type of the event to be emitted |
1542
1608
 
1543
1609
  <a name="HandlerCondition"></a>
1544
1610
 
1545
1611
  ## HandlerCondition : <code>string</code> \| <code>Array.&lt;string&gt;</code> \| <code>RegExp</code> \| [<code>HandlerConditionFilter</code>](#HandlerConditionFilter) \| [<code>Root</code>](#Root) \| [<code>Any</code>](#Any)
1546
- Condition to specify when handler shall be called<br>
1547
- If `string` then the element name must be equal to the string
1548
- If `string[]` then the element name must be included in string array
1549
- If `RegExp` then the element name must match the Regular Expression
1550
- If [HandlerConditionFilter](#HandlerConditionFilter) then function must return `true`
1551
- Use `Twig.Root` to call the handler on root element, i.e. when the end of document is reached
1552
- Use `Twig.Any` to call the handler on every element
1612
+ Condition to specify when handler shall be called<br>
1613
+ - If `string` then the element name must be equal to the string
1614
+ - If `string[]` then the element name must be included in string array
1615
+ - If `RegExp` then the element name must match the Regular Expression
1616
+ - If [HandlerConditionFilter](#HandlerConditionFilter) then function must return `true`
1617
+ - Use `Twig.Root` to call the handler on root element, i.e. when the end of document is reached
1618
+ - Use `Twig.Any` to call the handler on every element
1553
1619
 
1554
1620
  **Kind**: global typedef
1555
1621
  <a name="HandlerFunction"></a>
@@ -1572,7 +1644,12 @@ Custom filter function to specify when handler shall be called
1572
1644
  <a name="ElementCondition"></a>
1573
1645
 
1574
1646
  ## ElementCondition : <code>string</code> \| <code>RegExp</code> \| [<code>ElementConditionFilter</code>](#ElementConditionFilter) \| [<code>Twig</code>](#Twig) \| <code>undefined</code>
1575
- Optional condition to get elements<br>
1576
- If `undefined`, then all elements are returned.<br>
1577
- If `string` then the element name must be equal to the string
1578
- If `RegExp` then the element name must match the Regular Expression
1579
- If [ElementConditionFilter](#ElementConditionFilter) then function must return `true`
1580
- Use [Twig](#Twig) object to find a specific element
1647
+ Optional condition to get elements<br>
1648
+ - If `undefined`, then all elements are returned.<br>
1649
+ - If `string` then the element name must be equal to the string
1650
+ - If `RegExp` then the element name must match the Regular Expression
1651
+ - If [ElementConditionFilter](#ElementConditionFilter) then function must return `true`
1652
+ - Use [Twig](#Twig) object to find a specific element
1581
1653
 
1582
1654
  **Kind**: global typedef
1583
1655
  <a name="ElementConditionFilter"></a>
@@ -1597,16 +1674,20 @@ Custom filter function to select desired elements
1597
1674
 
1598
1675
  | Name | Type | Description |
1599
1676
  | --- | --- | --- |
1600
- | [currentLine] | <code>number</code> | The currently processed line in the XML-File. |
1601
- | [currentColumn] | <code>number</code> | The currently processed column in the XML-File. |
1602
- | [file] | <code>string</code> | The name of file to be parsed. Just used for information and logging purpose. |
1603
- | [twig] | <code>object</code> | Object with XML tree and current XML element |
1604
- | [method] | <code>string</code> | The underlying parser. Either `'sax'`, `'expat'`. |
1677
+ | currentLine | <code>number</code> | The currently processed line in the XML-File. |
1678
+ | currentColumn | <code>number</code> | The currently processed column in the XML-File. |
1679
+ | file | <code>string</code> | The name of file to be parsed. Just used for information and logging purpose. |
1680
+ | twig | <code>object</code> | Object with XML tree and current XML element |
1681
+ | method | <code>string</code> | The underlying parser. Either `'sax'`, `'expat'`. |
1605
1682
 
1606
1683
  <a name="AttributeCondition"></a>
1607
1684
 
1608
1685
  ## AttributeCondition : <code>string</code> \| <code>RegExp</code> \| [<code>AttributeConditionFilter</code>](#AttributeConditionFilter)
1609
- Optional condition to get attributes<br>
1610
- If `undefined`, then all attributes are returned.<br>
1611
- If `string` then the attribute name must be equal to the string
1612
- If `RegExp` then the attribute name must match the Regular Expression
1613
- If [AttributeConditionFilter](#AttributeConditionFilter) then the attribute must filter function
1686
+ Optional condition to get attributes<br>
1687
+ - If `undefined`, then all attributes are returned.<br>
1688
+ - If `string` then the attribute name must be equal to the string
1689
+ - If `RegExp` then the attribute name must match the Regular Expression
1690
+ - If [AttributeConditionFilter](#AttributeConditionFilter) then the attribute must filter function
1614
1691
 
1615
1692
  **Kind**: global typedef
1616
1693
  <a name="AttributeConditionFilter"></a>
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  },
6
6
  "name": "xml-twig",
7
7
  "description": "Node module for processing huge XML documents in tree mode",
8
- "version": "1.7.12",
8
+ "version": "1.9.0",
9
9
  "main": "twig.js",
10
10
  "directories": {
11
11
  "doc": "doc"
@@ -15,16 +15,15 @@
15
15
  "doc/*.md"
16
16
  ],
17
17
  "devDependencies": {
18
- "jsdoc-to-markdown": "^9.0.0",
19
- "luxon": "^3.5.0",
18
+ "jsdoc-to-markdown": "^9.1.1",
19
+ "luxon": "^3.6.1",
20
20
  "node-expat": "^2.4.1"
21
21
  },
22
22
  "scripts": {
23
23
  "test": "node demo.js",
24
- "preversion": "jsdoc2md --private twig.js > doc/twig.md",
25
- "postversion": "sed -i -e \"s/@version: .*/@version: %npm_package_version%/\" twig.js",
26
- "prepack": "unix2dos twig.js doc/twig.md",
27
- "prepare": "git commit -a -m \"Updated doc and version\""
24
+ "postversion": "sed -bi -e \"s/@version: .*/@version: %npm_package_version%/\" twig.js",
25
+ "prepare": "jsdoc2md --EOL win32 --private twig.js > doc/twig.md",
26
+ "postpack": "git commit -a -m \"Updated doc and version\""
28
27
  },
29
28
  "repository": {
30
29
  "type": "git",
package/twig.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @version: 1.7.12
2
+ * @version: 1.9.0
3
3
  * @author: Wernfried Domscheit
4
4
  * @copyright: Copyright (c) 2025 Wernfried Domscheit. All rights reserved.
5
5
  * @website: https://www.npmjs.com/package/xml-twig
@@ -62,12 +62,12 @@ const Any = new AnyHandler();
62
62
  /**
63
63
  * Optional settings for the Twig parser
64
64
  * @typedef ParserOptions
65
- * @property {'sax' | 'expat'} [method] - The underlying parser. Either `'sax'`, `'expat'`.
66
- * @property {boolean} [xmlns] - If `true`, then namespaces are accessible by `namespace` property.
67
- * @property {boolean} [trim] - If `true`, then turn any whitespace into a single space. Text and comments are trimmed.
68
- * @property {boolean} [resumeAfterError] - If `true` then parser continues reading after an error. Otherwise it throws exception.
69
- * @property {boolean} [partial] - If `true` then unhandled elements are purged.
70
- * @property {string} [file] - Optional. The name of file to be parsed. Just used for information and logging purpose.
65
+ * @property {'sax' | 'expat'} method - The underlying parser. Either `'sax'`, `'expat'`.
66
+ * @property {boolean} xmlns - If `true`, then namespaces are accessible by `namespace` property.
67
+ * @property {boolean} trim - If `true`, then turn any whitespace into a single space. Text and comments are trimmed.
68
+ * @property {boolean} resumeAfterError - If `true` then parser continues reading after an error. Otherwise it throws exception.
69
+ * @property {boolean} partial - If `true` then unhandled elements are purged.
70
+ * @property {string} [file - Optional. The name of file to be parsed. Just used for information and logging purpose.
71
71
  * @example { method: 'expat', xmlns: true }
72
72
  * @default { method: 'sax', xmlns: false, trim: true, resumeAfterError: false, partial: false }
73
73
  */
@@ -78,8 +78,8 @@ const Any = new AnyHandler();
78
78
  * You can specify a `function` or a `event` name
79
79
  * @typedef TwigHandler
80
80
  * @property {HandlerCondition} tag - Element specification
81
- * @property {HandlerFunction} [function] - Definition of handler function, either anonymous or explicit function
82
- * @property {string} [event] - Type of the event to be emitted
81
+ * @property {HandlerFunction} function - Definition of handler function, either anonymous or explicit function
82
+ * @property {string} event - Type of the event to be emitted
83
83
  */
84
84
 
85
85
  /**
@@ -126,18 +126,18 @@ const Any = new AnyHandler();
126
126
 
127
127
  /**
128
128
  * @typedef Parser
129
- * @property {number} [currentLine] - The currently processed line in the XML-File.
130
- * @property {number} [currentColumn] - The currently processed column in the XML-File.
131
- * @property {string} [file] - The name of file to be parsed. Just used for information and logging purpose.
132
- * @property {object} [twig] - Object with XML tree and current XML element
133
- * @property {string} [method] - The underlying parser. Either `'sax'`, `'expat'`.
129
+ * @property {number} currentLine - The currently processed line in the XML-File.
130
+ * @property {number} currentColumn - The currently processed column in the XML-File.
131
+ * @property {string} file - The name of file to be parsed. Just used for information and logging purpose.
132
+ * @property {object} twig - Object with XML tree and current XML element
133
+ * @property {string} method - The underlying parser. Either `'sax'`, `'expat'`.
134
134
  * @returns {external:sax|external:node-expat} The parser Object
135
135
  */
136
136
 
137
137
  /**
138
138
  * Create a new Twig parser
139
139
  * @param {TwigHandler|TwigHandler[]} handler - Object or array of element specification and function to handle elements
140
- * @param {ParserOptions} [options] - Object of optional options
140
+ * @param {ParserOptions} options - Object of optional options
141
141
  * @throws {UnsupportedParser} - For an unsupported parser. Currently `expat` and `sax` (default) are supported.
142
142
  * @returns {Parser} The parser Object
143
143
  */
@@ -517,9 +517,9 @@ class Twig {
517
517
  * Create a new Twig object
518
518
  * @param {Parser} parser - The main parser object
519
519
  * @param {?string} name - The name of the XML element
520
- * @param {Twig} [parent] - The parent object
521
- * @param {object} [attributes] - Attribute object
522
- * @param {string|number} [index] - Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last'
520
+ * @param {Twig} parent - The parent object
521
+ * @param {object} attributes - Attribute object
522
+ * @param {string|number} index - Position name 'first', 'last' or the position in the current `children` array.<br>Defaults to 'last'
523
523
  */
524
524
  constructor(parser, name, parent, attributes, index) {
525
525
  if (index === undefined)
@@ -564,7 +564,7 @@ class Twig {
564
564
  /**
565
565
  * Purges up to the elt element. This allows you to keep part of the tree in memory when you purge.<br>
566
566
  * The `elt` object is not purged. If you like to purge including `elt`, use `.purgeUpTo(elt.previous())`
567
- * @param {Twig} [elt] - Up to this element the tree will be purged.
567
+ * @param {Twig} elt - Up to this element the tree will be purged.
568
568
  * If `undefined` then the current element is purged (i.e. `purge()`)
569
569
  */
570
570
  purgeUpTo = function (elt) {
@@ -797,7 +797,7 @@ class Twig {
797
797
  /**
798
798
  * Returns attribute value or `null` if not found.<br>
799
799
  * If more than one matches the condition, then it returns object as [attribute()](#attribute)
800
- * @param {AttributeCondition} [condition] - Optional condition to select attribute
800
+ * @param {AttributeCondition} condition - Optional condition to select attribute
801
801
  * @returns {?string|number|object} - The value of the attribute or `null` if the does not exist
802
802
  */
803
803
  attr = function (condition) {
@@ -827,8 +827,8 @@ class Twig {
827
827
 
828
828
  /**
829
829
  * Retrieve or update XML attribute. For update, the condition must be a string, i.e. must match to one attribute only.
830
- * @param {AttributeCondition} [condition] - Optional condition to select attributes
831
- * @param {string|number|bigint|boolean} [value] - New value of the attribute.<br>If `undefined` then existing attributes is returned.
830
+ * @param {AttributeCondition} condition - Optional condition to select attributes
831
+ * @param {string|number|bigint|boolean} value - New value of the attribute.<br>If `undefined` then existing attributes is returned.
832
832
  * @returns {object} Attributes or `null` if no matching attribute found
833
833
  * @example attribute((name, val) => { return name === 'age' && val > 50})
834
834
  * attribute((name) => { return ['firstName', 'lastName'].includes(name) })
@@ -906,7 +906,7 @@ class Twig {
906
906
  /**
907
907
  * Common function to filter Twig elements from array
908
908
  * @param {Twig|Twig[]} elements - Array of elements you like to filter or a single element
909
- * @param {ElementCondition} [condition] - The filter condition
909
+ * @param {ElementCondition} condition - The filter condition
910
910
  * @returns {Twig[]} List of matching elements or empty array
911
911
  */
912
912
  filterElements(elements, condition) {
@@ -931,7 +931,7 @@ class Twig {
931
931
  /**
932
932
  * Common function to filter Twig element
933
933
  * @param {Twig} element - Element you like to filter
934
- * @param {ElementCondition} [condition] - The filter condition
934
+ * @param {ElementCondition} condition - The filter condition
935
935
  * @returns {boolean} `true` if the condition matches
936
936
  */
937
937
  testElement(element, condition) {
@@ -951,16 +951,36 @@ class Twig {
951
951
 
952
952
  /**
953
953
  * All children, optionally matching `condition` of the current element or empty array
954
- * @param {ElementCondition} [condition] - Optional condition
954
+ * @param {ElementCondition} condition - Optional condition
955
955
  * @returns {Twig[]}
956
956
  */
957
957
  children = function (condition) {
958
958
  return this.filterElements(this.#children, condition);
959
959
  };
960
960
 
961
+ /**
962
+ * The first matching child, optionally matching `condition` of the current element or null
963
+ * @param {ElementCondition} condition - Optional condition
964
+ * @returns {?Twig}
965
+ */
966
+ firstChild = function (condition) {
967
+ let _children = this.children(condition);
968
+ return _children.length == 0 ? null : _children[0];
969
+ };
970
+
971
+ /**
972
+ * The last matching child, optionally matching `condition` of the current element or null
973
+ * @param {ElementCondition} condition - Optional condition
974
+ * @returns {?Twig}
975
+ */
976
+ lastChild = function (condition) {
977
+ let _children = this.children(condition);
978
+ return _children.length == 0 ? null : _children[_children.length - 1];
979
+ };
980
+
961
981
  /**
962
982
  * Returns the next matching element.
963
- * @param {ElementCondition} [condition] - Optional condition
983
+ * @param {ElementCondition} condition - Optional condition
964
984
  * @returns {?Twig} - The next element
965
985
  * @see https://www.w3.org/TR/xpath-datamodel-31/#document-order
966
986
  */
@@ -986,7 +1006,7 @@ class Twig {
986
1006
 
987
1007
  /**
988
1008
  * Returns the previous matching element.
989
- * @param {ElementCondition} [condition] - Optional condition
1009
+ * @param {ElementCondition} condition - Optional condition
990
1010
  * @returns {?Twig} - The previous element
991
1011
  * @see https://www.w3.org/TR/xpath-datamodel-31/#document-order
992
1012
  */
@@ -1007,7 +1027,7 @@ class Twig {
1007
1027
 
1008
1028
  /**
1009
1029
  * Returns the first matching element. This is usually the root element
1010
- * @param {ElementCondition} [condition] - Optional condition
1030
+ * @param {ElementCondition} condition - Optional condition
1011
1031
  * @returns {?Twig} - The first element
1012
1032
  */
1013
1033
  first = function (condition) {
@@ -1018,7 +1038,7 @@ class Twig {
1018
1038
 
1019
1039
  /**
1020
1040
  * Returns the last matching element.
1021
- * @param {ElementCondition} [condition] - Optional condition
1041
+ * @param {ElementCondition} condition - Optional condition
1022
1042
  * @returns {?Twig} - The last element
1023
1043
  */
1024
1044
  last = function (condition) {
@@ -1061,7 +1081,7 @@ class Twig {
1061
1081
 
1062
1082
  /**
1063
1083
  * Returns descendants (children, grandchildren, etc.) of the current element
1064
- * @param {ElementCondition} [condition] - Optional condition
1084
+ * @param {ElementCondition} condition - Optional condition
1065
1085
  * @returns {Twig[]} - Array of descendants or empty array
1066
1086
  */
1067
1087
  descendant = function (condition) {
@@ -1075,7 +1095,7 @@ class Twig {
1075
1095
 
1076
1096
  /**
1077
1097
  * Returns descendants (children, grandchildren, etc.) of the current element and the current element itself
1078
- * @param {ElementCondition} [condition] - Optional condition
1098
+ * @param {ElementCondition} condition - Optional condition
1079
1099
  * @returns {Twig[]} - Array of descendants or empty array
1080
1100
  */
1081
1101
  descendantOrSelf = function (condition) {
@@ -1089,7 +1109,7 @@ class Twig {
1089
1109
 
1090
1110
  /**
1091
1111
  * Returns ancestors (parent, grandparent, etc.) of the current element
1092
- * @param {ElementCondition} [condition] - Optional condition
1112
+ * @param {ElementCondition} condition - Optional condition
1093
1113
  * @returns {Twig[]} - Array of ancestors or empty array
1094
1114
  */
1095
1115
  ancestor = function (condition) {
@@ -1107,7 +1127,7 @@ class Twig {
1107
1127
 
1108
1128
  /**
1109
1129
  * Returns ancestors (parent, grandparent, etc.) of the current element and the current element itself
1110
- * @param {ElementCondition} [condition] - Optional condition
1130
+ * @param {ElementCondition} condition - Optional condition
1111
1131
  * @returns {Twig[]} - Array of ancestors or empty array
1112
1132
  */
1113
1133
  ancestorOrSelf = function (condition) {
@@ -1125,7 +1145,7 @@ class Twig {
1125
1145
 
1126
1146
  /**
1127
1147
  * Returns all sibling element of the current element
1128
- * @param {ElementCondition} [condition] - Optional condition
1148
+ * @param {ElementCondition} condition - Optional condition
1129
1149
  * @returns {Twig[]} - Array of sibling or empty array
1130
1150
  */
1131
1151
  sibling = function (condition) {
@@ -1138,7 +1158,7 @@ class Twig {
1138
1158
 
1139
1159
  /**
1140
1160
  * Returns all sibling element of the current element and the current element itself
1141
- * @param {ElementCondition} [condition] - Optional condition
1161
+ * @param {ElementCondition} condition - Optional condition
1142
1162
  * @returns {Twig[]} - Array of sibling or empty array
1143
1163
  */
1144
1164
  siblingOrSelf = function (condition) {
@@ -1151,7 +1171,7 @@ class Twig {
1151
1171
 
1152
1172
  /**
1153
1173
  * Returns all following sibling element of the current element
1154
- * @param {ElementCondition} [condition] - Optional condition
1174
+ * @param {ElementCondition} condition - Optional condition
1155
1175
  * @returns {Twig[]} - Array of sibling or empty array
1156
1176
  */
1157
1177
  followingSibling = function (condition) {
@@ -1164,7 +1184,7 @@ class Twig {
1164
1184
 
1165
1185
  /**
1166
1186
  * Returns all preceding sibling element of the current element
1167
- * @param {ElementCondition} [condition] - Optional condition
1187
+ * @param {ElementCondition} condition - Optional condition
1168
1188
  * @returns {Twig[]} - Array of sibling or empty array
1169
1189
  */
1170
1190
  precedingSibling = function (condition) {
@@ -1177,7 +1197,7 @@ class Twig {
1177
1197
 
1178
1198
  /**
1179
1199
  * Returns next sibling element of the current element
1180
- * @param {ElementCondition} [condition] - Optional condition
1200
+ * @param {ElementCondition} condition - Optional condition
1181
1201
  * @returns {?Twig} - The next sibling or `null`
1182
1202
  */
1183
1203
  nextSibling = function (condition) {
@@ -1192,7 +1212,7 @@ class Twig {
1192
1212
 
1193
1213
  /**
1194
1214
  * Returns previous sibling element of the current element
1195
- * @param {ElementCondition} [condition] - Optional condition
1215
+ * @param {ElementCondition} condition - Optional condition
1196
1216
  * @returns {?Twig} - The previous sibling or `null`
1197
1217
  */
1198
1218
  prevSibling = function (condition) {
@@ -1225,9 +1245,9 @@ class Twig {
1225
1245
  /**
1226
1246
  * Add a new element in the current element
1227
1247
  * @param {string} name - The tag name
1228
- * @param {?string} [text] - Text of the element
1229
- * @param {?object} [attributes] - Element attributes
1230
- * @param {name|number} [position] - Position name 'first', 'last' or the position in the `children`
1248
+ * @param {?string} text - Text of the element
1249
+ * @param {?object} attributes - Element attributes
1250
+ * @param {name|number} position - Position name 'first', 'last' or the position in the `children`
1231
1251
  * @returns {Twig} - The appended element
1232
1252
  */
1233
1253
  addElement = function (parser, name, text, attributes, position) {