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
|
@@ -1,35 +1,66 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
import XmlNode from './xmlNode.js';
|
|
4
|
+
import { Matcher } from 'path-expression-matcher';
|
|
4
5
|
|
|
5
6
|
const METADATA_SYMBOL = XmlNode.getMetaDataSymbol();
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Helper function to strip attribute prefix from attribute map
|
|
10
|
+
* @param {object} attrs - Attributes with prefix (e.g., {"@_class": "code"})
|
|
11
|
+
* @param {string} prefix - Attribute prefix to remove (e.g., "@_")
|
|
12
|
+
* @returns {object} Attributes without prefix (e.g., {"class": "code"})
|
|
13
|
+
*/
|
|
14
|
+
function stripAttributePrefix(attrs, prefix) {
|
|
15
|
+
if (!attrs || typeof attrs !== 'object') return {};
|
|
16
|
+
if (!prefix) return attrs;
|
|
17
|
+
|
|
18
|
+
const rawAttrs = {};
|
|
19
|
+
for (const key in attrs) {
|
|
20
|
+
if (key.startsWith(prefix)) {
|
|
21
|
+
const rawName = key.substring(prefix.length);
|
|
22
|
+
rawAttrs[rawName] = attrs[key];
|
|
23
|
+
} else {
|
|
24
|
+
// Attribute without prefix (shouldn't normally happen, but be safe)
|
|
25
|
+
rawAttrs[key] = attrs[key];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return rawAttrs;
|
|
29
|
+
}
|
|
30
|
+
|
|
7
31
|
/**
|
|
8
32
|
*
|
|
9
33
|
* @param {array} node
|
|
10
34
|
* @param {any} options
|
|
35
|
+
* @param {Matcher} matcher - Path matcher instance
|
|
11
36
|
* @returns
|
|
12
37
|
*/
|
|
13
|
-
export default function prettify(node, options) {
|
|
14
|
-
return compress(node, options);
|
|
38
|
+
export default function prettify(node, options, matcher) {
|
|
39
|
+
return compress(node, options, matcher);
|
|
15
40
|
}
|
|
16
41
|
|
|
17
42
|
/**
|
|
18
43
|
*
|
|
19
44
|
* @param {array} arr
|
|
20
45
|
* @param {object} options
|
|
21
|
-
* @param {
|
|
46
|
+
* @param {Matcher} matcher - Path matcher instance
|
|
22
47
|
* @returns object
|
|
23
48
|
*/
|
|
24
|
-
function compress(arr, options,
|
|
49
|
+
function compress(arr, options, matcher) {
|
|
25
50
|
let text;
|
|
26
51
|
const compressedObj = {}; //This is intended to be a plain object
|
|
27
52
|
for (let i = 0; i < arr.length; i++) {
|
|
28
53
|
const tagObj = arr[i];
|
|
29
54
|
const property = propName(tagObj);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
55
|
+
|
|
56
|
+
// Push current property to matcher WITH RAW ATTRIBUTES (no prefix)
|
|
57
|
+
if (property !== undefined && property !== options.textNodeName) {
|
|
58
|
+
const rawAttrs = stripAttributePrefix(
|
|
59
|
+
tagObj[":@"] || {},
|
|
60
|
+
options.attributeNamePrefix
|
|
61
|
+
);
|
|
62
|
+
matcher.push(property, rawAttrs);
|
|
63
|
+
}
|
|
33
64
|
|
|
34
65
|
if (property === options.textNodeName) {
|
|
35
66
|
if (text === undefined) text = tagObj[property];
|
|
@@ -38,11 +69,11 @@ function compress(arr, options, jPath) {
|
|
|
38
69
|
continue;
|
|
39
70
|
} else if (tagObj[property]) {
|
|
40
71
|
|
|
41
|
-
let val = compress(tagObj[property], options,
|
|
72
|
+
let val = compress(tagObj[property], options, matcher);
|
|
42
73
|
const isLeaf = isLeafTag(val, options);
|
|
43
74
|
|
|
44
75
|
if (tagObj[":@"]) {
|
|
45
|
-
assignAttributes(val, tagObj[":@"],
|
|
76
|
+
assignAttributes(val, tagObj[":@"], matcher, options);
|
|
46
77
|
} else if (Object.keys(val).length === 1 && val[options.textNodeName] !== undefined && !options.alwaysCreateTextNode) {
|
|
47
78
|
val = val[options.textNodeName];
|
|
48
79
|
} else if (Object.keys(val).length === 0) {
|
|
@@ -63,12 +94,20 @@ function compress(arr, options, jPath) {
|
|
|
63
94
|
} else {
|
|
64
95
|
//TODO: if a node is not an array, then check if it should be an array
|
|
65
96
|
//also determine if it is a leaf node
|
|
66
|
-
|
|
97
|
+
|
|
98
|
+
// Pass jPath string or matcher based on options.jPath setting
|
|
99
|
+
const jPathOrMatcher = options.jPath ? matcher.toString() : matcher;
|
|
100
|
+
if (options.isArray(property, jPathOrMatcher, isLeaf)) {
|
|
67
101
|
compressedObj[property] = [val];
|
|
68
102
|
} else {
|
|
69
103
|
compressedObj[property] = val;
|
|
70
104
|
}
|
|
71
105
|
}
|
|
106
|
+
|
|
107
|
+
// Pop property from matcher after processing
|
|
108
|
+
if (property !== undefined && property !== options.textNodeName) {
|
|
109
|
+
matcher.pop();
|
|
110
|
+
}
|
|
72
111
|
}
|
|
73
112
|
|
|
74
113
|
}
|
|
@@ -89,13 +128,25 @@ function propName(obj) {
|
|
|
89
128
|
}
|
|
90
129
|
}
|
|
91
130
|
|
|
92
|
-
function assignAttributes(obj, attrMap,
|
|
131
|
+
function assignAttributes(obj, attrMap, matcher, options) {
|
|
93
132
|
if (attrMap) {
|
|
94
133
|
const keys = Object.keys(attrMap);
|
|
95
134
|
const len = keys.length; //don't make it inline
|
|
96
135
|
for (let i = 0; i < len; i++) {
|
|
97
|
-
const atrrName = keys[i];
|
|
98
|
-
|
|
136
|
+
const atrrName = keys[i]; // This is the PREFIXED name (e.g., "@_class")
|
|
137
|
+
|
|
138
|
+
// Strip prefix for matcher path (for isArray callback)
|
|
139
|
+
const rawAttrName = atrrName.startsWith(options.attributeNamePrefix)
|
|
140
|
+
? atrrName.substring(options.attributeNamePrefix.length)
|
|
141
|
+
: atrrName;
|
|
142
|
+
|
|
143
|
+
// For attributes, we need to create a temporary path
|
|
144
|
+
// Pass jPath string or matcher based on options.jPath setting
|
|
145
|
+
const jPathOrMatcher = options.jPath
|
|
146
|
+
? matcher.toString() + "." + rawAttrName
|
|
147
|
+
: matcher;
|
|
148
|
+
|
|
149
|
+
if (options.isArray(atrrName, jPathOrMatcher, true, true)) {
|
|
99
150
|
obj[atrrName] = [attrMap[atrrName]];
|
|
100
151
|
} else {
|
|
101
152
|
obj[atrrName] = attrMap[atrrName];
|
|
@@ -120,4 +171,4 @@ function isLeafTag(obj, options) {
|
|
|
120
171
|
}
|
|
121
172
|
|
|
122
173
|
return false;
|
|
123
|
-
}
|
|
174
|
+
}
|