• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NaturalIntelligence / fast-xml-parser / 4156981534

pending completion
4156981534

push

github

amit kumar gupta
Update package detail

692 of 741 branches covered (93.39%)

3 of 3 new or added lines in 2 files covered. (100.0%)

2376 of 2418 relevant lines covered (98.26%)

196233.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.67
/src/xmlbuilder/json2xml.js
1
'use strict';
2
//parse Empty Node as self closing node
3
const buildFromOrderedJs = require('./orderedJs2Xml');
1✔
4

5
const defaultOptions = {
1✔
6
  attributeNamePrefix: '@_',
7
  attributesGroupName: false,
8
  textNodeName: '#text',
9
  ignoreAttributes: true,
10
  cdataPropName: false,
11
  format: false,
12
  indentBy: '  ',
13
  suppressEmptyNode: false,
14
  suppressUnpairedNode: true,
15
  suppressBooleanAttributes: true,
16
  tagValueProcessor: function(key, a) {
17
    return a;
136✔
18
  },
19
  attributeValueProcessor: function(attrName, a) {
20
    return a;
81✔
21
  },
22
  preserveOrder: false,
23
  commentPropName: false,
24
  unpairedTags: [],
25
  entities: [
26
    { regex: new RegExp("&", "g"), val: "&" },//it must be on top
27
    { regex: new RegExp(">", "g"), val: ">" },
28
    { regex: new RegExp("<", "g"), val: "&lt;" },
29
    { regex: new RegExp("\'", "g"), val: "&apos;" },
30
    { regex: new RegExp("\"", "g"), val: "&quot;" }
31
  ],
32
  processEntities: true,
33
  stopNodes: [],
34
  // transformTagName: false,
35
  // transformAttributeName: false,
36
};
37

38
function Builder(options) {
39
  this.options = Object.assign({}, defaultOptions, options);
50✔
40
  if (this.options.ignoreAttributes || this.options.attributesGroupName) {
50✔
41
    this.isAttribute = function(/*a*/) {
22✔
42
      return false;
45✔
43
    };
44
  } else {
45
    this.attrPrefixLen = this.options.attributeNamePrefix.length;
28✔
46
    this.isAttribute = isAttribute;
28✔
47
  }
48

49
  this.processTextOrObjNode = processTextOrObjNode
50✔
50

51
  if (this.options.format) {
50✔
52
    this.indentate = indentate;
19✔
53
    this.tagEndChar = '>\n';
19✔
54
    this.newLine = '\n';
19✔
55
  } else {
56
    this.indentate = function() {
31✔
57
      return '';
127✔
58
    };
59
    this.tagEndChar = '>';
31✔
60
    this.newLine = '';
31✔
61
  }
62
}
63

64
Builder.prototype.build = function(jObj) {
1✔
65
  if(this.options.preserveOrder){
50✔
66
    return buildFromOrderedJs(jObj, this.options);
22✔
67
  }else {
68
    if(Array.isArray(jObj) && this.options.arrayNodeName && this.options.arrayNodeName.length > 1){
28✔
69
      jObj = {
1✔
70
        [this.options.arrayNodeName] : jObj
71
      }
72
    }
73
    return this.j2x(jObj, 0).val;
28✔
74
  }
75
};
76

77
Builder.prototype.j2x = function(jObj, level) {
1✔
78
  let attrStr = '';
99✔
79
  let val = '';
99✔
80
  for (let key in jObj) {
99✔
81
    if (typeof jObj[key] === 'undefined') {
175✔
82
      // supress undefined node
83
    } else if (jObj[key] === null) {
174✔
84
      if(key[0] === "?") val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
1!
85
      else val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
1✔
86
      // val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
87
    } else if (jObj[key] instanceof Date) {
173✔
88
      val += this.buildTextValNode(jObj[key], key, '', level);
2✔
89
    } else if (typeof jObj[key] !== 'object') {
171✔
90
      //premitive type
91
      const attr = this.isAttribute(key);
80✔
92
      if (attr) {
80✔
93
        attrStr += this.buildAttrPairStr(attr, '' + jObj[key]);
9✔
94
      }else {
95
        //tag value
96
        if (key === this.options.textNodeName) {
71✔
97
          let newval = this.options.tagValueProcessor(key, '' + jObj[key]);
19✔
98
          val += this.replaceEntitiesValue(newval);
19✔
99
        } else {
100
          val += this.buildTextValNode(jObj[key], key, '', level);
52✔
101
        }
102
      }
103
    } else if (Array.isArray(jObj[key])) {
91✔
104
      //repeated nodes
105
      const arrLen = jObj[key].length;
14✔
106
      for (let j = 0; j < arrLen; j++) {
14✔
107
        const item = jObj[key][j];
30✔
108
        if (typeof item === 'undefined') {
30✔
109
          // supress undefined node
110
        } else if (item === null) {
29!
111
          if(key[0] === "?") val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
×
112
          else val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
×
113
          // val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
114
        } else if (typeof item === 'object') {
29✔
115
          val += this.processTextOrObjNode(item, key, level)
10✔
116
        } else {
117
          val += this.buildTextValNode(item, key, '', level);
19✔
118
        }
119
      }
120
    } else {
121
      //nested node
122
      if (this.options.attributesGroupName && key === this.options.attributesGroupName) {
77✔
123
        const Ks = Object.keys(jObj[key]);
16✔
124
        const L = Ks.length;
16✔
125
        for (let j = 0; j < L; j++) {
16✔
126
          attrStr += this.buildAttrPairStr(Ks[j], '' + jObj[key][Ks[j]]);
26✔
127
        }
128
      } else {
129
        val += this.processTextOrObjNode(jObj[key], key, level)
61✔
130
      }
131
    }
132
  }
133
  return {attrStr: attrStr, val: val};
99✔
134
};
135

