fast-xml-parser 5.7.2 → 5.8.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,6 +1,6 @@
1
1
  {
2
2
  "name": "fast-xml-parser",
3
- "version": "5.7.2",
3
+ "version": "5.8.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",
@@ -23,7 +23,6 @@
23
23
  "test": "c8 --reporter=lcov --reporter=text jasmine spec/*spec.js",
24
24
  "test-types": "tsc --noEmit spec/typings/typings-test.ts",
25
25
  "unit": "jasmine",
26
- "coverage": "nyc report --reporter html --reporter text -t .nyc_output --report-dir .nyc_output/summary",
27
26
  "perf": "node ./benchmark/perfTest3.js",
28
27
  "lint": "eslint src/**/*.js spec/**/*.js benchmark/**/*.js",
29
28
  "bundle": "webpack --config webpack.cjs.config.js",
@@ -68,11 +67,11 @@
68
67
  "@babel/plugin-transform-runtime": "^7.13.10",
69
68
  "@babel/preset-env": "^7.13.10",
70
69
  "@babel/register": "^7.13.8",
70
+ "@byspec/xml": "^0.1.0",
71
71
  "@types/node": "20",
72
72
  "babel-loader": "^8.2.2",
73
73
  "c8": "^10.1.3",
74
74
  "eslint": "^8.3.0",
75
- "he": "^1.2.0",
76
75
  "jasmine": "^5.6.0",
77
76
  "prettier": "^3.5.1",
78
77
  "publish-please": "^5.5.2",
@@ -88,8 +87,9 @@
88
87
  ],
89
88
  "dependencies": {
90
89
  "@nodable/entities": "^2.1.0",
91
- "fast-xml-builder": "^1.1.5",
90
+ "fast-xml-builder": "^1.2.0",
92
91
  "path-expression-matcher": "^1.5.0",
93
- "strnum": "^2.2.3"
92
+ "strnum": "^2.3.0",
93
+ "xml-naming": "^0.1.0"
94
94
  }
95
95
  }
