Skip to content

Commit

Permalink
feat: support CDATA even if tag order is nor preserved
Browse files Browse the repository at this point in the history
  • Loading branch information
amitguptagwl committed Mar 16, 2022
1 parent 6d47e58 commit 0ee2a31
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 19 deletions.
52 changes: 51 additions & 1 deletion docs/v4/3.XMLBuilder.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,57 @@ This property is not supported when `preserveOrder: true` because attributes ar
To customize the bahaviour of parsing an attribute value to the string value. It accepts attribute name and value.

## cdataPropName
To recognize CDATA properties in a JS object so that they can be transformed correcty. This option is supported only if `preserveOrder: true`
To recognize CDATA properties in a JS object so that they can be transformed correcty.

Eg
Input
```json
{
"any_name": {
"person": {
"phone": [
122233344550,
122233344551,
""
],
"name": [
"<some>Jack</some>Jack",
"<some>Mohan</some>"
],
"blank": "",
"regx": "^[ ].*$"
}
}
};
```
code
```js
const options = {
processEntities:false,
format: true,
ignoreAttributes: false,
cdataPropName: "phone"
};

const builder = new XMLBuilder(options);
const xmlOutput = builder.build(input);
```
Output
```xml
<any_name>
<person>
<![CDATA[122233344550]]>
<![CDATA[122233344551]]>
<![CDATA[]]>
<name><some>Jack</some>Jack</name>
<name><some>Mohan</some></name>
<blank></blank>
<regx>^[ ].*$</regx>
</person>
</any_name>`;
```

It is recommended to use `preserveOrder: true` when you're parsing XML to js object and building the XML back. So that the order of CDATA is maintained.
## commentPropName
To recognize commentsin a JS object so that they can be transformed correcty. This option is supported only if `preserveOrder: true` because position of comment is important.

Expand Down
90 changes: 89 additions & 1 deletion spec/cdata_spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";

const {XMLParser, XMLValidator} = require("../src/fxp");
const {XMLParser, XMLBuilder, XMLValidator} = require("../src/fxp");

describe("XMLParser", function() {
it("should parse multiline tag value when tags without spaces", function() {
Expand Down Expand Up @@ -69,6 +69,94 @@ patronymic</person></root>`;
expect(result).toBe(true);
});

it("should build XML with CDATA for repeated values without parseOrder", function() {
const input = {
"any_name": {
"person": {
"phone": [
122233344550,
122233344551,
""
],
"name": [
`<some>Jack</some>Jack`,
`<some>Mohan</some>`
],
"blank": "",
"regx": "^[ ].*$"
}
}
};
const expected = `
<any_name>
<person>
<![CDATA[122233344550]]>
<![CDATA[122233344551]]>
<![CDATA[]]>
<name><some>Jack</some>Jack</name>
<name><some>Mohan</some></name>
<blank></blank>
<regx>^[ ].*$</regx>
</person>
</any_name>`;

const options = {
processEntities:false,
format: true,
ignoreAttributes: false,
cdataPropName: "phone"
};

const builder = new XMLBuilder(options);
const xmlOutput = builder.build(input);
// console.log(xmlOutput);
expect(xmlOutput.replace(/\s+/g, "")).toEqual(expected.replace(/\s+/g, ""));
});

it("should build XML with CDATA for single value without parseOrder", function() {
const input = {
"any_name": {
"person": {
"phone": [
122233344550,
122233344551,
""
],
"name": [
`<some>Jack</some>Jack`,
`<some>Mohan</some>`
],
"blank": "",
"regx": "^[ ].*$"
}
}
};
const expected = `
<any_name>
<person>
<phone>122233344550</phone>
<phone>122233344551</phone>
<phone></phone>
<name><some>Jack</some>Jack</name>
<name><some>Mohan</some></name>
<blank></blank>
<![CDATA[^[ ].*$]]>
</person>
</any_name>`;

const options = {
processEntities:false,
format: true,
ignoreAttributes: false,
cdataPropName: "regx"
};

const builder = new XMLBuilder(options);
const xmlOutput = builder.build(input);
// console.log(xmlOutput);
expect(xmlOutput.replace(/\s+/g, "")).toEqual(expected.replace(/\s+/g, ""));
});

it("should parse tag having CDATA 2", function() {
const xmlData = `\
<sql-queries>
Expand Down
37 changes: 20 additions & 17 deletions src/xmlbuilder/json2xml.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,7 @@ function buildObjectNode(val, key, attrStr, level) {
}

if (attrStr && val.indexOf('<') === -1) {
return (
this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' +
val +
tagEndExp );
return ( this.indentate(level) + '<' + key + attrStr + piClosingChar + '>' + val + tagEndExp );
} else {
return (
this.indentate(level) + '<' + key + attrStr + piClosingChar + this.tagEndChar +
Expand All @@ -194,20 +191,26 @@ function buildEmptyObjNode(val, key, attrStr, level) {
}

function buildTextValNode(val, key, attrStr, level) {
let textValue = this.options.tagValueProcessor(key, val);
textValue = this.replaceEntitiesValue(textValue);

if( textValue === '' && this.options.unpairedTags.indexOf(key) !== -1){ //unpaired
if(this.options.suppressUnpairedNode){
return this.indentate(level) + '<' + key + this.tagEndChar;
}else{
return this.indentate(level) + '<' + key + "/" + this.tagEndChar;
}
if (this.options.cdataPropName !== false && key === this.options.cdataPropName) {
if(this.options.format) return this.indentate(level) + `<![CDATA[${val}]]>\n`;
else return this.indentate(level) + `<![CDATA[${val}]]>`;
}else{
return (
this.indentate(level) + '<' + key + attrStr + '>' +
textValue +
'</' + key + this.tagEndChar );
let textValue = this.options.tagValueProcessor(key, val);
textValue = this.replaceEntitiesValue(textValue);

if( textValue === '' && this.options.unpairedTags.indexOf(key) !== -1){ //unpaired
if(this.options.suppressUnpairedNode){
return this.indentate(level) + '<' + key + this.tagEndChar;
}else{
return this.indentate(level) + '<' + key + "/" + this.tagEndChar;
}
} else{
return (
this.indentate(level) + '<' + key + attrStr + '>' +
textValue +
'</' + key + this.tagEndChar );
}

}
}

Expand Down

0 comments on commit 0ee2a31

Please sign in to comment.