diff --git a/.gitignore b/.gitignore index 69b51c5f..e52f494f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.swp +.idea node_modules npm-debug.log .nyc_output diff --git a/README.md b/README.md index be7b83f4..9468be8a 100644 --- a/README.md +++ b/README.md @@ -347,9 +347,10 @@ Possible options are: * `headless` (default: `false`): omit the XML header. Added in 0.4.3. * `allowSurrogateChars` (default: `false`): allows using characters from the Unicode surrogate blocks. - * `cdata` (default: `false`): wrap text nodes in `` instead of - escaping when necessary. Does not add `` if it is not required. + * `cdata` (default: `false`): + * When `true` wrap text nodes in `` instead of escaping when necessary. Does not add `` if it is not required. Added in 0.4.5. + * When `'always'` all inner text wrapped in `` regardless of content. `renderOpts`, `xmldec`,`doctype` and `headless` pass through to [xmlbuilder-js](https://github.com/oozcitak/xmlbuilder-js). diff --git a/lib/builder.js b/lib/builder.js index 58f36384..beeaeb95 100644 --- a/lib/builder.js +++ b/lib/builder.js @@ -51,7 +51,7 @@ return function(element, obj) { var attr, child, entry, index, key, value; if (typeof obj !== 'object') { - if (_this.options.cdata && requiresCDATA(obj)) { + if (_this.options.cdata === 'always' || (_this.options.cdata && requiresCDATA(obj))) { element.raw(wrapCDATA(obj)); } else { element.txt(obj); @@ -77,7 +77,7 @@ } } } else if (key === charkey) { - if (_this.options.cdata && requiresCDATA(child)) { + if (_this.options.cdata === 'always' || (_this.options.cdata && requiresCDATA(child))) { element = element.raw(wrapCDATA(child)); } else { element = element.txt(child); @@ -87,7 +87,7 @@ if (!hasProp.call(child, index)) continue; entry = child[index]; if (typeof entry === 'string') { - if (_this.options.cdata && requiresCDATA(entry)) { + if (_this.options.cdata === 'always' || (_this.options.cdata && requiresCDATA(entry))) { element = element.ele(key).raw(wrapCDATA(entry)).up(); } else { element = element.ele(key, entry).up(); @@ -99,7 +99,7 @@ } else if (typeof child === "object") { element = render(element.ele(key), child).up(); } else { - if (typeof child === 'string' && _this.options.cdata && requiresCDATA(child)) { + if (typeof child === 'string' && _this.options.cdata === 'always' || (_this.options.cdata && requiresCDATA(child))) { element = element.ele(key).raw(wrapCDATA(child)).up(); } else { if (child == null) { diff --git a/lib/parser.js b/lib/parser.js index 9e8261eb..317eb2c0 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -176,7 +176,7 @@ if (!_this.options.explicitChildren || !_this.options.preserveChildrenOrder) { delete obj["#name"]; } - if (obj.cdata === true) { + if (obj.cdata === 'always' || obj.cdata === true) { cdata = obj.cdata; delete obj.cdata; } diff --git a/src/builder.coffee b/src/builder.coffee index 5653fde0..bbec0bdb 100644 --- a/src/builder.coffee +++ b/src/builder.coffee @@ -44,7 +44,7 @@ class exports.Builder render = (element, obj) => if typeof obj isnt 'object' # single element, just append it as text - if @options.cdata && requiresCDATA obj + if @options.cdata is 'always' or (@options.cdata && requiresCDATA obj) element.raw wrapCDATA obj else element.txt obj @@ -64,7 +64,7 @@ class exports.Builder # Case #2 Char data (CDATA, etc.) else if key is charkey - if @options.cdata && requiresCDATA child + if @options.cdata is 'always' or (@options.cdata && requiresCDATA child) element = element.raw wrapCDATA child else element = element.txt child @@ -73,7 +73,7 @@ class exports.Builder else if Array.isArray child for own index, entry of child if typeof entry is 'string' - if @options.cdata && requiresCDATA entry + if @options.cdata is 'always' or (@options.cdata && requiresCDATA entry) element = element.ele(key).raw(wrapCDATA entry).up() else element = element.ele(key, entry).up() @@ -86,7 +86,7 @@ class exports.Builder # Case #5 String and remaining types else - if typeof child is 'string' && @options.cdata && requiresCDATA child + if typeof child is 'string' && @options.cdata is 'always' or (@options.cdata && requiresCDATA child) element = element.ele(key).raw(wrapCDATA child).up() else if not child? diff --git a/src/parser.coffee b/src/parser.coffee index 8a375197..c8a8ca1a 100644 --- a/src/parser.coffee +++ b/src/parser.coffee @@ -126,7 +126,7 @@ class exports.Parser extends events.EventEmitter nodeName = obj["#name"] delete obj["#name"] if not @options.explicitChildren or not @options.preserveChildrenOrder - if obj.cdata == true + if obj.cdata is 'always' or obj.cdata == true cdata = obj.cdata delete obj.cdata diff --git a/test/builder.test.coffee b/test/builder.test.coffee index e9c12be3..54c186e0 100644 --- a/test/builder.test.coffee +++ b/test/builder.test.coffee @@ -220,6 +220,22 @@ module.exports = diffeq expected, actual test.finish() + "test uses cdata for all chars when cdata is 'always'": (test) -> + expected = """ + + + + + + + """ + opts = cdata: 'always' + builder = new xml2js.Builder opts + obj = {"xml":{"MsgId":["& <<"],"Message":["Hello"]}} + actual = builder.buildObject obj + diffeq expected, actual + test.finish() + 'test uses cdata for string values of objects': (test) -> expected = """