package/src/fxp.d.ts CHANGED
@@ -696,11 +696,19 @@ export type ValidationError = {
696
696
 
697
697
  export class XMLParser {
698
698
  constructor(options?: X2jOptions);
699
- parse(xmlData: string | Uint8Array, validationOptions?: validationOptions | boolean): any;
699
+
700
+ parse(xmlData: string | Uint8Array): any;
701
+ /**
702
+ * @deprecated The `validationOptions` parameter is deprecated.
703
+ * Use the `fast-xml-validator` package instead for XML validation.
704
+ * @see https://www.npmjs.com/package/fast-xml-validator
705
+ */
706
+ parse(xmlData: string | Uint8Array, validationOptions: validationOptions | boolean): any;
700
707
  /**
701
708
  * Add Entity which is not by default supported by this library
702
709
  * @param entityIdentifier {string} Eg: 'ent' for &ent;
703
710
  * @param entityValue {string} Eg: '\r'
711
+ * @deprecated Use `entityDecoder` instead
704
712
  */
705
713
  addEntity(entityIdentifier: string, entityValue: string): void;
706
714
 
@@ -717,6 +725,10 @@ export class XMLParser {
717
725
  static getMetaDataSymbol(): Symbol;
718
726
  }
719
727
 
728
+ /**
729
+ * @deprecated Use fast-xml-validator instead
730
+ * @see https://www.npmjs.com/package/fast-xml-validator
731
+ */
720
732
  export class XMLValidator {
721
733
  static validate(xmlData: string, options?: validationOptions): true | ValidationError;
722
734
  }
@@ -1,11 +1,15 @@
1
- import { isName } from '../util.js';
1
+ import { qName as isName } from 'xml-naming';
2
2
 
3
3
  export default class DocTypeReader {
4
- constructor(options) {
4
+ constructor(options, xmlVersion) {
5
5
  this.suppressValidationErr = !options;
6
6
  this.options = options;
7
+ this.xmlVersion = xmlVersion || 1.0;
7
8
  }
8
9
 
10
+ setXmlVersion(xmlVersion = 1.0) {
11
+ this.xmlVersion = xmlVersion;
12
+ }
9
13
  readDocType(xmlData, i) {
10
14
  const entities = Object.create(null);
11
15
  let entityCount = 0;
@@ -103,7 +107,7 @@ export default class DocTypeReader {
103
107
  }
104
108
  let entityName = xmlData.substring(startIndex, i);
105
109
 
106
- validateEntityName(entityName);
110
+ validateEntityName(entityName, { xmlVersion: this.xmlVersion });
107
111
 
108
112
  // Skip whitespace after entity name
109
113
  i = skipWhitespace(xmlData, i);
@@ -146,7 +150,7 @@ export default class DocTypeReader {
146
150
  }
147
151
  let notationName = xmlData.substring(startIndex, i);
148
152
 
149
- !this.suppressValidationErr && validateEntityName(notationName);
153
+ !this.suppressValidationErr && validateEntityName(notationName, { xmlVersion: this.xmlVersion });
150
154
 
151
155
  // Skip whitespace after notation name
152
156
  i = skipWhitespace(xmlData, i);
@@ -226,7 +230,7 @@ export default class DocTypeReader {
226
230
  let elementName = xmlData.substring(startIndex, i);
227
231
 
228
232
  // Validate element name
229
- if (!this.suppressValidationErr && !isName(elementName)) {
233
+ if (!this.suppressValidationErr && !isName(elementName, { xmlVersion: this.xmlVersion })) {
230
234
  throw new Error(`Invalid element name: "${elementName}"`);
231
235
  }
232
236
 
@@ -273,7 +277,7 @@ export default class DocTypeReader {
273
277
  let elementName = xmlData.substring(startIndex, i);
274
278
 
275
279
  // Validate element name
276
- validateEntityName(elementName)
280
+ validateEntityName(elementName, { xmlVersion: this.xmlVersion })
277
281
 
278
282
  // Skip whitespace after element name
279
283
  i = skipWhitespace(xmlData, i);
@@ -286,7 +290,7 @@ export default class DocTypeReader {
286
290
  let attributeName = xmlData.substring(startIndex, i);
287
291
 
288
292
  // Validate attribute name
289
- if (!validateEntityName(attributeName)) {
293
+ if (!validateEntityName(attributeName, { xmlVersion: this.xmlVersion })) {
290
294
  throw new Error(`Invalid attribute name: "${attributeName}"`);
291
295
  }
292
296
 
@@ -321,7 +325,7 @@ export default class DocTypeReader {
321
325
 
322
326
  // Validate notation name
323
327
  notation = notation.trim();
324
- if (!validateEntityName(notation)) {
328
+ if (!validateEntityName(notation, { xmlVersion: this.xmlVersion })) {
325
329
  throw new Error(`Invalid notation name: "${notation}"`);
326
330
  }
327
331
 
@@ -399,8 +403,8 @@ function hasSeq(data, seq, i) {
399
403
  return true;
400
404
  }
401
405
 
402
- function validateEntityName(name) {
403
- if (isName(name))
406
+ function validateEntityName(name, xmlVersion) {
407
+ if (isName(name, { xmlVersion: xmlVersion }))
404
408
  return name;
405
409
  else
406
410
  throw new Error(`Invalid entity name ${name}`);
@@ -105,9 +105,6 @@ export default class OrderedObjParser {
105
105
 
106
106
  // Initialize path matcher for path-expression-matcher
107
107
  this.matcher = new Matcher();
108
-
109
- // Live read-only proxy of matcher — PEM creates and caches this internally.
110
- // All user callbacks receive this instead of the mutable matcher.
111
108
  this.readonlyMatcher = this.matcher.readOnly();
112
109
 
113
110
  // Flag to track if current node is a stop node (optimization)
@@ -343,6 +340,7 @@ const parseXml = function (xmlData) {
343
340
  if (attsMap) {
344
341
  const ver = attsMap[this.options.attributeNamePrefix + "version"];
345
342
  this.entityDecoder.setXmlVersion(Number(ver) || 1.0);
343
+ docTypeReader.setXmlVersion(Number(ver) || 1.0);
346
344
  }
347
345
  if ((options.ignoreDeclaration && tagData.tagName === "?xml") || options.ignorePiTags) {
348
346
  //do nothing
@@ -776,7 +774,7 @@ function readStopNodeData(xmlData, tagName, i) {
776
774
  const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
777
775
  i = closeIndex;
778
776
  } else {
779
- const tagData = readTagExp(xmlData, i, '>')
777
+ const tagData = readTagExp(xmlData, i, false)
780
778
 
781
779
  if (tagData) {
782
780
  const openTagName = tagData && tagData.tagName;
@@ -71,6 +71,10 @@ function compress(arr, options, matcher, readonlyMatcher) {
71
71
  let val = compress(tagObj[property], options, matcher, readonlyMatcher);
72
72
  const isLeaf = isLeafTag(val, options);
73
73
 
74
+ if (Object.keys(val).length === 0 && options.alwaysCreateTextNode) {
75
+ val[options.textNodeName] = "";
76
+ }
77
+
74
78
  if (tagObj[":@"]) {
75
79
  assignAttributes(val, tagObj[":@"], readonlyMatcher, options);
76
80
  } else if (Object.keys(val).length === 1 && val[options.textNodeName] !== undefined && !options.alwaysCreateTextNode) {