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 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
  ![Donate $5](static/img/donation_quote.png)
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.17.4",
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.2",
74
- "@babel/plugin-transform-runtime": "^7.10.1",
75
- "@babel/preset-env": "^7.10.2",
76
- "@babel/register": "^7.10.1",
77
- "babel-loader": "^8.1.0",
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.5.0",
81
+ "jasmine": "^3.6.4",
83
82
  "nimnjs": "^1.3.2",
84
83
  "prettier": "^1.19.1",
85
- "publish-please": "^5.5.1",
86
- "webpack": "^4.43.0",
87
- "webpack-cli": "^3.3.11"
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
- } else {
12
- //otherwise create a textnode if node has some text
13
- if (util.isExist(node.val)) {
14
- if (!(typeof node.val === 'string' && (node.val === '' || node.val === options.cdataPositionChar))) {
15
- if(options.arrayMode === "strict"){
16
- jObj[options.textNodeName] = [ node.val ];
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
- var tagname = keys[index];
29
- if (node.child[tagname] && node.child[tagname].length > 1) {
30
- jObj[tagname] = [];
31
- for (var tag in node.child[tagname]) {
32
- jObj[tagname].push(convertToJson(node.child[tagname][tag], options));
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
- if(options.arrayMode === true){
36
- const result = convertToJson(node.child[tagname][0], options)
37
- if(typeof result === 'object')
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('../src/nimndata').convert2nimn;
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
- if (xmlData[i] === '<') {
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
- if (xmlData[i] === '?') {
36
- i = readPI(xmlData, ++i);
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] === '&') {
@@ -168,7 +168,7 @@ function buildAttributesMap(attrStr, options) {
168
168
  }
169
169
 
170
170
  const getTraversalObj = function(xmlData, options) {
171
- xmlData = xmlData.replace(/(\r\n)|\n/, " ");
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).trimRight();
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);
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
-
4
- const msg = '\u001b[96m\u001b[1mLove fast-xml-parser? Check \u001b[32mhttps://amitkumargupta.work \u001b[96m\u001b[1mfor more projects and contribution.\u001b[0m\n';
5
- console.log(msg)