fast-xml-parser 5.0.9 → 5.2.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.
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "fast-xml-parser",
3
- "version": "5.0.9",
3
+ "version": "5.2.0",
4
4
  "description": "Validate XML, Parse XML, Build XML without C/C++ based libraries",
5
5
  "main": "./lib/fxp.cjs",
6
6
  "type": "module",
7
+ "sideEffects": false,
7
8
  "module": "./src/fxp.js",
8
9
  "types": "./src/fxp.d.ts",
9
10
  "exports": {
package/src/fxp.d.ts CHANGED
@@ -210,6 +210,12 @@ type X2jOptions = {
210
210
  * Defaults to `(tagName, jPath, attrs) => tagName`
211
211
  */
212
212
  updateTag?: (tagName: string, jPath: string, attrs: {[k: string]: string}) => string | boolean;
213
+
214
+ /**
215
+ * If true, adds a Symbol to all object nodes, accessible by {@link XMLParser.getMetaDataSymbol} with
216
+ * metadata about each the node in the XML file.
217
+ */
218
+ captureMetaData?: boolean;
213
219
  };
214
220
 
215
221
  type strnumOptions = {
@@ -407,6 +413,18 @@ export class XMLParser {
407
413
  * @param entityValue {string} Eg: '\r'
408
414
  */
409
415
  addEntity(entityIdentifier: string, entityValue: string): void;
416
+
417
+ /**
418
+ * Returns a Symbol that can be used to access the {@link XMLMetaData}
419
+ * property on a node.
420
+ *
421
+ * If Symbol is not available in the environment, an ordinary property is used
422
+ * and the name of the property is here returned.
423
+ *
424
+ * The XMLMetaData property is only present when {@link X2jOptions.captureMetaData}
425
+ * is true in the options.
426
+ */
427
+ static getMetaDataSymbol() : Symbol;
410
428
  }
411
429
 
412
430
  export class XMLValidator{
@@ -414,5 +432,14 @@ export class XMLValidator{
414
432
  }
415
433
  export class XMLBuilder {
416
434
  constructor(options?: XmlBuilderOptions);
417
- build(jObj: any): any;
435
+ build(jObj: any): string;
436
+ }
437
+
438
+ /**
439
+ * This object is available on nodes via the symbol {@link XMLParser.getMetaDataSymbol}
440
+ * when {@link X2jOptions.captureMetaData} is true.
441
+ */
442
+ export interface XMLMetaData {
443
+ /** The index, if available, of the character where the XML node began in the input stream. */
444
+ startIndex?: number;
418
445
  }
@@ -38,6 +38,7 @@ export const defaultOptions = {
38
38
  return tagName
39
39
  },
40
40
  // skipEmptyListItem: false
41
+ captureMetaData: false,
41
42
  };
42
43
 
43
44
  export const buildOptions = function(options) {
@@ -246,8 +246,7 @@ const parseXml = function(xmlData) {
246
246
  if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
247
247
  childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath, tagData.tagName);
248
248
  }
249
- this.addChild(currentNode, childNode, jPath)
250
-
249
+ this.addChild(currentNode, childNode, jPath, i);
251
250
  }
252
251
 
253
252
 
@@ -312,6 +311,7 @@ const parseXml = function(xmlData) {
312
311
  if(tagName !== xmlObj.tagname){
313
312
  jPath += jPath ? "." + tagName : tagName;
314
313
  }
314
+ const startIndex = i;
315
315
  if (this.isItStopNode(this.options.stopNodes, jPath, tagName)) {
316
316
  let tagContent = "";
317
317
  //self-closing tag
@@ -340,6 +340,7 @@ const parseXml = function(xmlData) {
340
340
  }
341
341
 
342
342
  const childNode = new xmlNode(tagName);
343
+
343
344
  if(tagName !== tagExp && attrExpPresent){
344
345
  childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
345
346
  }
@@ -350,7 +351,7 @@ const parseXml = function(xmlData) {
350
351
  jPath = jPath.substr(0, jPath.lastIndexOf("."));
351
352
  childNode.add(this.options.textNodeName, tagContent);
352
353
 
353
- this.addChild(currentNode, childNode, jPath)
354
+ this.addChild(currentNode, childNode, jPath, startIndex);
354
355
  }else{
355
356
  //selfClosing tag
356
357
  if(tagExp.length > 0 && tagExp.lastIndexOf("/") === tagExp.length - 1){
@@ -370,7 +371,7 @@ const parseXml = function(xmlData) {
370
371
  if(tagName !== tagExp && attrExpPresent){
371
372
  childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
372
373
  }
373
- this.addChild(currentNode, childNode, jPath)
374
+ this.addChild(currentNode, childNode, jPath, startIndex);
374
375
  jPath = jPath.substr(0, jPath.lastIndexOf("."));
375
376
  }
376
377
  //opening tag
@@ -381,7 +382,7 @@ const parseXml = function(xmlData) {
381
382
  if(tagName !== tagExp && attrExpPresent){
382
383
  childNode[":@"] = this.buildAttributesMap(tagExp, jPath, tagName);
383
384
  }
384
- this.addChild(currentNode, childNode, jPath)
385
+ this.addChild(currentNode, childNode, jPath, startIndex);
385
386
  currentNode = childNode;
386
387
  }
387
388
  textData = "";
@@ -395,14 +396,16 @@ const parseXml = function(xmlData) {
395
396
  return xmlObj.child;
396
397
  }
397
398
 
398
- function addChild(currentNode, childNode, jPath){
399
+ function addChild(currentNode, childNode, jPath, startIndex){
400
+ // unset startIndex if not requested
401
+ if (!this.options.captureMetaData) startIndex = undefined;
399
402
  const result = this.options.updateTag(childNode.tagname, jPath, childNode[":@"])
400
403
  if(result === false){
401
- }else if(typeof result === "string"){
404
+ } else if(typeof result === "string"){
402
405
  childNode.tagname = result
403
- currentNode.addChild(childNode);
406
+ currentNode.addChild(childNode, startIndex);
404
407
  }else{
405
- currentNode.addChild(childNode);
408
+ currentNode.addChild(childNode, startIndex);
406
409
  }
407
410
  }
408
411
 
@@ -2,6 +2,7 @@ import { buildOptions} from './OptionsBuilder.js';
2
2
  import OrderedObjParser from './OrderedObjParser.js';
3
3
  import prettify from './node2json.js';
4
4
  import {validate} from "../validator.js";
5
+ import XmlNode from './xmlNode.js';
5
6
 
6
7
  export default class XMLParser{
7
8
 
@@ -53,4 +54,18 @@ export default class XMLParser{
53
54
  this.externalEntities[key] = value;
54
55
  }
55
56
  }
56
- }
57
+
58
+ /**
59
+ * Returns a Symbol that can be used to access the metadata
60
+ * property on a node.
61
+ *
62
+ * If Symbol is not available in the environment, an ordinary property is used
63
+ * and the name of the property is here returned.
64
+ *
65
+ * The XMLMetaData property is only present when `captureMetaData`
66
+ * is true in the options.
67
+ */
68
+ static getMetaDataSymbol() {
69
+ return XmlNode.getMetaDataSymbol();
70
+ }
71
+ }
@@ -1,5 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ import XmlNode from './xmlNode.js';
4
+
5
+ const METADATA_SYMBOL = XmlNode.getMetaDataSymbol();
6
+
3
7
  /**
4
8
  *
5
9
  * @param {array} node
@@ -36,6 +40,9 @@ function compress(arr, options, jPath){
36
40
 
37
41
  let val = compress(tagObj[property], options, newJpath);
38
42
  const isLeaf = isLeafTag(val, options);
43
+ if (tagObj[METADATA_SYMBOL] !== undefined) {
44
+ val[METADATA_SYMBOL] = tagObj[METADATA_SYMBOL]; // copy over metadata
45
+ }
39
46
 
40
47
  if(tagObj[":@"]){
41
48
  assignAttributes( val, tagObj[":@"], newJpath, options);
@@ -1,5 +1,13 @@
1
1
  'use strict';
2
2
 
3
+ let METADATA_SYMBOL;
4
+
5
+ if (typeof Symbol !== "function") {
6
+ METADATA_SYMBOL = "@@xmlMetadata";
7
+ } else {
8
+ METADATA_SYMBOL = Symbol("XML Node Metadata");
9
+ }
10
+
3
11
  export default class XmlNode{
4
12
  constructor(tagname) {
5
13
  this.tagname = tagname;
@@ -11,12 +19,22 @@ export default class XmlNode{
11
19
  if(key === "__proto__") key = "#__proto__";
12
20
  this.child.push( {[key]: val });
13
21
  }
14
- addChild(node) {
22
+ addChild(node, startIndex) {
15
23
  if(node.tagname === "__proto__") node.tagname = "#__proto__";
16
24
  if(node[":@"] && Object.keys(node[":@"]).length > 0){
17
25
  this.child.push( { [node.tagname]: node.child, [":@"]: node[":@"] });
18
26
  }else{
19
27
  this.child.push( { [node.tagname]: node.child });
20
28
  }
29
+ // if requested, add the startIndex
30
+ if (startIndex !== undefined) {
31
+ // Note: for now we just overwrite the metadata. If we had more complex metadata,
32
+ // we might need to do an object append here: metadata = { ...metadata, startIndex }
33
+ this.child[this.child.length - 1][METADATA_SYMBOL] = { startIndex };
34
+ }
35
+ }
36
+ /** symbol used for metadata */
37
+ static getMetaDataSymbol() {
38
+ return METADATA_SYMBOL;
21
39
  }
22
40
  }