fast-xml-parser 4.0.0-beta.7 → 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 +22 -5
- package/README.md +15 -5
- package/package.json +3 -2
- package/src/fxp.d.ts +3 -0
- package/src/fxp_cjs +8 -0
- package/src/xmlbuilder/json2xml.js +64 -58
- package/src/xmlbuilder/orderedJs2Xml.js +5 -4
- package/src/xmlparser/OptionsBuilder.js +2 -0
- package/src/xmlparser/OrderedObjParser.js +28 -27
package/CHANGELOG.md
CHANGED
|
@@ -1,26 +1,43 @@
|
|
|
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
|
-
**
|
|
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
|
+
|
|
9
|
+
**4.0.1 / 2022-01-08**
|
|
10
|
+
* fix builder for pi tag
|
|
11
|
+
* fix: support suppressBooleanAttrs by builder
|
|
12
|
+
|
|
13
|
+
**4.0.0 / 2022-01-06**
|
|
14
|
+
* Generating different combined, parser only, builder only, validator only browser bundles
|
|
15
|
+
* Keeping cjs modules as they can be imported in cjs and esm modules both. Otherwise refer `esm` branch.
|
|
16
|
+
|
|
17
|
+
**4.0.0-beta.8 / 2021-12-13**
|
|
18
|
+
* call tagValueProcessor for stop nodes
|
|
19
|
+
|
|
20
|
+
**4.0.0-beta.7 / 2021-12-09**
|
|
4
21
|
* fix Validator bug when an attribute has no value but '=' only
|
|
5
22
|
* XML Builder should suppress unpaired tags by default.
|
|
6
23
|
* documents update for missing features
|
|
7
24
|
* refactoring to use Object.assign
|
|
8
25
|
* refactoring to remove repeated code
|
|
9
26
|
|
|
10
|
-
**
|
|
27
|
+
**4.0.0-beta.6 / 2021-12-05**
|
|
11
28
|
* Support PI Tags processing
|
|
12
29
|
* Support `suppressBooleanAttributes` by XML Builder for attributes with value `true`.
|
|
13
30
|
|
|
14
|
-
**
|
|
31
|
+
**4.0.0-beta.5 / 2021-12-04**
|
|
15
32
|
* fix: when a tag with name "attributes"
|
|
16
33
|
|
|
17
|
-
**
|
|
34
|
+
**4.0.0-beta.4 / 2021-12-02**
|
|
18
35
|
* Support HTML document parsing
|
|
19
36
|
* skip stop nodes parsing when building the XML from JS object
|
|
20
37
|
* Support external entites without DOCTYPE
|
|
21
38
|
* update dev dependency: strnum v1.0.5 to fix long number issue
|
|
22
39
|
|
|
23
|
-
**
|
|
40
|
+
**4.0.0-beta.3 / 2021-11-30**
|
|
24
41
|
* support global stopNodes expression like "*.stop"
|
|
25
42
|
* support self-closing and paired unpaired tags
|
|
26
43
|
* fix: CDATA should not be parsed.
|
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# [fast-xml-parser](https://www.npmjs.com/package/fast-xml-parser)
|
|
2
2
|
[](#backers) [](#sponsors) [](https://snyk.io/test/github/naturalintelligence/fast-xml-parser)
|
|
3
3
|
[![NPM quality][quality-image]][quality-url]
|
|
4
|
-
[](https://travis-ci.org/NaturalIntelligence/fast-xml-parser)
|
|
5
4
|
[](https://coveralls.io/github/NaturalIntelligence/fast-xml-parser?branch=master)
|
|
6
5
|
[<img src="https://img.shields.io/badge/Try-me-blue.svg?colorA=FFA500&colorB=0000FF" alt="Try me"/>](https://naturalintelligence.github.io/fast-xml-parser/)
|
|
7
6
|
[](https://npm.im/fast-xml-parser)
|
|
@@ -90,7 +89,7 @@ const xmlContent = builder.build(jObj);
|
|
|
90
89
|
|
|
91
90
|
In a HTML page
|
|
92
91
|
```html
|
|
93
|
-
<script src="path/to/
|
|
92
|
+
<script src="path/to/fxp.min.js"></script>
|
|
94
93
|
:
|
|
95
94
|
<script>
|
|
96
95
|
const parser = new fxparser.XMLParser();
|
|
@@ -98,6 +97,16 @@ In a HTML page
|
|
|
98
97
|
</script>
|
|
99
98
|
```
|
|
100
99
|
|
|
100
|
+
Check lib folder for different browser bundles
|
|
101
|
+
|
|
102
|
+
| Bundle Name | Size |
|
|
103
|
+
| -- | -- |
|
|
104
|
+
| fxbuilder.min.js | 5.2K |
|
|
105
|
+
| fxparser.js | 50K |
|
|
106
|
+
| fxparser.min.js | 17K |
|
|
107
|
+
| fxp.min.js | 22K |
|
|
108
|
+
| fxvalidator.min.js | 5.7K |
|
|
109
|
+
|
|
101
110
|
### Documents
|
|
102
111
|
**v3**
|
|
103
112
|
* [documents](./docs/v3/docs.md)
|
|
@@ -107,9 +116,9 @@ In a HTML page
|
|
|
107
116
|
2. [XML Parser](./docs/v4/2.XMLparseOptions.md)
|
|
108
117
|
3. [XML Builder](./docs/v4/3.XMLBuilder.md)
|
|
109
118
|
4. [XML Validator](./docs/v4/4.XMLValidator.md)
|
|
110
|
-
5. [Entites](./docs/5.Entities.md)
|
|
111
|
-
6. [HTML Document Parsing](./docs/6.HTMLParsing.md)
|
|
112
|
-
7. [PI Tag processing](./docs/7.PITags.md)
|
|
119
|
+
5. [Entites](./docs/v4/5.Entities.md)
|
|
120
|
+
6. [HTML Document Parsing](./docs/v4/6.HTMLParsing.md)
|
|
121
|
+
7. [PI Tag processing](./docs/v4/7.PITags.md)
|
|
113
122
|
## Performance
|
|
114
123
|
|
|
115
124
|
### XML Parser
|
|
@@ -135,6 +144,7 @@ In a HTML page
|
|
|
135
144
|
* Run tests for a route or from a route
|
|
136
145
|
* Customizable reporting
|
|
137
146
|
* Central dashboard for better monitoring
|
|
147
|
+
* Options to integrate E2E tests with Jira, Github etc using Central dashboard `Tian`.
|
|
138
148
|
* **[Stubmatic](https://github.com/NaturalIntelligence/Stubmatic)** : Create fake webservices, DynamoDB or S3 servers, Manage fake/mock stub data, Or fake any HTTP(s) call.
|
|
139
149
|
|
|
140
150
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fast-xml-parser",
|
|
3
|
-
"version": "4.0.
|
|
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": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"coverage": "nyc report --reporter html --reporter text -t .nyc_output --report-dir .nyc_output/summary",
|
|
10
10
|
"perf": "node ./benchmark/perfTest3.js",
|
|
11
11
|
"lint": "eslint src/*.js spec/*.js",
|
|
12
|
-
"bundle": "webpack
|
|
12
|
+
"bundle": "webpack --config webpack-prod.config.js",
|
|
13
13
|
"prettier": "prettier --write src/**/*.js",
|
|
14
14
|
"publish-please": "publish-please",
|
|
15
15
|
"checkReadiness": "publish-please --dry-run"
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
"@babel/preset-env": "^7.13.10",
|
|
48
48
|
"@babel/register": "^7.13.8",
|
|
49
49
|
"babel-loader": "^8.2.2",
|
|
50
|
+
"cytorus": "^0.2.9",
|
|
50
51
|
"eslint": "^8.3.0",
|
|
51
52
|
"he": "^1.2.0",
|
|
52
53
|
"jasmine": "^3.6.4",
|
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[];
|
package/src/fxp_cjs
ADDED
|
@@ -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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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: "<" },
|
|
29
|
+
{ regex: new RegExp("\'", "g"), val: "'" },
|
|
30
|
+
{ regex: new RegExp("\"", "g"), val: """ }
|
|
31
|
+
],
|
|
30
32
|
processEntities: true,
|
|
31
33
|
stopNodes: []
|
|
32
34
|
};
|
|
@@ -68,6 +70,7 @@ function Builder(options) {
|
|
|
68
70
|
this.buildObjectNode = buildObjectNode;
|
|
69
71
|
|
|
70
72
|
this.replaceEntitiesValue = replaceEntitiesValue;
|
|
73
|
+
this.buildAttrPairStr = buildAttrPairStr;
|
|
71
74
|
}
|
|
72
75
|
|
|
73
76
|
Builder.prototype.build = function(jObj) {
|
|
@@ -90,16 +93,16 @@ Builder.prototype.j2x = function(jObj, level) {
|
|
|
90
93
|
if (typeof jObj[key] === 'undefined') {
|
|
91
94
|
// supress undefined node
|
|
92
95
|
} else if (jObj[key] === null) {
|
|
93
|
-
val += this.indentate(level) + '<' + key + '
|
|
96
|
+
if(key[0] === "?") val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
|
|
97
|
+
else val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
|
98
|
+
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
|
94
99
|
} else if (jObj[key] instanceof Date) {
|
|
95
100
|
val += this.buildTextNode(jObj[key], key, '', level);
|
|
96
101
|
} else if (typeof jObj[key] !== 'object') {
|
|
97
102
|
//premitive type
|
|
98
103
|
const attr = this.isAttribute(key);
|
|
99
104
|
if (attr) {
|
|
100
|
-
|
|
101
|
-
val = this.replaceEntitiesValue(val);
|
|
102
|
-
attrStr += ' ' + attr + '="' + val + '"';
|
|
105
|
+
attrStr += this.buildAttrPairStr(attr, '' + jObj[key]);
|
|
103
106
|
}else {
|
|
104
107
|
//tag value
|
|
105
108
|
if (key === this.options.textNodeName) {
|
|
@@ -117,7 +120,9 @@ Builder.prototype.j2x = function(jObj, level) {
|
|
|
117
120
|
if (typeof item === 'undefined') {
|
|
118
121
|
// supress undefined node
|
|
119
122
|
} else if (item === null) {
|
|
120
|
-
val += this.indentate(level) + '<' + key + '
|
|
123
|
+
if(key[0] === "?") val += this.indentate(level) + '<' + key + '?' + this.tagEndChar;
|
|
124
|
+
else val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
|
125
|
+
// val += this.indentate(level) + '<' + key + '/' + this.tagEndChar;
|
|
121
126
|
} else if (typeof item === 'object') {
|
|
122
127
|
val += this.processTextOrObjNode(item, key, level)
|
|
123
128
|
} else {
|
|
@@ -130,9 +135,7 @@ Builder.prototype.j2x = function(jObj, level) {
|
|
|
130
135
|
const Ks = Object.keys(jObj[key]);
|
|
131
136
|
const L = Ks.length;
|
|
132
137
|
for (let j = 0; j < L; j++) {
|
|
133
|
-
|
|
134
|
-
val = this.replaceEntitiesValue(val);
|
|
135
|
-
attrStr += ' ' + Ks[j] + '="' + val + '"';
|
|
138
|
+
attrStr += this.buildAttrPairStr(Ks[j], '' + jObj[key][Ks[j]]);
|
|
136
139
|
}
|
|
137
140
|
} else {
|
|
138
141
|
val += this.processTextOrObjNode(jObj[key], key, level)
|
|
@@ -142,6 +145,14 @@ Builder.prototype.j2x = function(jObj, level) {
|
|
|
142
145
|
return {attrStr: attrStr, val: val};
|
|
143
146
|
};
|
|
144
147
|
|
|
148
|
+
function buildAttrPairStr(attrName, val){
|
|
149
|
+
val = this.options.attributeValueProcessor(attrName, '' + val);
|
|
150
|
+
val = this.replaceEntitiesValue(val);
|
|
151
|
+
if (this.options.suppressBooleanAttributes && val === "true") {
|
|
152
|
+
return ' ' + attrName;
|
|
153
|
+
} else return ' ' + attrName + '="' + val + '"';
|
|
154
|
+
}
|
|
155
|
+
|
|
145
156
|
function processTextOrObjNode (object, key, level) {
|
|
146
157
|
const result = this.j2x(object, level + 1);
|
|
147
158
|
if (object[this.options.textNodeName] !== undefined && Object.keys(object).length === 1) {
|
|
@@ -152,34 +163,24 @@ function processTextOrObjNode (object, key, level) {
|
|
|
152
163
|
}
|
|
153
164
|
|
|
154
165
|
function buildObjectNode(val, key, attrStr, level) {
|
|
166
|
+
let tagEndExp = '</' + key + this.tagEndChar;
|
|
167
|
+
let piClosingChar = "";
|
|
168
|
+
|
|
169
|
+
if(key[0] === "?") {
|
|
170
|
+
piClosingChar = "?";
|
|
171
|
+
tagEndExp = "";
|
|
172
|
+
}
|
|
173
|
+
|
|
155
174
|
if (attrStr && val.indexOf('<') === -1) {
|
|
156
175
|
return (
|
|
157
|
-
this.indentate(level) +
|
|
158
|
-
'<' +
|
|
159
|
-
key +
|
|
160
|
-
attrStr +
|
|
161
|
-
'>' +
|
|
176
|
+
this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' +
|
|
162
177
|
val +
|
|
163
|
-
|
|
164
|
-
// + this.indentate(level)
|
|
165
|
-
'</' +
|
|
166
|
-
key +
|
|
167
|
-
this.tagEndChar
|
|
168
|
-
);
|
|
178
|
+
tagEndExp );
|
|
169
179
|
} else {
|
|
170
180
|
return (
|
|
171
|
-
this.indentate(level) +
|
|
172
|
-
'<' +
|
|
173
|
-
key +
|
|
174
|
-
attrStr +
|
|
175
|
-
this.tagEndChar +
|
|
181
|
+
this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar +
|
|
176
182
|
val +
|
|
177
|
-
|
|
178
|
-
this.indentate(level) +
|
|
179
|
-
'</' +
|
|
180
|
-
key +
|
|
181
|
-
this.tagEndChar
|
|
182
|
-
);
|
|
183
|
+
this.indentate(level) + tagEndExp );
|
|
183
184
|
}
|
|
184
185
|
}
|
|
185
186
|
|
|
@@ -187,32 +188,32 @@ function buildEmptyObjNode(val, key, attrStr, level) {
|
|
|
187
188
|
if (val !== '') {
|
|
188
189
|
return this.buildObjectNode(val, key, attrStr, level);
|
|
189
190
|
} else {
|
|
190
|
-
return
|
|
191
|
-
|
|
191
|
+
if(key[0] === "?") return this.indentate(level) + '<' + key + attrStr+ '?' + this.tagEndChar;
|
|
192
|
+
else return this.indentate(level) + '<' + key + attrStr + '/' + this.tagEndChar;
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
function buildTextValNode(val, key, attrStr, level) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
+
}
|
|
210
211
|
}
|
|
211
212
|
|
|
212
213
|
function replaceEntitiesValue(textValue){
|
|
213
214
|
if(textValue && textValue.length > 0 && this.options.processEntities){
|
|
214
|
-
for (
|
|
215
|
-
const entity = this.options.entities[
|
|
215
|
+
for (let i=0; i<this.options.entities.length; i++) {
|
|
216
|
+
const entity = this.options.entities[i];
|
|
216
217
|
textValue = textValue.replace(entity.regex, entity.val);
|
|
217
218
|
}
|
|
218
219
|
}
|
|
@@ -220,12 +221,17 @@ function replaceEntitiesValue(textValue){
|
|
|
220
221
|
}
|
|
221
222
|
|
|
222
223
|
function buildEmptyTextNode(val, key, attrStr, level) {
|
|
223
|
-
if( val === '' && this.options.unpairedTags.indexOf(key) !== -1){
|
|
224
|
-
|
|
225
|
-
|
|
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
|
|
226
231
|
return this.buildTextValNode(val, key, attrStr, level);
|
|
227
232
|
} else {
|
|
228
|
-
return
|
|
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
|
|
229
235
|
}
|
|
230
236
|
}
|
|
231
237
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const EOL = "\n";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
*
|
|
@@ -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 (
|
|
99
|
-
const entity = options.entities[
|
|
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
|
}
|
|
@@ -72,14 +72,15 @@ function addExternalEntities(externalEntities){
|
|
|
72
72
|
* @param {boolean} dontTrim
|
|
73
73
|
* @param {boolean} hasAttributes
|
|
74
74
|
* @param {boolean} isLeafNode
|
|
75
|
+
* @param {boolean} escapeEntities
|
|
75
76
|
*/
|
|
76
|
-
function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode) {
|
|
77
|
+
function parseTextData(val, tagName, jPath, dontTrim, hasAttributes, isLeafNode, escapeEntities) {
|
|
77
78
|
if (val !== undefined) {
|
|
78
79
|
if (this.options.trimValues && !dontTrim) {
|
|
79
80
|
val = val.trim();
|
|
80
81
|
}
|
|
81
82
|
if(val.length > 0){
|
|
82
|
-
val = this.replaceEntitiesValue(val);
|
|
83
|
+
if(!escapeEntities) val = this.replaceEntitiesValue(val);
|
|
83
84
|
|
|
84
85
|
const newval = this.options.tagValueProcessor(tagName, val, jPath, hasAttributes, isLeafNode);
|
|
85
86
|
if(newval === null || newval === undefined){
|
|
@@ -193,14 +194,7 @@ const parseXml = function(xmlData) {
|
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
if(currentNode){
|
|
196
|
-
textData = this.
|
|
197
|
-
, currentNode.tagname
|
|
198
|
-
, jPath
|
|
199
|
-
,false
|
|
200
|
-
, currentNode[":@"] ? Object.keys(currentNode[":@"]).length !== 0 : false
|
|
201
|
-
, Object.keys(currentNode.child).length === 0);
|
|
202
|
-
if(textData !== undefined && textData !== "") currentNode.add(this.options.textNodeName, textData);
|
|
203
|
-
textData = "";
|
|
197
|
+
textData = this.saveTextToParentTag(textData, currentNode, jPath);
|
|
204
198
|
}
|
|
205
199
|
|
|
206
200
|
jPath = jPath.substr(0, jPath.lastIndexOf("."));
|
|
@@ -209,21 +203,29 @@ const parseXml = function(xmlData) {
|
|
|
209
203
|
textData = "";
|
|
210
204
|
i = closeIndex;
|
|
211
205
|
} else if( xmlData[i+1] === '?') {
|
|
206
|
+
|
|
212
207
|
let tagData = readTagExp(xmlData,i, false, "?>");
|
|
213
208
|
if(!tagData) throw new Error("Pi Tag is not closed.");
|
|
209
|
+
|
|
214
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);
|
|
215
222
|
|
|
216
|
-
const childNode = new xmlNode(tagData.tagName);
|
|
217
|
-
childNode.add(this.options.textNodeName, "");
|
|
218
|
-
|
|
219
|
-
if(tagData.tagName !== tagData.tagExp && tagData.attrExpPresent){
|
|
220
|
-
childNode[":@"] = this.buildAttributesMap(tagData.tagExp, jPath);
|
|
221
223
|
}
|
|
222
|
-
|
|
224
|
+
|
|
223
225
|
|
|
224
226
|
i = tagData.closeIndex + 1;
|
|
225
227
|
} else if(xmlData.substr(i + 1, 3) === '!--') {
|
|
226
|
-
const endIndex = findClosingIndex(xmlData, "-->", i, "Comment is not closed.")
|
|
228
|
+
const endIndex = findClosingIndex(xmlData, "-->", i+4, "Comment is not closed.")
|
|
227
229
|
if(this.options.commentPropName){
|
|
228
230
|
const comment = xmlData.substring(i + 4, endIndex - 2);
|
|
229
231
|
|
|
@@ -266,14 +268,7 @@ const parseXml = function(xmlData) {
|
|
|
266
268
|
if (currentNode && textData) {
|
|
267
269
|
if(currentNode.tagname !== '!xml'){
|
|
268
270
|
//when nested tag is found
|
|
269
|
-
textData = this.
|
|
270
|
-
, currentNode.tagname
|
|
271
|
-
, jPath
|
|
272
|
-
, false
|
|
273
|
-
, currentNode[":@"] ? Object.keys(currentNode[":@"]).length !== 0 : false
|
|
274
|
-
, false);
|
|
275
|
-
if(textData !== undefined && textData !== "") currentNode.add(this.options.textNodeName, textData);
|
|
276
|
-
textData = "";
|
|
271
|
+
textData = this.saveTextToParentTag(textData, currentNode, jPath, false);
|
|
277
272
|
}
|
|
278
273
|
}
|
|
279
274
|
|
|
@@ -306,6 +301,10 @@ const parseXml = function(xmlData) {
|
|
|
306
301
|
if(tagName !== tagExp && attrExpPresent){
|
|
307
302
|
childNode[":@"] = this.buildAttributesMap(tagExp, jPath);
|
|
308
303
|
}
|
|
304
|
+
if(tagContent) {
|
|
305
|
+
tagContent = this.parseTextData(tagContent, tagName, jPath, true, attrExpPresent, true, true);
|
|
306
|
+
}
|
|
307
|
+
|
|
309
308
|
jPath = jPath.substr(0, jPath.lastIndexOf("."));
|
|
310
309
|
childNode.add(this.options.textNodeName, tagContent);
|
|
311
310
|
|
|
@@ -369,14 +368,16 @@ const replaceEntitiesValue = function(val){
|
|
|
369
368
|
}
|
|
370
369
|
return val;
|
|
371
370
|
}
|
|
372
|
-
function saveTextToParentTag(textData, currentNode, jPath) {
|
|
371
|
+
function saveTextToParentTag(textData, currentNode, jPath, isLeafNode) {
|
|
373
372
|
if (textData) { //store previously collected data as textNode
|
|
373
|
+
if(isLeafNode === undefined) isLeafNode = Object.keys(currentNode.child).length === 0
|
|
374
|
+
|
|
374
375
|
textData = this.parseTextData(textData,
|
|
375
376
|
currentNode.tagname,
|
|
376
377
|
jPath,
|
|
377
378
|
false,
|
|
378
379
|
currentNode[":@"] ? Object.keys(currentNode[":@"]).length !== 0 : false,
|
|
379
|
-
|
|
380
|
+
isLeafNode);
|
|
380
381
|
|
|
381
382
|
if (textData !== undefined && textData !== "")
|
|
382
383
|
currentNode.add(this.options.textNodeName, textData);
|