fast-xml-parser 4.0.1 → 4.0.2

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 CHANGED
@@ -1,5 +1,11 @@
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.2 / 2022-02-04**
4
+ * builder supports `suppressUnpairedNode`
5
+ * parser supports `ignoreDeclaration` and `ignorePiTags`
6
+ * fix: when comment is parsed as text value if given as `<!--> ...` #423
7
+ * builder supports decoding `&`
8
+
3
9
  **4.0.1 / 2022-01-08**
4
10
  * fix builder for pi tag
5
11
  * fix: support suppressBooleanAttrs by builder
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fast-xml-parser",
3
- "version": "4.0.1",
3
+ "version": "4.0.2",
4
4
  "description": "Validate XML, Parse XML, Build XML without C/C++ based libraries",
5
5
  "main": "./src/fxp.js",
6
6
  "scripts": {
package/src/fxp.d.ts CHANGED
@@ -20,6 +20,8 @@ type X2jOptions = {
20
20
  isArray: (tagName: string, jPath: string, isLeafNode: boolean, isAttribute: boolean) => boolean;
21
21
  processEntities: boolean;
22
22
  htmlEntities: boolean;
23
+ ignoreDeclaration: boolean;
24
+ ignorePiTags: boolean;
23
25
  };
24
26
  type strnumOptions = {
25
27
  hex: boolean;
@@ -44,6 +46,7 @@ type XmlBuilderOptions = {
44
46
  indentBy: string;
45
47
  arrayNodeName: string;
46
48
  suppressEmptyNode: boolean;
49
+ suppressUnpairedNode: boolean;
47
50
  suppressBooleanAttributes: boolean;
48
51
  preserveOrder: boolean;
49
52
  unpairedTags: string[];
@@ -11,6 +11,7 @@ const defaultOptions = {
11
11
  format: false,
12
12
  indentBy: ' ',
13
13
  suppressEmptyNode: false,
14
+ suppressUnpairedNode: true,
14
15
  suppressBooleanAttributes: true,
15
16
  tagValueProcessor: function(key, a) {
16
17
  return a;
@@ -21,12 +22,13 @@ const defaultOptions = {
21
22
  preserveOrder: false,
22
23
  commentPropName: false,
23
24
  unpairedTags: [],
24
- entities: {
25
- ">" : { regex: new RegExp(">", "g"), val: "&gt;" },
26
- "<" : { regex: new RegExp("<", "g"), val: "&lt;" },
27
- "sQuot" : { regex: new RegExp("\'", "g"), val: "&apos;" },
28
- "dQuot" : { regex: new RegExp("\"", "g"), val: "&quot;" }
29
- },
25
+ entities: [
26
+ { regex: new RegExp("&", "g"), val: "&amp;" },//it must be on top
27
+ { regex: new RegExp(">", "g"), val: "&gt;" },
28
+ { regex: new RegExp("<", "g"), val: "&lt;" },
29
+ { regex: new RegExp("\'", "g"), val: "&apos;" },
30
+ { regex: new RegExp("\"", "g"), val: "&quot;" }
31
+ ],
30
32
  processEntities: true,
31
33
  stopNodes: []
32
34
  };
@@ -192,19 +194,26 @@ function buildEmptyObjNode(val, key, attrStr, level) {
192
194
  }
193
195
 
194
196
  function buildTextValNode(val, key, attrStr, level) {
195
- let textValue = this.options.tagValueProcessor(key, val);
196
- textValue = this.replaceEntitiesValue(textValue);
197
-
198
- return (
199
- this.indentate(level) + '<' + key + attrStr + '>' +
200
- textValue +
201
- '</' + key + this.tagEndChar );
197
+ const textValue = this.replaceEntitiesValue(val);
198
+
199
+ if( textValue === '' && this.options.unpairedTags.indexOf(key) !== -1){ //unpaired
200
+ if(this.options.suppressUnpairedNode){
201
+ return this.indentate(level) + '<' + key + this.tagEndChar;
202
+ }else{
203
+ return this.indentate(level) + '<' + key + "/" + this.tagEndChar;
204
+ }
205
+ }else{
206
+ return (
207
+ this.indentate(level) + '<' + key + attrStr + '>' +
208
+ textValue +
209
+ '</' + key + this.tagEndChar );
210
+ }
202
211
  }
203
212
 
204
213
  function replaceEntitiesValue(textValue){
205
214
  if(textValue && textValue.length > 0 && this.options.processEntities){
206
- for (const entityName in this.options.entities) {
207
- const entity = this.options.entities[entityName];
215
+ for (let i=0; i<this.options.entities.length; i++) {
216
+ const entity = this.options.entities[i];
208
217
  textValue = textValue.replace(entity.regex, entity.val);
209
218
  }
210
219
  }
@@ -212,13 +221,17 @@ function replaceEntitiesValue(textValue){
212
221
  }
213
222
 
214
223
  function buildEmptyTextNode(val, key, attrStr, level) {
215
- if( val === '' && this.options.unpairedTags.indexOf(key) !== -1){
216
- return this.indentate(level) + '<' + key + attrStr + this.tagEndChar;
217
- }else if (val !== '') {
224
+ if( val === '' && this.options.unpairedTags.indexOf(key) !== -1){ //unpaired
225
+ if(this.options.suppressUnpairedNode){
226
+ return this.indentate(level) + '<' + key + this.tagEndChar;
227
+ }else{
228
+ return this.indentate(level) + '<' + key + "/" + this.tagEndChar;
229
+ }
230
+ }else if (val !== '') { //empty
218
231
  return this.buildTextValNode(val, key, attrStr, level);
219
232
  } else {
220
- if(key[0] === "?") return this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar;
221
- else return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
233
+ if(key[0] === "?") return this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar; //PI tag
234
+ else return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar; //normal
222
235
  }
223
236
  }
224
237
 
@@ -48,7 +48,8 @@ function arrToStr(arr, options, jPath, level){
48
48
  let tagStart = indentation + `<${tagName}${attStr}`;
49
49
  let tagValue = arrToStr(tagObj[tagName], options, newJPath, level + 1);
50
50
  if(options.unpairedTags.indexOf(tagName) !== -1){
51
- xmlStr += tagStart + ">";
51
+ if(options.suppressUnpairedNode) xmlStr += tagStart + ">";
52
+ else xmlStr += tagStart + "/>";
52
53
  }else if( (!tagValue || tagValue.length === 0) && options.suppressEmptyNode){
53
54
  xmlStr += tagStart + "/>";
54
55
  }else{
@@ -95,8 +96,8 @@ function isStopNode(jPath, options){
95
96
 
96
97
  function replaceEntitiesValue(textValue, options){
97
98
  if(textValue && textValue.length > 0 && options.processEntities){
98
- for (const entityName in options.entities) {
99
- const entity = options.entities[entityName];
99
+ for (let i=0; i< options.entities.length; i++) {
100
+ const entity = options.entities[i];
100
101
  textValue = textValue.replace(entity.regex, entity.val);
101
102
  }
102
103
  }
@@ -29,6 +29,8 @@ const defaultOptions = {
29
29
  unpairedTags: [],
30
30
  processEntities: true,
31
31
  htmlEntities: false,
32
+ ignoreDeclaration: false,
33
+ ignorePiTags: false
32
34
  };
33
35
 
34
36
  const buildOptions = function(options) {
@@ -203,21 +203,29 @@ const parseXml = function(xmlData) {
203
203
  textData = "";
204
204
  i = closeIndex;
205
205
  } else if( xmlData[i+1] === '?') {
206
+
206
207
  let tagData = readTagExp(xmlData,i, false, "?>");
207
208
  if(!tagData) throw new Error("Pi Tag is not closed.");
209
+
208
210
  textData = this.saveTextToParentTag(textData, currentNode, jPath);
211
+ if( (this.options.ignoreDeclaration && tagData.tagName === "?xml") || this.options.ignorePiTags){
212
+
213
+ }else{
214
+
215
+ const childNode = new xmlNode(tagData.tagName);
216
+ childNode.add(this.options.textNodeName, "");
217
+
218
+ if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
219
+ childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath);
220
+ }
221
+ currentNode.addChild(childNode);
209
222
 
210
- const childNode = new xmlNode(tagData.tagName);
211
- childNode.add(this.options.textNodeName, "");
212
-
213
- if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
214
- childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath);
215
223
  }
216
- currentNode.addChild(childNode);
224
+
217
225
 
218
226
  i = tagData.closeIndex + 1;
219
227
  } else if(xmlData.substr(i + 1, 3) === '!--') {
220
- const endIndex = findClosingIndex(xmlData, "-->", i, "Comment is not closed.")
228
+ const endIndex = findClosingIndex(xmlData, "-->", i+4, "Comment is not closed.")
221
229
  if(this.options.commentPropName){
222
230
  const comment = xmlData.substring(i + 4, endIndex - 2);
223
231