diff --git a/lib/parser.js b/lib/parser.js index 7fa2fc58..2bf13e74 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript 1.12.7 (function() { "use strict"; - var bom, defaults, defineProperty, events, isEmpty, processItem, processors, sax, setImmediate, + var bom, defaults, defineProperty, events, hasNoContent, isEmpty, processItem, processors, sax, setImmediate, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; @@ -22,6 +22,10 @@ return typeof thing === "object" && (thing != null) && Object.keys(thing).length === 0; }; + hasNoContent = function(thing) { + return typeof thing === "object" && (thing != null) && (Object.keys(thing).length === 0 || (Object.keys(thing).length === 1 && '$' in thing)); + }; + processItem = function(processors, item, key) { var i, len, process; for (i = 0, len = processors.length; i < len; i++) { @@ -181,7 +185,7 @@ })(this); this.saxParser.onclosetag = (function(_this) { return function() { - var cdata, emptyStr, key, node, nodeName, obj, objClone, old, s, xpath; + var cdata, emptyStr, emptyTag, key, node, nodeName, obj, objClone, old, s, xpath; obj = stack.pop(); nodeName = obj["#name"]; if (!_this.options.explicitChildren || !_this.options.preserveChildrenOrder) { @@ -207,12 +211,15 @@ obj = obj[charkey]; } } + if (typeof _this.options.emptyTag === 'function') { + emptyTag = _this.options.emptyTag(); + } else { + emptyTag = _this.options.emptyTag !== '' ? _this.options.emptyTag : emptyStr; + } if (isEmpty(obj)) { - if (typeof _this.options.emptyTag === 'function') { - obj = _this.options.emptyTag(); - } else { - obj = _this.options.emptyTag !== '' ? _this.options.emptyTag : emptyStr; - } + obj = emptyTag; + } else if (hasNoContent(obj)) { + obj['_'] = emptyTag; } if (_this.options.validator != null) { xpath = "/" + ((function() { diff --git a/src/parser.coffee b/src/parser.coffee index dade8f39..2cd26762 100644 --- a/src/parser.coffee +++ b/src/parser.coffee @@ -11,6 +11,9 @@ defaults = require('./defaults').defaults isEmpty = (thing) -> return typeof thing is "object" && thing? && Object.keys(thing).length is 0 +hasNoContent = (thing) -> + return typeof thing is "object" && thing? && (Object.keys(thing).length is 0 || (Object.keys(thing).length is 1 && '$' of thing)) + processItem = (processors, item, key) -> item = process(item, key) for process in processors return item @@ -154,11 +157,15 @@ class exports.Parser extends events if Object.keys(obj).length == 1 and charkey of obj and not @EXPLICIT_CHARKEY obj = obj[charkey] + if typeof @options.emptyTag == 'function' + emptyTag = @options.emptyTag() + else + emptyTag = if @options.emptyTag != '' then @options.emptyTag else emptyStr + if (isEmpty obj) - if typeof @options.emptyTag == 'function' - obj = @options.emptyTag() - else - obj = if @options.emptyTag != '' then @options.emptyTag else emptyStr + obj = emptyTag + else if (hasNoContent obj) + obj['_'] = emptyTag if @options.validator? xpath = "/" + (node["#name"] for node in stack).concat(nodeName).join("/") diff --git a/test/parser.test.coffee b/test/parser.test.coffee index f2758759..5243554c 100644 --- a/test/parser.test.coffee +++ b/test/parser.test.coffee @@ -313,6 +313,32 @@ module.exports = equ r.sample.listtest[0].item[1], 'Qux.' equ r.sample.listtest[0].item[2], 'Quux.') + 'test parseStringPromise with emptyTag and explicitArray': (test) -> + xml = """ + + value1 + + value3 + + + """ + parser = new xml2js.Parser + emptyTag: '--EMPTY--' + explicitArray: false + + parser.parseStringPromise(xml) + .then (result) -> + equ result.test.$?.xmlns, 'http://example.com/namespace' + equ result.test.value1, 'value1' + equ result.test.value2, '--EMPTY--' + equ result.test.value3._, 'value3' + equ result.test.value3.$?.xmlns, 'http://example.com/namespace' + equ result.test.value4._, '--EMPTY--' + equ result.test.value4.$?.xmlns, 'http://example.com/namespace' + test.finish() + .catch (err) -> + test.fail('Should not error: ' + err) + 'test simple callback mode': (test) -> x2js = new xml2js.Parser() fs.readFile fileName, (err, data) ->