136
Builder.prototype.buildAttrPairStr = function(attrName, val){
1✔
137
  val = this.options.attributeValueProcessor(attrName, '' + val);
35✔
138
  val = this.replaceEntitiesValue(val);
35✔
139
  if (this.options.suppressBooleanAttributes && val === "true") {
35✔
140
    return ' ' + attrName;
3✔
141
  } else return ' ' + attrName + '="' + val + '"';
32✔
142
}
143

144
function processTextOrObjNode (object, key, level) {
145
  const result = this.j2x(object, level + 1);
71✔
146
  if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
71✔
147
    return this.buildTextValNode(object[this.options.textNodeName], key, result.attrStr, level);
5✔
148
  } else {
149
    return this.buildObjectNode(result.val, key, result.attrStr, level);
66✔
150
  }
151
}
152

153
Builder.prototype.buildObjectNode = function(val, key, attrStr, level) {
1✔
154
  if(val === ""){
66✔
155
    if(key[0] === "?") return  this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar;
10✔
156
    else {
157
      return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
8✔
158
    }
159
  }else{
160

161
    let tagEndExp = '</' + key + this.tagEndChar;
56✔
162
    let piClosingChar = "";
56✔
163
    
164
    if(key[0] === "?") {
56!
165
      piClosingChar = "?";
×
166
      tagEndExp = "";
×
167
    }
168
  
169
    if (attrStr && val.indexOf('<') === -1) {
56✔
170
      return ( this.indentate(level) + '<' +  key + attrStr + piClosingChar + '>' + val + tagEndExp );
5✔
171
    } else if (this.options.commentPropName !== false && key === this.options.commentPropName && piClosingChar.length === 0) {
51!
172
      return this.indentate(level) + `<!--${val}-->` + this.newLine;
×
173
    }else {
174
      return (
51✔
175
        this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar +
176
        val +
177
        this.indentate(level) + tagEndExp    );
178
    }
179
  }
180
}
181

182
Builder.prototype.closeTag = function(key){
1✔
183
  let closeTag = "";
21✔
184
  if(this.options.unpairedTags.indexOf(key) !== -1){ //unpaired
21✔
185
    if(!this.options.suppressUnpairedNode) closeTag = "/"
7✔
186
  }else if(this.options.suppressEmptyNode){ //empty
14✔
187
    closeTag = "/";
7✔
188
  }else{
189
    closeTag = `></${key}`
7✔
190
  }
191
  return closeTag;
21✔
192
}
193

194
function buildEmptyObjNode(val, key, attrStr, level) {
195
  if (val !== '') {
×
196
    return this.buildObjectNode(val, key, attrStr, level);
×
197
  } else {
198
    if(key[0] === "?") return  this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar;
×
199
    else {
200
      return  this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
×
201
      // return this.buildTagStr(level,key, attrStr);
202
    }
203
  }
204
}
205

206
Builder.prototype.buildTextValNode = function(val, key, attrStr, level) {
1✔
207
  if (this.options.cdataPropName !== false && key === this.options.cdataPropName) {
78✔
208
    return this.indentate(level) + `<![CDATA[${val}]]>` +  this.newLine;
4✔
209
  }else if (this.options.commentPropName !== false && key === this.options.commentPropName) {
74✔
210
    return this.indentate(level) + `<!--${val}-->` +  this.newLine;
4✔
211
  }else if(key[0] === "?") {//PI tag
70!
212
    return  this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar; 
×
213
  }else{
214
    let textValue = this.options.tagValueProcessor(key, val);
70✔
215
    textValue = this.replaceEntitiesValue(textValue);
70✔
216
  
217
    if( textValue === ''){
70✔
218
      return this.indentate(level) + '<' + key + attrStr + this.closeTag(key) + this.tagEndChar;
13✔
219
    }else{
220
      return this.indentate(level) + '<' + key + attrStr + '>' +
57✔
221
         textValue +
222
        '</' + key + this.tagEndChar;
223
    }
224
  }
225
}
226

227
Builder.prototype.replaceEntitiesValue = function(textValue){
1✔
228
  if(textValue && textValue.length > 0 && this.options.processEntities){
124✔
229
    for (let i=0; i<this.options.entities.length; i++) {
76✔
230
      const entity = this.options.entities[i];
380✔
231
      textValue = textValue.replace(entity.regex, entity.val);
380✔
232
    }
233
  }
234
  return textValue;
124✔
235
}
236

237
function indentate(level) {
238
  return this.options.indentBy.repeat(level);
69✔
239
}
240

241
function isAttribute(name /*, options*/) {
242
  if (name.startsWith(this.options.attributeNamePrefix)) {
35✔
243
    return name.substr(this.attrPrefixLen);
9✔
244
  } else {
245
    return false;
26✔
246
  }
247
}
248

249
module.exports = Builder;
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc