fast-xml-parser 3.17.4 → 3.19.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/LICENSE +0 -2
- package/README.md +9 -7
- package/package.json +10 -11
- package/src/node2json.js +18 -29
- package/src/parser.d.ts +1 -1
- package/src/parser.js +2 -2
- package/src/util.js +22 -2
- package/src/validator.js +12 -8
- package/src/xmlstr2xmlnode.js +5 -3
- package/tasks/postinstall.js +0 -5
- package/yarn.lock +0 -4953
package/LICENSE
CHANGED
|
@@ -9,8 +9,6 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
9
9
|
copies of the Software, and to permit persons to whom the Software is
|
|
10
10
|
furnished to do so, subject to the following conditions:
|
|
11
11
|
|
|
12
|
-
If you use this library in a public repository then you give us the right to mention your company name and logo in user's list without further permission required, but you can request them to be taken down within 30 days.
|
|
13
|
-
|
|
14
12
|
The above copyright notice and this permission notice shall be included in all
|
|
15
13
|
copies or substantial portions of the Software.
|
|
16
14
|
|
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
Validate XML, Parse XML to JS/JSON and vice versa, or parse XML to Nimn rapidly without C/C++ based libraries and no callback
|
|
16
16
|
|
|
17
|
+
To cover expenses, we're planning to launch [FXP Enterprise](https://github.com/NaturalIntelligence/fxp-ent) edition in parallel. Watch it for further updates, if you're interested.
|
|
18
|
+
|
|
17
19
|

