fast-xml-parser 4.0.12 → 4.0.13
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 +4 -0
- package/README.md +25 -18
- package/package.json +1 -1
- package/src/fxp.d.ts +1 -0
- package/src/xmlbuilder/json2xml.js +2 -1
- package/src/xmlbuilder/orderedJs2Xml.js +73 -51
- package/src/xmlparser/OptionsBuilder.js +1 -0
- package/src/xmlparser/OrderedObjParser.js +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
Note: If you find missing information about particular minor version, that version must have been changed without any functional change in this library.
|
|
2
2
|
|
|
3
|
+
**4.0.13 / 2023-01-07**
|
|
4
|
+
* preserveorder formatting (By [mdeknowis](https://github.com/mdeknowis))
|
|
5
|
+
* support `transformAttributeName` (By [Erik Rothoff Andersson](https://github.com/erkie))
|
|
6
|
+
|
|
3
7
|
**4.0.12 / 2022-11-19**
|
|
4
8
|
* fix typescript
|
|
5
9
|
|
package/README.md
CHANGED
|
@@ -13,16 +13,32 @@ Validate XML, Parse XML to JS Object, or Build XML from JS Object without C/C++
|
|
|
13
13
|
|
|
14
14
|
> Looking for maintainers
|
|
15
15
|
|
|
16
|
+
Support this project by becoming a **Sponsor**.
|
|
17
|
+
|
|
18
|
+
Click on Sponsor button above or
|
|
16
19
|
<a href="https://opencollective.com/fast-xml-parser/donate" target="_blank">
|
|
17
20
|
<img src="https://opencollective.com/fast-xml-parser/donate/button@2x.png?color=blue" width=200 />
|
|
18
21
|
</a>
|
|
19
22
|
<a href="https://paypal.me/naturalintelligence"> <img src="static/img/support_paypal.svg" alt="Stubmatic donate button" width="200"/></a>
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
|
|
25
|
+
### Sponsors
|
|
26
|
+
|
|
27
|
+
<a href="https://github.com/getsentry" target="_blank"><img src="https://user-images.githubusercontent.com/7692328/204701653-ce369b29-6fdb-48f2-9848-593d04628a2b.png" width="60px"></a>
|
|
28
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/0/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/0/avatar.svg"></a>
|
|
29
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/1/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/1/avatar.svg"></a>
|
|
30
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/2/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/2/avatar.svg"></a>
|
|
31
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/3/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/3/avatar.svg"></a>
|
|
32
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/4/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/4/avatar.svg"></a>
|
|
33
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/5/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/5/avatar.svg"></a>
|
|
34
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/6/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/6/avatar.svg"></a>
|
|
35
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/7/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/7/avatar.svg"></a>
|
|
36
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/8/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/8/avatar.svg"></a>
|
|
37
|
+
<a href="https://opencollective.com/fast-xml-parser/sponsor/9/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/9/avatar.svg"></a>
|
|
22
38
|
|
|
23
39
|
|
|
40
|
+
Check [ThankYouBackers](https://github.com/NaturalIntelligence/ThankYouBackers) for our supporters
|
|
24
41
|
|
|
25
|
-
[](https://github.com/NaturalIntelligence/ads/)
|
|
26
42
|
## Users
|
|
27
43
|
|
|
28
44
|
<a href="https://github.com/renovatebot/renovate" title="renovate" ><img src="https://avatars1.githubusercontent.com/u/38656520" width="60px" ></a>
|
|
@@ -36,12 +52,14 @@ Check [ThankYouBackers](https://github.com/NaturalIntelligence/ThankYouBackers)
|
|
|
36
52
|
<a href="https://github.com/aws" title="AWS SDK" > <img src="https://avatars.githubusercontent.com/u/2232217" width="60px" ></a>
|
|
37
53
|
<a href="http://www.fda.gov/" title="Food and Drug Administration " > <img src="https://avatars2.githubusercontent.com/u/6471964" width="60px" ></a>
|
|
38
54
|
<a href="http://www.magento.com/" title="Magento" > <img src="https://avatars2.githubusercontent.com/u/168457" width="60px" ></a>
|
|
55
|
+
<a href="https://github.com/SAP" title="SAP" > <img src="https://user-images.githubusercontent.com/7692328/204835214-d9d25b58-e3df-408d-87a3-c7d36b578ee4.png" width="60px" ></a>
|
|
56
|
+
<a href="https://github.com/postmanlabs" title="postman" > <img src="https://user-images.githubusercontent.com/7692328/204835529-e9e290ad-696a-49ad-9d34-08e955704715.png" width="60px" ></a>
|
|
39
57
|
|
|
40
58
|
Check the list of all known users [here](./USERs.md);
|
|
41
59
|
|
|
42
60
|
<small>The list of users is collected either from the list published by Github, cummunicated directly through mails/chat , or from other resources. If you feel that your name in the above list is incorrectly published or you're not the user of this library anymore then you can inform us to remove it. We'll do the necessary changes ASAP.</small>
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
## Main Features
|
|
45
63
|
|
|
46
64
|
<img align="right" src="static/img/fxp_logo.png" width="180px" alt="FXP logo"/>
|
|
47
65
|
|
|
@@ -82,7 +100,7 @@ $ fxparser some.xml
|
|
|
82
100
|
|
|
83
101
|
In a node js project
|
|
84
102
|
```js
|
|
85
|
-
const { XMLParser, XMLBuilder, XMLValidator} = require("
|
|
103
|
+
const { XMLParser, XMLBuilder, XMLValidator} = require("fast-xml-parser");
|
|
86
104
|
|
|
87
105
|
const parser = new XMLParser();
|
|
88
106
|
let jObj = parser.parse(XMLdata);
|
|
@@ -130,6 +148,7 @@ Check lib folder for different browser bundles
|
|
|
130
148
|

|
|
131
149
|
* Y-axis: requests per second
|
|
132
150
|
* X-axis: File size
|
|
151
|
+
|
|
133
152
|
**Large files**
|
|
134
153
|

|
|
135
154
|
* Y-axis: requests per second
|
|
@@ -141,6 +160,8 @@ Check lib folder for different browser bundles
|
|
|
141
160
|
|
|
142
161
|
<small>negative means error</small>
|
|
143
162
|
|
|
163
|
+
[](https://github.com/NaturalIntelligence/ads/)
|
|
164
|
+
|
|
144
165
|
## Our other projects and research you must try
|
|
145
166
|
|
|
146
167
|
* **[BigBit standard](https://github.com/amitguptagwl/bigbit)** :
|
|
@@ -175,20 +196,6 @@ Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com
|
|
|
175
196
|
<a href="https://opencollective.com/fast-xml-parser#backers" target="_blank"><img src="https://opencollective.com/fast-xml-parser/backers.svg?width=890"></a>
|
|
176
197
|
|
|
177
198
|
|
|
178
|
-
### Sponsors
|
|
179
|
-
|
|
180
|
-
<small>[[Become a sponsor](https://opencollective.com/fast-xml-parser#sponsor)] Support this project by becoming a sponsor. Your logo will show up here with a link to your website. Please also share your detail so we can thankyou on SocialMedia.</small>
|
|
181
|
-
|
|
182
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/0/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/0/avatar.svg"></a>
|
|
183
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/1/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/1/avatar.svg"></a>
|
|
184
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/2/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/2/avatar.svg"></a>
|
|
185
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/3/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/3/avatar.svg"></a>
|
|
186
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/4/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/4/avatar.svg"></a>
|
|
187
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/5/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/5/avatar.svg"></a>
|
|
188
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/6/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/6/avatar.svg"></a>
|
|
189
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/7/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/7/avatar.svg"></a>
|
|
190
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/8/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/8/avatar.svg"></a>
|
|
191
|
-
<a href="https://opencollective.com/fast-xml-parser/sponsor/9/website" target="_blank"><img src="https://opencollective.com/fast-xml-parser/sponsor/9/avatar.svg"></a>
|
|
192
199
|
|
|
193
200
|
# License
|
|
194
201
|
* MIT License
|
package/package.json
CHANGED
package/src/fxp.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ Control how tag value should be parsed. Called only if tag value is not empty
|
|
|
31
31
|
ignoreDeclaration: boolean;
|
|
32
32
|
ignorePiTags: boolean;
|
|
33
33
|
transformTagName: ((tagName: string) => string) | false;
|
|
34
|
+
transformAttributeName: ((attributeName: string) => string) | false;
|
|
34
35
|
};
|
|
35
36
|
type strnumOptions = {
|
|
36
37
|
hex: boolean;
|
|
@@ -6,104 +6,126 @@ const EOL = "\n";
|
|
|
6
6
|
* @param {any} options
|
|
7
7
|
* @returns
|
|
8
8
|
*/
|
|
9
|
-
function toXml(jArray, options){
|
|
10
|
-
|
|
9
|
+
function toXml(jArray, options) {
|
|
10
|
+
let indentation = "";
|
|
11
|
+
if (options.format && options.indentBy.length > 0) {
|
|
12
|
+
indentation = EOL;
|
|
13
|
+
}
|
|
14
|
+
return arrToStr(jArray, options, "", indentation);
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
function arrToStr(arr, options, jPath,
|
|
17
|
+
function arrToStr(arr, options, jPath, indentation) {
|
|
14
18
|
let xmlStr = "";
|
|
15
|
-
|
|
16
|
-
let indentation = "";
|
|
17
|
-
if(options.format && options.indentBy.length > 0){//TODO: this logic can be avoided for each call
|
|
18
|
-
indentation = EOL + "" + options.indentBy.repeat(level);
|
|
19
|
-
}
|
|
19
|
+
let isPreviousElementTag = false;
|
|
20
20
|
|
|
21
21
|
for (let i = 0; i < arr.length; i++) {
|
|
22
22
|
const tagObj = arr[i];
|
|
23
23
|
const tagName = propName(tagObj);
|
|
24
24
|
let newJPath = "";
|
|
25
|
-
if(jPath.length === 0) newJPath = tagName
|
|
25
|
+
if (jPath.length === 0) newJPath = tagName
|
|
26
26
|
else newJPath = `${jPath}.${tagName}`;
|
|
27
27
|
|
|
28
|
-
if(tagName === options.textNodeName){
|
|
28
|
+
if (tagName === options.textNodeName) {
|
|
29
29
|
let tagText = tagObj[tagName];
|
|
30
|
-
if(!isStopNode(newJPath, options)){
|
|
31
|
-
tagText = options.tagValueProcessor(
|
|
30
|
+
if (!isStopNode(newJPath, options)) {
|
|
31
|
+
tagText = options.tagValueProcessor(tagName, tagText);
|
|
32
32
|
tagText = replaceEntitiesValue(tagText, options);
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
if (isPreviousElementTag) {
|
|
35
|
+
xmlStr += indentation;
|
|
36
|
+
}
|
|
37
|
+
xmlStr += tagText;
|
|
38
|
+
isPreviousElementTag = false;
|
|
35
39
|
continue;
|
|
36
|
-
}else if(
|
|
37
|
-
|
|
40
|
+
} else if (tagName === options.cdataPropName) {
|
|
41
|
+
if (isPreviousElementTag) {
|
|
42
|
+
xmlStr += indentation;
|
|
43
|
+
}
|
|
44
|
+
xmlStr += `<![CDATA[${tagObj[tagName][0][options.textNodeName]}]]>`;
|
|
45
|
+
isPreviousElementTag = false;
|
|
38
46
|
continue;
|
|
39
|
-
}else if(
|
|
47
|
+
} else if (tagName === options.commentPropName) {
|
|
40
48
|
xmlStr += indentation + `<!--${tagObj[tagName][0][options.textNodeName]}-->`;
|
|
49
|
+
isPreviousElementTag = true;
|
|
41
50
|
continue;
|
|
42
|
-
}else if(
|
|
51
|
+
} else if (tagName[0] === "?") {
|
|
43
52
|
const attStr = attr_to_str(tagObj[":@"], options);
|
|
44
53
|
const tempInd = tagName === "?xml" ? "" : indentation;
|
|
45
54
|
let piTextNodeName = tagObj[tagName][0][options.textNodeName];
|
|
46
55
|
piTextNodeName = piTextNodeName.length !== 0 ? " " + piTextNodeName : ""; //remove extra spacing
|
|
47
56
|
xmlStr += tempInd + `<${tagName}${piTextNodeName}${attStr}?>`;
|
|
57
|
+
isPreviousElementTag = true;
|
|
48
58
|
continue;
|
|
49
59
|
}
|
|
60
|
+
let newIdentation = indentation;
|
|
61
|
+
if (newIdentation !== "") {
|
|
62
|
+
newIdentation += options.indentBy;
|
|
63
|
+
}
|
|
50
64
|
const attStr = attr_to_str(tagObj[":@"], options);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if(options.unpairedTags.indexOf(tagName) !== -1){
|
|
54
|
-
if(options.suppressUnpairedNode)
|
|
55
|
-
else xmlStr += tagStart + "/>";
|
|
56
|
-
}else if
|
|
57
|
-
xmlStr += tagStart + "/>";
|
|
58
|
-
}else{
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
const tagStart = indentation + `<${tagName}${attStr}`;
|
|
66
|
+
const tagValue = arrToStr(tagObj[tagName], options, newJPath, newIdentation);
|
|
67
|
+
if (options.unpairedTags.indexOf(tagName) !== -1) {
|
|
68
|
+
if (options.suppressUnpairedNode) xmlStr += tagStart + ">";
|
|
69
|
+
else xmlStr += tagStart + "/>";
|
|
70
|
+
} else if ((!tagValue || tagValue.length === 0) && options.suppressEmptyNode) {
|
|
71
|
+
xmlStr += tagStart + "/>";
|
|
72
|
+
} else if (tagValue && tagValue.endsWith(">")) {
|
|
73
|
+
xmlStr += tagStart + `>${tagValue}${indentation}</${tagName}>`;
|
|
74
|
+
} else {
|
|
75
|
+
xmlStr += tagStart + ">";
|
|
76
|
+
if (tagValue && indentation !== "" && (tagValue.includes("/>") || tagValue.includes("</"))) {
|
|
77
|
+
xmlStr += indentation + options.indentBy + tagValue + indentation;
|
|
78
|
+
} else {
|
|
79
|
+
xmlStr += tagValue;
|
|
80
|
+
}
|
|
81
|
+
xmlStr += `</${tagName}>`;
|
|
61
82
|
}
|
|
83
|
+
isPreviousElementTag = true;
|
|
62
84
|
}
|
|
63
|
-
|
|
85
|
+
|
|
64
86
|
return xmlStr;
|
|
65
87
|
}
|
|
66
88
|
|
|
67
|
-
function propName(obj){
|
|
89
|
+
function propName(obj) {
|
|
68
90
|
const keys = Object.keys(obj);
|
|
69
91
|
for (let i = 0; i < keys.length; i++) {
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
const key = keys[i];
|
|
93
|
+
if (key !== ":@") return key;
|
|
72
94
|
}
|
|
73
|
-
|
|
95
|
+
}
|
|
74
96
|
|
|
75
|
-
function attr_to_str(attrMap, options){
|
|
97
|
+
function attr_to_str(attrMap, options) {
|
|
76
98
|
let attrStr = "";
|
|
77
|
-
if(attrMap && !options.ignoreAttributes){
|
|
78
|
-
for (let attr in attrMap){
|
|
99
|
+
if (attrMap && !options.ignoreAttributes) {
|
|
100
|
+
for (let attr in attrMap) {
|
|
79
101
|
let attrVal = options.attributeValueProcessor(attr, attrMap[attr]);
|
|
80
102
|
attrVal = replaceEntitiesValue(attrVal, options);
|
|
81
|
-
if(attrVal === true && options.suppressBooleanAttributes){
|
|
82
|
-
attrStr+= ` ${attr.substr(options.attributeNamePrefix.length)}`;
|
|
83
|
-
}else{
|
|
84
|
-
attrStr+= ` ${attr.substr(options.attributeNamePrefix.length)}="${attrVal}"`;
|
|
103
|
+
if (attrVal === true && options.suppressBooleanAttributes) {
|
|
104
|
+
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`;
|
|
105
|
+
} else {
|
|
106
|
+
attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${attrVal}"`;
|
|
85
107
|
}
|
|
86
108
|
}
|
|
87
109
|
}
|
|
88
110
|
return attrStr;
|
|
89
111
|
}
|
|
90
112
|
|
|
91
|
-
function isStopNode(jPath, options){
|
|
92
|
-
jPath = jPath.substr(0,jPath.length - options.textNodeName.length - 1);
|
|
113
|
+
function isStopNode(jPath, options) {
|
|
114
|
+
jPath = jPath.substr(0, jPath.length - options.textNodeName.length - 1);
|
|
93
115
|
let tagName = jPath.substr(jPath.lastIndexOf(".") + 1);
|
|
94
|
-
for(let index in options.stopNodes){
|
|
95
|
-
if(options.stopNodes[index] === jPath || options.stopNodes[index] === "*."+tagName) return true;
|
|
116
|
+
for (let index in options.stopNodes) {
|
|
117
|
+
if (options.stopNodes[index] === jPath || options.stopNodes[index] === "*." + tagName) return true;
|
|
96
118
|
}
|
|
97
119
|
return false;
|
|
98
120
|
}
|
|
99
121
|
|
|
100
|
-
function replaceEntitiesValue(textValue, options){
|
|
101
|
-
if(textValue && textValue.length > 0 && options.processEntities){
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
122
|
+
function replaceEntitiesValue(textValue, options) {
|
|
123
|
+
if (textValue && textValue.length > 0 && options.processEntities) {
|
|
124
|
+
for (let i = 0; i < options.entities.length; i++) {
|
|
125
|
+
const entity = options.entities[i];
|
|
126
|
+
textValue = textValue.replace(entity.regex, entity.val);
|
|
127
|
+
}
|
|
106
128
|
}
|
|
107
129
|
return textValue;
|
|
108
|
-
|
|
109
|
-
module.exports = toXml;
|
|
130
|
+
}
|
|
131
|
+
module.exports = toXml;
|
|
@@ -132,8 +132,11 @@ function buildAttributesMap(attrStr, jPath) {
|
|
|
132
132
|
for (let i = 0; i < len; i++) {
|
|
133
133
|
const attrName = this.resolveNameSpace(matches[i][1]);
|
|
134
134
|
let oldVal = matches[i][4];
|
|
135
|
-
|
|
135
|
+
let aName = this.options.attributeNamePrefix + attrName;
|
|
136
136
|
if (attrName.length) {
|
|
137
|
+
if (this.options.transformAttributeName) {
|
|
138
|
+
aName = this.options.transformAttributeName(aName);
|
|
139
|
+
}
|
|
137
140
|
if (oldVal !== undefined) {
|
|
138
141
|
if (this.options.trimValues) {
|
|
139
142
|
oldVal = oldVal.trim();
|
|
@@ -261,7 +264,7 @@ const parseXml = function(xmlData) {
|
|
|
261
264
|
|
|
262
265
|
i = closeIndex + 2;
|
|
263
266
|
}else {//Opening tag
|
|
264
|
-
let result = readTagExp(xmlData,i, this.
|
|
267
|
+
let result = readTagExp(xmlData,i, this.options.removeNSPrefix);
|
|
265
268
|
let tagName= result.tagName;
|
|
266
269
|
let tagExp = result.tagExp;
|
|
267
270
|
let attrExpPresent = result.attrExpPresent;
|