fast-xml-parser 4.0.6 → 4.0.9
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 +16 -0
- package/README.md +11 -7
- package/package.json +1 -1
- package/src/fxp.d.ts +1 -0
- package/src/xmlbuilder/json2xml.js +26 -19
- package/src/xmlbuilder/orderedJs2Xml.js +4 -1
- package/src/xmlparser/DocTypeReader.js +25 -0
- package/src/xmlparser/OptionsBuilder.js +2 -1
- package/src/xmlparser/OrderedObjParser.js +48 -10
- package/src/xmlparser/node2json.js +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
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.9 / 2022-07-10**
|
|
4
|
+
* fix #470: stop-tag can have self-closing tag with same name
|
|
5
|
+
* fix #472: stopNode can have any special tag inside
|
|
6
|
+
* Allow !ATTLIST and !NOTATION with DOCTYPE
|
|
7
|
+
* Add transformTagName option to transform tag names when parsing (#469) (By [Erik Rothoff Andersson](https://github.com/erkie))
|
|
8
|
+
|
|
9
|
+
**4.0.8 / 2022-05-28**
|
|
10
|
+
* Fix CDATA parsing returning empty string when value = 0 (#451) (By [ndelanou](https://github.com/ndelanou))
|
|
11
|
+
* Fix stopNodes when same tag appears inside node (#456) (By [patrickshipe](https://github.com/patrickshipe))
|
|
12
|
+
* fix #468: prettify own properties only
|
|
13
|
+
|
|
14
|
+
**4.0.7 / 2022-03-18**
|
|
15
|
+
* support CDATA even if tag order is not preserved
|
|
16
|
+
* support Comments even if tag order is not preserved
|
|
17
|
+
* fix #446: XMLbuilder should not indent XML declaration
|
|
18
|
+
|
|
3
19
|
**4.0.6 / 2022-03-08**
|
|
4
20
|
* fix: call tagValueProcessor only once for array items
|
|
5
21
|
* fix: missing changed for #437
|
package/README.md
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
|
|
12
12
|
Validate XML, Parse XML to JS Object, or Build XML from JS Object without C/C++ based libraries and no callback.
|
|
13
13
|
|
|
14
|
+
> Looking for maintainers
|
|
15
|
+
|
|
14
16
|
<a href="https://opencollective.com/fast-xml-parser/donate" target="_blank">
|
|
15
17
|
<img src="https://opencollective.com/fast-xml-parser/donate/button@2x.png?color=blue" width=200 />
|
|
16
18
|
</a>
|
|
@@ -18,6 +20,8 @@ Validate XML, Parse XML to JS Object, or Build XML from JS Object without C/C++
|
|
|
18
20
|
|
|
19
21
|
Check [ThankYouBackers](https://github.com/NaturalIntelligence/ThankYouBackers) for our contributors
|
|
20
22
|
|
|
23
|
+
|
|
24
|
+
|
|
21
25
|
[](https://github.com/NaturalIntelligence/ads/)
|
|
22
26
|
## Users
|
|
23
27
|
|
|
@@ -100,12 +104,12 @@ In a HTML page
|
|
|
100
104
|
|
|
101
105
|
Check lib folder for different browser bundles
|
|
102
106
|
|
|
103
|
-
| Bundle Name
|
|
104
|
-
|
|
|
105
|
-
| fxbuilder.min.js
|
|
106
|
-
| fxparser.js
|
|
107
|
-
| fxparser.min.js
|
|
108
|
-
| fxp.min.js
|
|
107
|
+
| Bundle Name | Size |
|
|
108
|
+
| ------------------ | ---- |
|
|
109
|
+
| fxbuilder.min.js | 5.2K |
|
|
110
|
+
| fxparser.js | 50K |
|
|
111
|
+
| fxparser.min.js | 17K |
|
|
112
|
+
| fxp.min.js | 22K |
|
|
109
113
|
| fxvalidator.min.js | 5.7K |
|
|
110
114
|
|
|
111
115
|
### Documents
|
|
@@ -140,7 +144,7 @@ Check lib folder for different browser bundles
|
|
|
140
144
|
* **[BigBit standard](https://github.com/amitguptagwl/bigbit)** :
|
|
141
145
|
* Single text encoding to replace UTF-8, UTF-16, UTF-32 and more with less memory.
|
|
142
146
|
* Single Numeric datatype alternative of integer, float, double, long, decimal and more without precision loss.
|
|
143
|
-
* **[Cytorus](https://github.com/NaturalIntelligence/cytorus)**:
|
|
147
|
+
* **[Cytorus](https://github.com/NaturalIntelligence/cytorus)**: Be specific and flexible while running E2E tests.
|
|
144
148
|
* Run tests only for a particular User Story
|
|
145
149
|
* Run tests for a route or from a route
|
|
146
150
|
* Customizable reporting
|
package/package.json
CHANGED
package/src/fxp.d.ts
CHANGED
|
@@ -30,7 +30,8 @@ const defaultOptions = {
|
|
|
30
30
|
{ regex: new RegExp("\"", "g"), val: """ }
|
|
31
31
|
],
|
|
32
32
|
processEntities: true,
|
|
33
|
-
stopNodes: []
|
|
33
|
+
stopNodes: [],
|
|
34
|
+
transformTagName: false,
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
function Builder(options) {
|
|
@@ -172,11 +173,10 @@ function buildObjectNode(val, key, attrStr, level) {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
if (attrStr && val.indexOf('<') === -1) {
|
|
175
|
-
return (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
} else {
|
|
176
|
+
return ( this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' + val + tagEndExp );
|
|
177
|
+
} else if (this.options.commentPropName !== false && key === this.options.commentPropName && piClosingChar.length === 0) {
|
|
178
|
+
return this.indentate(level) + `<!--${val}-->` + this.newLine;
|
|
179
|
+
}else {
|
|
180
180
|
return (
|
|
181
181
|
this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar +
|
|
182
182
|
val +
|
|
@@ -194,20 +194,27 @@ function buildEmptyObjNode(val, key, attrStr, level) {
|
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
function buildTextValNode(val, key, attrStr, level) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if(this.options.suppressUnpairedNode){
|
|
202
|
-
return this.indentate(level) + '<' + key + this.tagEndChar;
|
|
203
|
-
}else{
|
|
204
|
-
return this.indentate(level) + '<' + key + "/" + this.tagEndChar;
|
|
205
|
-
}
|
|
197
|
+
if (this.options.cdataPropName !== false && key === this.options.cdataPropName) {
|
|
198
|
+
return this.indentate(level) + `<![CDATA[${val}]]>` + this.newLine;
|
|
199
|
+
}else if (this.options.commentPropName !== false && key === this.options.commentPropName) {
|
|
200
|
+
return this.indentate(level) + `<!--${val}-->` + this.newLine;
|
|
206
201
|
}else{
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
202
|
+
let textValue = this.options.tagValueProcessor(key, val);
|
|
203
|
+
textValue = this.replaceEntitiesValue(textValue);
|
|
204
|
+
|
|
205
|
+
if( textValue === '' && this.options.unpairedTags.indexOf(key) !== -1){ //unpaired
|
|
206
|
+
if(this.options.suppressUnpairedNode){
|
|
207
|
+
return this.indentate(level) + '<' + key + this.tagEndChar;
|
|
208
|
+
}else{
|
|
209
|
+
return this.indentate(level) + '<' + key + "/" + this.tagEndChar;
|
|
210
|
+
}
|
|
211
|
+
} else{
|
|
212
|
+
return (
|
|
213
|
+
this.indentate(level) + '<' + key + attrStr + '>' +
|
|
214
|
+
textValue +
|
|
215
|
+
'</' + key + this.tagEndChar );
|
|
216
|
+
}
|
|
217
|
+
|
|
211
218
|
}
|
|
212
219
|
}
|
|
213
220
|
|
|
@@ -41,7 +41,10 @@ function arrToStr(arr, options, jPath, level){
|
|
|
41
41
|
continue;
|
|
42
42
|
}else if( tagName[0] === "?"){
|
|
43
43
|
const attStr = attr_to_str(tagObj[":@"], options);
|
|
44
|
-
|
|
44
|
+
const tempInd = tagName === "?xml" ? "" : indentation;
|
|
45
|
+
let piTextNodeName = tagObj[tagName][0][options.textNodeName];
|
|
46
|
+
piTextNodeName = piTextNodeName.length !== 0 ? " " + piTextNodeName : ""; //remove extra spacing
|
|
47
|
+
xmlStr += tempInd + `<${tagName}${piTextNodeName}${attStr}?>`;
|
|
45
48
|
continue;
|
|
46
49
|
}
|
|
47
50
|
const attStr = attr_to_str(tagObj[":@"], options);
|
|
@@ -38,6 +38,31 @@ function readDocType(xmlData, i){
|
|
|
38
38
|
){
|
|
39
39
|
//Not supported
|
|
40
40
|
i += 8;
|
|
41
|
+
}else if( hasBody &&
|
|
42
|
+
xmlData[i+1] === '!' &&
|
|
43
|
+
xmlData[i+2] === 'A' &&
|
|
44
|
+
xmlData[i+3] === 'T' &&
|
|
45
|
+
xmlData[i+4] === 'T' &&
|
|
46
|
+
xmlData[i+5] === 'L' &&
|
|
47
|
+
xmlData[i+6] === 'I' &&
|
|
48
|
+
xmlData[i+7] === 'S' &&
|
|
49
|
+
xmlData[i+8] === 'T'
|
|
50
|
+
){
|
|
51
|
+
//Not supported
|
|
52
|
+
i += 8;
|
|
53
|
+
}else if( hasBody &&
|
|
54
|
+
xmlData[i+1] === '!' &&
|
|
55
|
+
xmlData[i+2] === 'N' &&
|
|
56
|
+
xmlData[i+3] === 'O' &&
|
|
57
|
+
xmlData[i+4] === 'T' &&
|
|
58
|
+
xmlData[i+5] === 'A' &&
|
|
59
|
+
xmlData[i+6] === 'T' &&
|
|
60
|
+
xmlData[i+7] === 'I' &&
|
|
61
|
+
xmlData[i+8] === 'O' &&
|
|
62
|
+
xmlData[i+9] === 'N'
|
|
63
|
+
){
|
|
64
|
+
//Not supported
|
|
65
|
+
i += 9;
|
|
41
66
|
}else if( //comment
|
|
42
67
|
xmlData[i+1] === '!' &&
|
|
43
68
|
xmlData[i+2] === '-' &&
|
|
@@ -193,6 +193,10 @@ const parseXml = function(xmlData) {
|
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
if(this.options.transformTagName) {
|
|
197
|
+
tagName = this.options.transformTagName(tagName);
|
|
198
|
+
}
|
|
199
|
+
|
|
196
200
|
if(currentNode){
|
|
197
201
|
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
198
202
|
}
|
|
@@ -251,18 +255,21 @@ const parseXml = function(xmlData) {
|
|
|
251
255
|
currentNode.add(this.options.cdataPropName, [ { [this.options.textNodeName] : tagExp } ]);
|
|
252
256
|
}else{
|
|
253
257
|
let val = this.parseTextData(tagExp, currentNode.tagname, jPath, true, false, true);
|
|
254
|
-
if(
|
|
258
|
+
if(val == undefined) val = "";
|
|
255
259
|
currentNode.add(this.options.textNodeName, val);
|
|
256
260
|
}
|
|
257
261
|
|
|
258
262
|
i = closeIndex + 2;
|
|
259
263
|
}else {//Opening tag
|
|
260
|
-
|
|
261
264
|
let result = readTagExp(xmlData,i, this. options.removeNSPrefix);
|
|
262
265
|
let tagName= result.tagName;
|
|
263
266
|
let tagExp = result.tagExp;
|
|
264
267
|
let attrExpPresent = result.attrExpPresent;
|
|
265
268
|
let closeIndex = result.closeIndex;
|
|
269
|
+
|
|
270
|
+
if (this.options.transformTagName) {
|
|
271
|
+
tagName = this.options.transformTagName(tagName);
|
|
272
|
+
}
|
|
266
273
|
|
|
267
274
|
//save text as child node
|
|
268
275
|
if (currentNode && textData) {
|
|
@@ -322,6 +329,10 @@ const parseXml = function(xmlData) {
|
|
|
322
329
|
}else{
|
|
323
330
|
tagExp = tagExp.substr(0, tagExp.length - 1);
|
|
324
331
|
}
|
|
332
|
+
|
|
333
|
+
if(this.options.transformTagName) {
|
|
334
|
+
tagName = this.options.transformTagName(tagName);
|
|
335
|
+
}
|
|
325
336
|
|
|
326
337
|
const childNode = new xmlNode(tagName);
|
|
327
338
|
if(tagName !== tagExp && attrExpPresent){
|
|
@@ -486,17 +497,44 @@ function readTagExp(xmlData,i, removeNSPrefix, closingChar = ">"){
|
|
|
486
497
|
*/
|
|
487
498
|
function readStopNodeData(xmlData, tagName, i){
|
|
488
499
|
const startIndex = i;
|
|
500
|
+
// Starting at 1 since we already have an open tag
|
|
501
|
+
let openTagCount = 1;
|
|
502
|
+
|
|
489
503
|
for (; i < xmlData.length; i++) {
|
|
490
|
-
if( xmlData[i] === "<"
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
504
|
+
if( xmlData[i] === "<"){
|
|
505
|
+
if (xmlData[i+1] === "/") {//close tag
|
|
506
|
+
const closeIndex = findClosingIndex(xmlData, ">", i, `${tagName} is not closed`);
|
|
507
|
+
let closeTagName = xmlData.substring(i+2,closeIndex).trim();
|
|
508
|
+
if(closeTagName === tagName){
|
|
509
|
+
openTagCount--;
|
|
510
|
+
if (openTagCount === 0) {
|
|
511
|
+
return {
|
|
512
|
+
tagContent: xmlData.substring(startIndex, i),
|
|
513
|
+
i : closeIndex
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
i=closeIndex;
|
|
518
|
+
} else if(xmlData[i+1] === '?') {
|
|
519
|
+
const closeIndex = findClosingIndex(xmlData, "?>", i+1, "StopNode is not closed.")
|
|
520
|
+
i=closeIndex;
|
|
521
|
+
} else if(xmlData.substr(i + 1, 3) === '!--') {
|
|
522
|
+
const closeIndex = findClosingIndex(xmlData, "-->", i+3, "StopNode is not closed.")
|
|
523
|
+
i=closeIndex;
|
|
524
|
+
} else if(xmlData.substr(i + 1, 2) === '![') {
|
|
525
|
+
const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2;
|
|
526
|
+
i=closeIndex;
|
|
527
|
+
} else {
|
|
528
|
+
const tagData = readTagExp(xmlData, i, '>')
|
|
529
|
+
|
|
530
|
+
if (tagData) {
|
|
531
|
+
const openTagName = tagData && tagData.tagName;
|
|
532
|
+
if (openTagName === tagName && tagData.tagExp[tagData.tagExp.length-1] !== "/") {
|
|
533
|
+
openTagCount++;
|
|
534
|
+
}
|
|
535
|
+
i=tagData.closeIndex;
|
|
497
536
|
}
|
|
498
537
|
}
|
|
499
|
-
i=closeIndex;
|
|
500
538
|
}
|
|
501
539
|
}//end for loop
|
|
502
540
|
}
|
|
@@ -46,9 +46,9 @@ function compress(arr, options, jPath){
|
|
|
46
46
|
else val = "";
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
if(compressedObj[property] !== undefined) {
|
|
49
|
+
if(compressedObj[property] !== undefined && compressedObj.hasOwnProperty(property)) {
|
|
50
50
|
if(!Array.isArray(compressedObj[property])) {
|
|
51
|
-
|
|
51
|
+
compressedObj[property] = [ compressedObj[property] ];
|
|
52
52
|
}
|
|
53
53
|
compressedObj[property].push(val);
|
|
54
54
|
}else{
|