|
|
18
20
|
|
|
19
21
|
<a href="https://opencollective.com/fast-xml-parser/donate" target="_blank">
|
|
@@ -81,8 +83,7 @@ List of some applications/projects using Fast XML Parser. (Raise an issue to sub
|
|
|
81
83
|
<a href="http://www.magento.com/" title="Magento" > <img src="https://avatars2.githubusercontent.com/u/168457" width="80px" ></a>
|
|
82
84
|
|
|
83
85
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
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.
|
|
86
87
|
|
|
87
88
|
### Main Features
|
|
88
89
|
|
|
@@ -191,7 +192,7 @@ Validator returns the following object in case of error;
|
|
|
191
192
|
* **cdataTagName** : If specified, parser parse CDATA as nested tag instead of adding it's value to parent tag.
|
|
192
193
|
* **cdataPositionChar** : It'll help to covert JSON back to XML without losing CDATA position.
|
|
193
194
|
* **parseTrueNumberOnly**: if true then values like "+123", or "0123" will not be parsed as number.
|
|
194
|
-
* **arrayMode** : When `false`, a tag with single occurrence is parsed as an object but as an array in case of multiple occurences. When `true`, a tag will be parsed as an array always excluding leaf nodes. When `strict`, all the tags will be parsed as array only.
|
|
195
|
+
* **arrayMode** : When `false`, a tag with single occurrence is parsed as an object but as an array in case of multiple occurences. When `true`, a tag will be parsed as an array always excluding leaf nodes. When `strict`, all the tags will be parsed as array only. When instance of `RegEx`, only tags will be parsed as array that match the regex. When `function` a tag name is passed to the callback that can be checked.
|
|
195
196
|
* **tagValueProcessor** : Process tag value during transformation. Like HTML decoding, word capitalization, etc. Applicable in case of string only.
|
|
196
197
|
* **attrValueProcessor** : Process attribute value during transformation. Like HTML decoding, word capitalization, etc. Applicable in case of string only.
|
|
197
198
|
* **stopNodes** : an array of tag names which are not required to be parsed. Instead their values are parsed as string.
|
|
@@ -301,9 +302,6 @@ With the correct options, you can get the almost original XML without losing any
|
|
|
301
302
|
|
|
302
303
|
</details>
|
|
303
304
|
|
|
304
|
-
### Limitations
|
|
305
|
-
Currently FXP fails to parse XML with attributes has ">" in the value. This problem is left open as change in regex for its fix is degrading the performance. And the parser become very slow in case of long attribute names. However, it is not ignored and we're working on the fix.
|
|
306
|
-
|
|
307
305
|
### Worth to mention
|
|
308
306
|
|
|
309
307
|
- **[BigBit standard)](https://github.com/amitguptagwl/bigbit)** : A standard to represent any number in the universe in comparatively less space and without precision loss. A standard to save memory to represent any text string in comparision of UTF encodings.
|
|
@@ -317,7 +315,7 @@ With the correct options, you can get the almost original XML without losing any
|
|
|
317
315
|
|
|
318
316
|
## Contributors
|
|
319
317
|
|
|
320
|
-
This project exists thanks to [all](graphs/contributors) the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
|
318
|
+
This project exists thanks to [all](graphs/contributors) the people who contribute. [[Contribute](docs/CONTRIBUTING.md)].
|
|
321
319
|
<!-- <a href="graphs/contributors"><img src="https://opencollective.com/fast-xml-parser/contributors.svg?width=890&button=false" /></a> -->
|
|
322
320
|
<!--
|
|
323
321
|
### Lead Maintainers
|
|
@@ -348,3 +346,7 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
|
|
|
348
346
|
<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>
|
|
349
347
|
<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>
|
|
350
348
|
<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>
|
|
349
|
+
|
|
350
|
+
# License
|
|
351
|
+
|
|
352
|
+
* MIT License
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-xml-parser",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.19.0",
|
|
4
4
|
"description": "Validate XML or Parse XML to JS/JSON very fast without C/C++ based libraries",
|
|
5
5
|
"main": "./src/parser.js",
|
|
6
6
|
"scripts": {
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
"bundle": "webpack && webpack --config webpack-prod.config.js",
|
|
12
12
|
"coverage": "istanbul cover -x \"cli.js\" -x \"spec/*spec.js\" jasmine spec/*spec.js;",
|
|
13
13
|
"coverage:check": "istanbul check-coverage --branch 90 --statement 90",
|
|
14
|
-
"postinstall": "node tasks/postinstall.js || exit 0",
|
|
15
14
|
"prettier": "prettier --write src/**/*.js",
|
|
16
15
|
"publish-please": "publish-please",
|
|
17
16
|
"prepublishOnly": "publish-please guard"
|
|
@@ -70,21 +69,21 @@
|
|
|
70
69
|
],
|
|
71
70
|
"license": "MIT",
|
|
72
71
|
"devDependencies": {
|
|
73
|
-
"@babel/core": "^7.10
|
|
74
|
-
"@babel/plugin-transform-runtime": "^7.10
|
|
75
|
-
"@babel/preset-env": "^7.10
|
|
76
|
-
"@babel/register": "^7.
|
|
77
|
-
"babel-loader": "^8.
|
|
72
|
+
"@babel/core": "^7.13.10",
|
|
73
|
+
"@babel/plugin-transform-runtime": "^7.13.10",
|
|
74
|
+
"@babel/preset-env": "^7.13.10",
|
|
75
|
+
"@babel/register": "^7.13.8",
|
|
76
|
+
"babel-loader": "^8.2.2",
|
|
78
77
|
"eslint": "^5.16.0",
|
|
79
78
|
"he": "^1.2.0",
|
|
80
79
|
"http-server": "^0.12.3",
|
|
81
80
|
"istanbul": "^0.4.5",
|
|
82
|
-
"jasmine": "^3.
|
|
81
|
+
"jasmine": "^3.6.4",
|
|
83
82
|
"nimnjs": "^1.3.2",
|
|
84
83
|
"prettier": "^1.19.1",
|
|
85
|
-
"publish-please": "^5.5.
|
|
86
|
-
"webpack": "^4.
|
|
87
|
-
"webpack-cli": "^3.3.
|
|
84
|
+
"publish-please": "^5.5.2",
|
|
85
|
+
"webpack": "^4.46.0",
|
|
86
|
+
"webpack-cli": "^3.3.12"
|
|
88
87
|
},
|
|
89
88
|
"typings": "src/parser.d.ts",
|
|
90
89
|
"funding": {
|
package/src/node2json.js
CHANGED
|
@@ -2,47 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
const util = require('./util');
|
|
4
4
|
|
|
5
|
-
const convertToJson = function(node, options) {
|
|
5
|
+
const convertToJson = function(node, options, parentTagName) {
|
|
6
6
|
const jObj = {};
|
|
7
7
|
|
|
8
|
-
//when no child node or attr is present
|
|
8
|
+
// when no child node or attr is present
|
|
9
9
|
if ((!node.child || util.isEmptyObject(node.child)) && (!node.attrsMap || util.isEmptyObject(node.attrsMap))) {
|
|
10
10
|
return util.isExist(node.val) ? node.val : '';
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}else{
|
|
18
|
-
jObj[options.textNodeName] = node.val;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// otherwise create a textnode if node has some text
|
|
14
|
+
if (util.isExist(node.val) && !(typeof node.val === 'string' && (node.val === '' || node.val === options.cdataPositionChar))) {
|
|
15
|
+
const asArray = util.isTagNameInArrayMode(node.tagname, options.arrayMode, parentTagName)
|
|
16
|
+
jObj[options.textNodeName] = asArray ? [node.val] : node.val;
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
util.merge(jObj, node.attrsMap, options.arrayMode);
|
|
25
20
|
|
|
26
21
|
const keys = Object.keys(node.child);
|
|
27
22
|
for (let index = 0; index < keys.length; index++) {
|
|
28
|
-
|
|
29
|
-
if (node.child[
|
|
30
|
-
jObj[
|
|
31
|
-
for (
|
|
32
|
-
|
|
23
|
+
const tagName = keys[index];
|
|
24
|
+
if (node.child[tagName] && node.child[tagName].length > 1) {
|
|
25
|
+
jObj[tagName] = [];
|
|
26
|
+
for (let tag in node.child[tagName]) {
|
|
27
|
+
if (node.child[tagName].hasOwnProperty(tag)) {
|
|
28
|
+
jObj[tagName].push(convertToJson(node.child[tagName][tag], options, tagName));
|
|
29
|
+
}
|
|
33
30
|
}
|
|
34
31
|
} else {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
jObj[tagname] = [ result ];
|
|
39
|
-
else
|
|
40
|
-
jObj[tagname] = result;
|
|
41
|
-
}else if(options.arrayMode === "strict"){
|
|
42
|
-
jObj[tagname] = [convertToJson(node.child[tagname][0], options) ];
|
|
43
|
-
}else{
|
|
44
|
-
jObj[tagname] = convertToJson(node.child[tagname][0], options);
|
|
45
|
-
}
|
|
32
|
+
const result = convertToJson(node.child[tagName][0], options, tagName);
|
|
33
|
+
const asArray = (options.arrayMode === true && typeof result === 'object') || util.isTagNameInArrayMode(tagName, options.arrayMode, parentTagName);
|
|
34
|
+
jObj[tagName] = asArray ? [result] : result;
|
|
46
35
|
}
|
|
47
36
|
}
|
|
48
37
|
|
package/src/parser.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ type X2jOptions = {
|
|
|
7
7
|
allowBooleanAttributes: boolean;
|
|
8
8
|
parseNodeValue: boolean;
|
|
9
9
|
parseAttributeValue: boolean;
|
|
10
|
-
arrayMode: boolean | 'strict';
|
|
10
|
+
arrayMode: boolean | 'strict' | RegExp | ((tagName: string, parentTagName: string) => boolean);
|
|
11
11
|
trimValues: boolean;
|
|
12
12
|
cdataTagName: false | string;
|
|
13
13
|
cdataPositionChar: string;
|
package/src/parser.js
CHANGED
|
@@ -20,7 +20,7 @@ exports.parse = function(xmlData, options, validationOption) {
|
|
|
20
20
|
//print(traversableObj, " ");
|
|
21
21
|
return nodeToJson.convertToJson(traversableObj, options);
|
|
22
22
|
};
|
|
23
|
-
exports.convertTonimn = require('
|
|
23
|
+
exports.convertTonimn = require('./nimndata').convert2nimn;
|
|
24
24
|
exports.getTraversalObj = xmlToNodeobj.getTraversalObj;
|
|
25
25
|
exports.convertToJson = nodeToJson.convertToJson;
|
|
26
26
|
exports.convertToJsonString = require('./node2json_str').convertToJsonString;
|
|
@@ -64,4 +64,4 @@ function print(xmlNode, indentation){
|
|
|
64
64
|
}
|
|
65
65
|
console.log(indentation + "},")
|
|
66
66
|
}
|
|
67
|
-
}
|
|
67
|
+
}
|
package/src/util.js
CHANGED
|
@@ -43,9 +43,9 @@ exports.merge = function(target, a, arrayMode) {
|
|
|
43
43
|
const keys = Object.keys(a); // will return an array of own properties
|
|
44
44
|
const len = keys.length; //don't make it inline
|
|
45
45
|
for (let i = 0; i < len; i++) {
|
|
46
|
-
if(arrayMode === 'strict'){
|
|
46
|
+
if (arrayMode === 'strict') {
|
|
47
47
|
target[keys[i]] = [ a[keys[i]] ];
|
|
48
|
-
}else{
|
|
48
|
+
} else {
|
|
49
49
|
target[keys[i]] = a[keys[i]];
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -82,6 +82,26 @@ exports.buildOptions = function(options, defaultOptions, props) {
|
|
|
82
82
|
return newOptions;
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Check if a tag name should be treated as array
|
|
87
|
+
*
|
|
88
|
+
* @param tagName the node tagname
|
|
89
|
+
* @param arrayMode the array mode option
|
|
90
|
+
* @param parentTagName the parent tag name
|
|
91
|
+
* @returns {boolean} true if node should be parsed as array
|
|
92
|
+
*/
|
|
93
|
+
exports.isTagNameInArrayMode = function (tagName, arrayMode, parentTagName) {
|
|
94
|
+
if (arrayMode === false) {
|
|
95
|
+
return false;
|
|
96
|
+
} else if (arrayMode instanceof RegExp) {
|
|
97
|
+
return arrayMode.test(tagName);
|
|
98
|
+
} else if (typeof arrayMode === 'function') {
|
|
99
|
+
return !!arrayMode(tagName, parentTagName);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return arrayMode === "strict";
|
|
103
|
+
}
|
|
104
|
+
|
|
85
105
|
exports.isName = isName;
|
|
86
106
|
exports.getAllMatches = getAllMatches;
|
|
87
107
|
exports.nameRegexp = nameRegexp;
|
package/src/validator.js
CHANGED
|
@@ -27,17 +27,18 @@ exports.validate = function (xmlData, options) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
for (let i = 0; i < xmlData.length; i++) {
|
|
30
|
-
|
|
30
|
+
|
|
31
|
+
if (xmlData[i] === '<' && xmlData[i+1] === '?') {
|
|
32
|
+
i+=2;
|
|
33
|
+
i = readPI(xmlData,i);
|
|
34
|
+
if (i.err) return i;
|
|
35
|
+
}else if (xmlData[i] === '<') {
|
|
31
36
|
//starting of tag
|
|
32
37
|
//read until you reach to '>' avoiding any '>' in attribute value
|
|
33
38
|
|
|
34
39
|
i++;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (i.err) {
|
|
38
|
-
return i;
|
|
39
|
-
}
|
|
40
|
-
} else if (xmlData[i] === '!') {
|
|
40
|
+
|
|
41
|
+
if (xmlData[i] === '!') {
|
|
41
42
|
i = readCommentAndCDATA(xmlData, i);
|
|
42
43
|
continue;
|
|
43
44
|
} else {
|
|
@@ -140,7 +141,10 @@ exports.validate = function (xmlData, options) {
|
|
|
140
141
|
i++;
|
|
141
142
|
i = readCommentAndCDATA(xmlData, i);
|
|
142
143
|
continue;
|
|
143
|
-
} else {
|
|
144
|
+
} else if (xmlData[i+1] === '?') {
|
|
145
|
+
i = readPI(xmlData, ++i);
|
|
146
|
+
if (i.err) return i;
|
|
147
|
+
} else{
|
|
144
148
|
break;
|
|
145
149
|
}
|
|
146
150
|
} else if (xmlData[i] === '&') {
|
package/src/xmlstr2xmlnode.js
CHANGED
|
@@ -168,7 +168,7 @@ function buildAttributesMap(attrStr, options) {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
const getTraversalObj = function(xmlData, options) {
|
|
171
|
-
xmlData = xmlData.replace(
|
|
171
|
+
xmlData = xmlData.replace(/\r\n?/g, "\n");
|
|
172
172
|
options = buildOptions(options, defaultOptions, props);
|
|
173
173
|
const xmlObj = new xmlNode('!xml');
|
|
174
174
|
let currentNode = xmlObj;
|
|
@@ -253,8 +253,9 @@ const getTraversalObj = function(xmlData, options) {
|
|
|
253
253
|
const closeIndex = result.index;
|
|
254
254
|
const separatorIndex = tagExp.indexOf(" ");
|
|
255
255
|
let tagName = tagExp;
|
|
256
|
+
let shouldBuildAttributesMap = true;
|
|
256
257
|
if(separatorIndex !== -1){
|
|
257
|
-
tagName = tagExp.substr(0, separatorIndex).
|
|
258
|
+
tagName = tagExp.substr(0, separatorIndex).replace(/\s\s*$/, '');
|
|
258
259
|
tagExp = tagExp.substr(separatorIndex + 1);
|
|
259
260
|
}
|
|
260
261
|
|
|
@@ -262,6 +263,7 @@ const getTraversalObj = function(xmlData, options) {
|
|
|
262
263
|
const colonIndex = tagName.indexOf(":");
|
|
263
264
|
if(colonIndex !== -1){
|
|
264
265
|
tagName = tagName.substr(colonIndex+1);
|
|
266
|
+
shouldBuildAttributesMap = tagName !== result.data.substr(colonIndex + 1);
|
|
265
267
|
}
|
|
266
268
|
}
|
|
267
269
|
|
|
@@ -292,7 +294,7 @@ const getTraversalObj = function(xmlData, options) {
|
|
|
292
294
|
if (options.stopNodes.length && options.stopNodes.includes(childNode.tagname)) {
|
|
293
295
|
childNode.startIndex=closeIndex;
|
|
294
296
|
}
|
|
295
|
-
if(tagName !== tagExp){
|
|
297
|
+
if(tagName !== tagExp && shouldBuildAttributesMap){
|
|
296
298
|
childNode.attrsMap = buildAttributesMap(tagExp, options);
|
|
297
299
|
}
|
|
298
300
|
currentNode.addChild(childNode);
|