fast-xml-parser 5.5.9 → 5.5.10
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 +8 -0
- package/README.md +8 -28
- package/lib/fxbuilder.min.js +1 -1
- package/lib/fxbuilder.min.js.map +1 -1
- package/lib/fxp.cjs +1 -1
- 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 +3 -3
- package/src/xmlparser/OptionsBuilder.js +3 -3
- package/src/xmlparser/OrderedObjParser.js +31 -39
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-xml-parser",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.10",
|
|
4
4
|
"description": "Validate XML, Parse XML, Build XML without C/C++ based libraries",
|
|
5
5
|
"main": "./lib/fxp.cjs",
|
|
6
6
|
"type": "module",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
],
|
|
89
89
|
"dependencies": {
|
|
90
90
|
"fast-xml-builder": "^1.1.4",
|
|
91
|
-
"path-expression-matcher": "^1.2.
|
|
91
|
+
"path-expression-matcher": "^1.2.1",
|
|
92
92
|
"strnum": "^2.2.2"
|
|
93
93
|
}
|
|
94
|
-
}
|
|
94
|
+
}
|
|
@@ -105,10 +105,10 @@ function normalizeProcessEntities(value) {
|
|
|
105
105
|
return {
|
|
106
106
|
enabled: value.enabled !== false,
|
|
107
107
|
maxEntitySize: Math.max(1, value.maxEntitySize ?? 10000),
|
|
108
|
-
maxExpansionDepth: Math.max(1, value.maxExpansionDepth ??
|
|
109
|
-
maxTotalExpansions: Math.max(1, value.maxTotalExpansions ??
|
|
108
|
+
maxExpansionDepth: Math.max(1, value.maxExpansionDepth ?? 10000),
|
|
109
|
+
maxTotalExpansions: Math.max(1, value.maxTotalExpansions ?? Infinity),
|
|
110
110
|
maxExpandedLength: Math.max(1, value.maxExpandedLength ?? 100000),
|
|
111
|
-
maxEntityCount: Math.max(1, value.maxEntityCount ??
|
|
111
|
+
maxEntityCount: Math.max(1, value.maxEntityCount ?? 1000),
|
|
112
112
|
allowedTags: value.allowedTags ?? null,
|
|
113
113
|
tagFilter: value.tagFilter ?? null
|
|
114
114
|
};
|
|
@@ -217,89 +217,80 @@ function buildAttributesMap(attrStr, jPath, tagName) {
|
|
|
217
217
|
const len = matches.length; //don't make it inline
|
|
218
218
|
const attrs = {};
|
|
219
219
|
|
|
220
|
-
//
|
|
221
|
-
//
|
|
220
|
+
// Pre-process values once: trim + entity replacement
|
|
221
|
+
// Reused in both matcher update and second pass
|
|
222
|
+
const processedVals = new Array(len);
|
|
223
|
+
let hasRawAttrs = false;
|
|
222
224
|
const rawAttrsForMatcher = {};
|
|
225
|
+
|
|
223
226
|
for (let i = 0; i < len; i++) {
|
|
224
227
|
const attrName = this.resolveNameSpace(matches[i][1]);
|
|
225
228
|
const oldVal = matches[i][4];
|
|
226
229
|
|
|
227
230
|
if (attrName.length && oldVal !== undefined) {
|
|
228
|
-
let
|
|
229
|
-
if (this.options.trimValues)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
rawAttrsForMatcher[attrName] =
|
|
231
|
+
let val = oldVal;
|
|
232
|
+
if (this.options.trimValues) val = val.trim();
|
|
233
|
+
val = this.replaceEntitiesValue(val, tagName, this.readonlyMatcher);
|
|
234
|
+
processedVals[i] = val;
|
|
235
|
+
|
|
236
|
+
rawAttrsForMatcher[attrName] = val;
|
|
237
|
+
hasRawAttrs = true;
|
|
234
238
|
}
|
|
235
239
|
}
|
|
236
240
|
|
|
237
|
-
// Update matcher
|
|
238
|
-
if (
|
|
241
|
+
// Update matcher ONCE before second pass, if applicable
|
|
242
|
+
if (hasRawAttrs && typeof jPath === 'object' && jPath.updateCurrent) {
|
|
239
243
|
jPath.updateCurrent(rawAttrsForMatcher);
|
|
240
244
|
}
|
|
241
245
|
|
|
242
|
-
//
|
|
246
|
+
// Hoist toString() once — path doesn't change during attribute processing
|
|
247
|
+
const jPathStr = this.options.jPath ? jPath.toString() : this.readonlyMatcher;
|
|
248
|
+
|
|
249
|
+
// Second pass: apply processors, build final attrs
|
|
250
|
+
let hasAttrs = false;
|
|
243
251
|
for (let i = 0; i < len; i++) {
|
|
244
252
|
const attrName = this.resolveNameSpace(matches[i][1]);
|
|
245
253
|
|
|
246
|
-
|
|
247
|
-
const jPathStr = this.options.jPath ? jPath.toString() : this.readonlyMatcher;
|
|
248
|
-
if (this.ignoreAttributesFn(attrName, jPathStr)) {
|
|
249
|
-
continue
|
|
250
|
-
}
|
|
254
|
+
if (this.ignoreAttributesFn(attrName, jPathStr)) continue;
|
|
251
255
|
|
|
252
|
-
let oldVal = matches[i][4];
|
|
253
256
|
let aName = this.options.attributeNamePrefix + attrName;
|
|
254
257
|
|
|
255
258
|
if (attrName.length) {
|
|
256
259
|
if (this.options.transformAttributeName) {
|
|
257
260
|
aName = this.options.transformAttributeName(aName);
|
|
258
261
|
}
|
|
259
|
-
//if (aName === "__proto__") aName = "#__proto__";
|
|
260
262
|
aName = sanitizeName(aName, this.options);
|
|
261
263
|
|
|
262
|
-
if (
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
oldVal = this.replaceEntitiesValue(oldVal, tagName, this.readonlyMatcher);
|
|
264
|
+
if (matches[i][4] !== undefined) {
|
|
265
|
+
// Reuse already-processed value — no double entity replacement
|
|
266
|
+
const oldVal = processedVals[i];
|
|
267
267
|
|
|
268
|
-
|
|
269
|
-
const jPathOrMatcher = this.options.jPath ? jPath.toString() : this.readonlyMatcher;
|
|
270
|
-
const newVal = this.options.attributeValueProcessor(attrName, oldVal, jPathOrMatcher);
|
|
268
|
+
const newVal = this.options.attributeValueProcessor(attrName, oldVal, jPathStr);
|
|
271
269
|
if (newVal === null || newVal === undefined) {
|
|
272
|
-
//don't parse
|
|
273
270
|
attrs[aName] = oldVal;
|
|
274
271
|
} else if (typeof newVal !== typeof oldVal || newVal !== oldVal) {
|
|
275
|
-
//overwrite
|
|
276
272
|
attrs[aName] = newVal;
|
|
277
273
|
} else {
|
|
278
|
-
|
|
279
|
-
attrs[aName] = parseValue(
|
|
280
|
-
oldVal,
|
|
281
|
-
this.options.parseAttributeValue,
|
|
282
|
-
this.options.numberParseOptions
|
|
283
|
-
);
|
|
274
|
+
attrs[aName] = parseValue(oldVal, this.options.parseAttributeValue, this.options.numberParseOptions);
|
|
284
275
|
}
|
|
276
|
+
hasAttrs = true;
|
|
285
277
|
} else if (this.options.allowBooleanAttributes) {
|
|
286
278
|
attrs[aName] = true;
|
|
279
|
+
hasAttrs = true;
|
|
287
280
|
}
|
|
288
281
|
}
|
|
289
282
|
}
|
|
290
283
|
|
|
291
|
-
if (!
|
|
292
|
-
|
|
293
|
-
}
|
|
284
|
+
if (!hasAttrs) return;
|
|
285
|
+
|
|
294
286
|
if (this.options.attributesGroupName) {
|
|
295
287
|
const attrCollection = {};
|
|
296
288
|
attrCollection[this.options.attributesGroupName] = attrs;
|
|
297
289
|
return attrCollection;
|
|
298
290
|
}
|
|
299
|
-
return attrs
|
|
291
|
+
return attrs;
|
|
300
292
|
}
|
|
301
293
|
}
|
|
302
|
-
|
|
303
294
|
const parseXml = function (xmlData) {
|
|
304
295
|
xmlData = xmlData.replace(/\r\n?/g, "\n"); //TODO: remove this line
|
|
305
296
|
const xmlObj = new xmlNode('!xml');
|
|
@@ -659,6 +650,7 @@ function replaceEntitiesValue(val, tagName, jPath) {
|
|
|
659
650
|
}
|
|
660
651
|
}
|
|
661
652
|
}
|
|
653
|
+
if (val.indexOf('&') === -1) return val;
|
|
662
654
|
// Replace standard entities
|
|
663
655
|
for (const entityName of Object.keys(this.lastEntities)) {
|
|
664
656
|
const entity = this.lastEntities[entityName];
|