fast-xml-parser 5.4.1 → 5.5.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/CHANGELOG.md +10 -4
- package/README.md +8 -7
- package/lib/fxbuilder.min.js +1 -1
- package/lib/fxbuilder.min.js.map +1 -1
- package/lib/fxp.cjs +1 -1
- package/lib/fxp.d.cts +53 -19
- package/lib/fxp.min.js +1 -1
- package/lib/fxp.min.js.map +1 -1
- package/lib/fxparser.min.js +1 -1
- package/lib/fxparser.min.js.map +1 -1
- package/package.json +4 -3
- package/src/fxp.d.ts +53 -19
- package/src/xmlparser/DocTypeReader.js +10 -1
- package/src/xmlparser/OptionsBuilder.js +15 -0
- package/src/xmlparser/OrderedObjParser.js +238 -89
- package/src/xmlparser/XMLParser.js +1 -1
- package/src/xmlparser/node2json.js +65 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-xml-parser",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.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",
|
|
@@ -87,7 +87,8 @@
|
|
|
87
87
|
}
|
|
88
88
|
],
|
|
89
89
|
"dependencies": {
|
|
90
|
-
"fast-xml-builder": "
|
|
90
|
+
"fast-xml-builder": "file:../../fxp-builder",
|
|
91
|
+
"path-expression-matcher": "^1.1.2",
|
|
91
92
|
"strnum": "^2.1.2"
|
|
92
93
|
}
|
|
93
|
-
}
|
|
94
|
+
}
|
package/src/fxp.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Matcher, Expression } from 'path-expression-matcher';
|
|
2
|
+
|
|
1
3
|
export type ProcessEntitiesOptions = {
|
|
2
4
|
/**
|
|
3
5
|
* Whether to enable entity processing
|
|
@@ -34,6 +36,13 @@ export type ProcessEntitiesOptions = {
|
|
|
34
36
|
*/
|
|
35
37
|
maxExpandedLength?: number;
|
|
36
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Maximum number of entities allowed in the XML
|
|
41
|
+
*
|
|
42
|
+
* Defaults to `100`
|
|
43
|
+
*/
|
|
44
|
+
maxEntityCount?: number;
|
|
45
|
+
|
|
37
46
|
/**
|
|
38
47
|
* Array of tag names where entity replacement is allowed.
|
|
39
48
|
* If null, entities are replaced in all tags.
|
|
@@ -46,12 +55,12 @@ export type ProcessEntitiesOptions = {
|
|
|
46
55
|
* Custom filter function to determine if entities should be replaced in a tag
|
|
47
56
|
*
|
|
48
57
|
* @param tagName - The name of the current tag
|
|
49
|
-
* @param
|
|
58
|
+
* @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false)
|
|
50
59
|
* @returns `true` to allow entity replacement, `false` to skip
|
|
51
60
|
*
|
|
52
61
|
* Defaults to `null`
|
|
53
62
|
*/
|
|
54
|
-
tagFilter?: ((tagName: string,
|
|
63
|
+
tagFilter?: ((tagName: string, jPathOrMatcher: string | Matcher) => boolean) | null;
|
|
55
64
|
};
|
|
56
65
|
|
|
57
66
|
export type X2jOptions = {
|
|
@@ -96,7 +105,7 @@ export type X2jOptions = {
|
|
|
96
105
|
*
|
|
97
106
|
* Defaults to `true`
|
|
98
107
|
*/
|
|
99
|
-
ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string,
|
|
108
|
+
ignoreAttributes?: boolean | (string | RegExp)[] | ((attrName: string, jPathOrMatcher: string | Matcher) => boolean);
|
|
100
109
|
|
|
101
110
|
/**
|
|
102
111
|
* Whether to remove namespace string from tag and attribute names
|
|
@@ -150,28 +159,33 @@ export type X2jOptions = {
|
|
|
150
159
|
/**
|
|
151
160
|
* Control how tag value should be parsed. Called only if tag value is not empty
|
|
152
161
|
*
|
|
162
|
+
* @param tagName - The name of the tag
|
|
163
|
+
* @param tagValue - The value of the tag
|
|
164
|
+
* @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false)
|
|
165
|
+
* @param hasAttributes - Whether the tag has attributes
|
|
166
|
+
* @param isLeafNode - Whether the tag is a leaf node
|
|
153
167
|
* @returns {undefined|null} `undefined` or `null` to set original value.
|
|
154
168
|
* @returns {unknown}
|
|
155
169
|
*
|
|
156
170
|
* 1. Different value or value with different data type to set new value.
|
|
157
171
|
* 2. Same value to set parsed value if `parseTagValue: true`.
|
|
158
172
|
*
|
|
159
|
-
* Defaults to `(tagName, val,
|
|
173
|
+
* Defaults to `(tagName, val, jPathOrMatcher, hasAttributes, isLeafNode) => val`
|
|
160
174
|
*/
|
|
161
|
-
tagValueProcessor?: (tagName: string, tagValue: string,
|
|
175
|
+
tagValueProcessor?: (tagName: string, tagValue: string, jPathOrMatcher: string | Matcher, hasAttributes: boolean, isLeafNode: boolean) => unknown;
|
|
162
176
|
|
|
163
177
|
/**
|
|
164
178
|
* Control how attribute value should be parsed
|
|
165
179
|
*
|
|
166
|
-
* @param attrName
|
|
167
|
-
* @param attrValue
|
|
168
|
-
* @param jPath
|
|
180
|
+
* @param attrName - The name of the attribute
|
|
181
|
+
* @param attrValue - The value of the attribute
|
|
182
|
+
* @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false)
|
|
169
183
|
* @returns {undefined|null} `undefined` or `null` to set original value
|
|
170
184
|
* @returns {unknown}
|
|
171
185
|
*
|
|
172
|
-
* Defaults to `(attrName, val,
|
|
186
|
+
* Defaults to `(attrName, val, jPathOrMatcher) => val`
|
|
173
187
|
*/
|
|
174
|
-
attributeValueProcessor?: (attrName: string, attrValue: string,
|
|
188
|
+
attributeValueProcessor?: (attrName: string, attrValue: string, jPathOrMatcher: string | Matcher) => unknown;
|
|
175
189
|
|
|
176
190
|
/**
|
|
177
191
|
* Options to pass to `strnum` for parsing numbers
|
|
@@ -183,9 +197,13 @@ export type X2jOptions = {
|
|
|
183
197
|
/**
|
|
184
198
|
* Nodes to stop parsing at
|
|
185
199
|
*
|
|
200
|
+
* Accepts string patterns or Expression objects from path-expression-matcher
|
|
201
|
+
*
|
|
202
|
+
* String patterns starting with "*." are automatically converted to ".." for backward compatibility
|
|
203
|
+
*
|
|
186
204
|
* Defaults to `[]`
|
|
187
205
|
*/
|
|
188
|
-
stopNodes?: string[];
|
|
206
|
+
stopNodes?: (string | Expression)[];
|
|
189
207
|
|
|
190
208
|
/**
|
|
191
209
|
* List of tags without closing tags
|
|
@@ -204,15 +222,15 @@ export type X2jOptions = {
|
|
|
204
222
|
/**
|
|
205
223
|
* Determine whether a tag should be parsed as an array
|
|
206
224
|
*
|
|
207
|
-
* @param tagName
|
|
208
|
-
* @param jPath
|
|
209
|
-
* @param isLeafNode
|
|
210
|
-
* @param isAttribute
|
|
225
|
+
* @param tagName - The name of the tag
|
|
226
|
+
* @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false)
|
|
227
|
+
* @param isLeafNode - Whether the tag is a leaf node
|
|
228
|
+
* @param isAttribute - Whether this is an attribute
|
|
211
229
|
* @returns {boolean}
|
|
212
230
|
*
|
|
213
231
|
* Defaults to `() => false`
|
|
214
232
|
*/
|
|
215
|
-
isArray?: (tagName: string,
|
|
233
|
+
isArray?: (tagName: string, jPathOrMatcher: string | Matcher, isLeafNode: boolean, isAttribute: boolean) => boolean;
|
|
216
234
|
|
|
217
235
|
/**
|
|
218
236
|
* Whether to process default and DOCTYPE entities
|
|
@@ -266,12 +284,15 @@ export type X2jOptions = {
|
|
|
266
284
|
* Change the tag name when a different name is returned. Skip the tag from parsed result when false is returned.
|
|
267
285
|
* Modify `attrs` object to control attributes for the given tag.
|
|
268
286
|
*
|
|
287
|
+
* @param tagName - The name of the tag
|
|
288
|
+
* @param jPathOrMatcher - The jPath string (if jPath: true) or Matcher instance (if jPath: false)
|
|
289
|
+
* @param attrs - The attributes object
|
|
269
290
|
* @returns {string} new tag name.
|
|
270
291
|
* @returns false to skip the tag
|
|
271
292
|
*
|
|
272
|
-
* Defaults to `(tagName,
|
|
293
|
+
* Defaults to `(tagName, jPathOrMatcher, attrs) => tagName`
|
|
273
294
|
*/
|
|
274
|
-
updateTag?: (tagName: string,
|
|
295
|
+
updateTag?: (tagName: string, jPathOrMatcher: string | Matcher, attrs: { [k: string]: string }) => string | boolean;
|
|
275
296
|
|
|
276
297
|
/**
|
|
277
298
|
* If true, adds a Symbol to all object nodes, accessible by {@link XMLParser.getMetaDataSymbol} with
|
|
@@ -292,6 +313,17 @@ export type X2jOptions = {
|
|
|
292
313
|
* Defaults to `true`
|
|
293
314
|
*/
|
|
294
315
|
strictReservedNames?: boolean;
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Controls whether callbacks receive jPath as string or Matcher instance
|
|
319
|
+
*
|
|
320
|
+
* When `true` - callbacks receive jPath as string (backward compatible)
|
|
321
|
+
*
|
|
322
|
+
* When `false` - callbacks receive Matcher instance for advanced pattern matching
|
|
323
|
+
*
|
|
324
|
+
* Defaults to `true`
|
|
325
|
+
*/
|
|
326
|
+
jPath?: boolean;
|
|
295
327
|
};
|
|
296
328
|
|
|
297
329
|
|
|
@@ -430,9 +462,11 @@ export type XmlBuilderOptions = {
|
|
|
430
462
|
/**
|
|
431
463
|
* Nodes to stop parsing at
|
|
432
464
|
*
|
|
465
|
+
* Accepts string patterns or Expression objects from path-expression-matcher
|
|
466
|
+
*
|
|
433
467
|
* Defaults to `[]`
|
|
434
468
|
*/
|
|
435
|
-
stopNodes?: string[];
|
|
469
|
+
stopNodes?: (string | Expression)[];
|
|
436
470
|
|
|
437
471
|
/**
|
|
438
472
|
* Control how tag value should be parsed. Called only if tag value is not empty
|
|
@@ -7,8 +7,9 @@ export default class DocTypeReader {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
readDocType(xmlData, i) {
|
|
10
|
-
|
|
11
10
|
const entities = Object.create(null);
|
|
11
|
+
let entityCount = 0;
|
|
12
|
+
|
|
12
13
|
if (xmlData[i + 3] === 'O' &&
|
|
13
14
|
xmlData[i + 4] === 'C' &&
|
|
14
15
|
xmlData[i + 5] === 'T' &&
|
|
@@ -26,11 +27,19 @@ export default class DocTypeReader {
|
|
|
26
27
|
let entityName, val;
|
|
27
28
|
[entityName, val, i] = this.readEntityExp(xmlData, i + 1, this.suppressValidationErr);
|
|
28
29
|
if (val.indexOf("&") === -1) { //Parameter entities are not supported
|
|
30
|
+
if (this.options.enabled !== false &&
|
|
31
|
+
this.options.maxEntityCount &&
|
|
32
|
+
entityCount >= this.options.maxEntityCount) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Entity count (${entityCount + 1}) exceeds maximum allowed (${this.options.maxEntityCount})`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
29
37
|
const escaped = entityName.replace(/[.\-+*:]/g, '\\.');
|
|
30
38
|
entities[entityName] = {
|
|
31
39
|
regx: RegExp(`&${escaped};`, "g"),
|
|
32
40
|
val: val
|
|
33
41
|
};
|
|
42
|
+
entityCount++;
|
|
34
43
|
}
|
|
35
44
|
}
|
|
36
45
|
else if (hasBody && hasSeq(xmlData, "!ELEMENT", i)) {
|
|
@@ -40,6 +40,7 @@ export const defaultOptions = {
|
|
|
40
40
|
captureMetaData: false,
|
|
41
41
|
maxNestedTags: 100,
|
|
42
42
|
strictReservedNames: true,
|
|
43
|
+
jPath: true, // if true, pass jPath string to callbacks; if false, pass matcher instance
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -56,6 +57,7 @@ function normalizeProcessEntities(value) {
|
|
|
56
57
|
maxExpansionDepth: 10,
|
|
57
58
|
maxTotalExpansions: 1000,
|
|
58
59
|
maxExpandedLength: 100000,
|
|
60
|
+
maxEntityCount: 100,
|
|
59
61
|
allowedTags: null,
|
|
60
62
|
tagFilter: null
|
|
61
63
|
};
|
|
@@ -69,6 +71,7 @@ function normalizeProcessEntities(value) {
|
|
|
69
71
|
maxExpansionDepth: value.maxExpansionDepth ?? 10,
|
|
70
72
|
maxTotalExpansions: value.maxTotalExpansions ?? 1000,
|
|
71
73
|
maxExpandedLength: value.maxExpandedLength ?? 100000,
|
|
74
|
+
maxEntityCount: value.maxEntityCount ?? 100,
|
|
72
75
|
allowedTags: value.allowedTags ?? null,
|
|
73
76
|
tagFilter: value.tagFilter ?? null
|
|
74
77
|
};
|
|
@@ -83,6 +86,18 @@ export const buildOptions = function (options) {
|
|
|
83
86
|
|
|
84
87
|
// Always normalize processEntities for backward compatibility and validation
|
|
85
88
|
built.processEntities = normalizeProcessEntities(built.processEntities);
|
|
89
|
+
|
|
90
|
+
// Convert old-style stopNodes for backward compatibility
|
|
91
|
+
if (built.stopNodes && Array.isArray(built.stopNodes)) {
|
|
92
|
+
built.stopNodes = built.stopNodes.map(node => {
|
|
93
|
+
if (typeof node === 'string' && node.startsWith('*.')) {
|
|
94
|
+
// Old syntax: *.tagname meant "tagname anywhere"
|
|
95
|
+
// Convert to new syntax: ..tagname
|
|
96
|
+
return '..' + node.substring(2);
|
|
97
|
+
}
|
|
98
|
+
return node;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
86
101
|
//console.debug(built.processEntities)
|
|
87
102
|
return built;
|
|
88
103
|
};
|