Permalink
Browse files

Improved consistenzy with explicitArray + mergeAttrs

Many thanks to @hoelzl for spotting and fixing this.

Merge branch 'hoelzl-master'

Conflicts:
	lib/xml2js.js
  • Loading branch information...
2 parents bfe77b8 + f004ffc commit 6391ea2c9a8d7614143a3c9bd689caf69583c6cc @Leonidas-from-XIV committed Nov 6, 2013
Showing with 78 additions and 62 deletions.
  1. +28 −33 lib/xml2js.js
  2. +2 −1 package.json
  3. +14 −15 src/xml2js.coffee
  4. +2 −1 test/fixtures/sample.xml
  5. +32 −12 test/parser.test.coffee
View
@@ -1,9 +1,9 @@
-// Generated by CoffeeScript 1.6.1
+// Generated by CoffeeScript 1.6.3
(function() {
var bom, builder, events, isEmpty, sax,
__hasProp = {}.hasOwnProperty,
__extends = 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; },
- _this = this;
+ __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
sax = require('sax');
@@ -71,7 +71,6 @@
};
exports.ValidationError = (function(_super) {
-
__extends(ValidationError, _super);
function ValidationError(message) {
@@ -83,7 +82,6 @@
})(Error);
exports.Builder = (function() {
-
function Builder(opts) {
var key, value, _ref;
this.options = {};
@@ -155,18 +153,13 @@
})();
exports.Parser = (function(_super) {
-
__extends(Parser, _super);
function Parser(opts) {
- var key, value, _ref,
- _this = this;
- this.parseString = function(str, cb) {
- return Parser.prototype.parseString.apply(_this, arguments);
- };
- this.reset = function() {
- return Parser.prototype.reset.apply(_this, arguments);
- };
+ this.parseString = __bind(this.parseString, this);
+ this.reset = __bind(this.reset, this);
+ this.assignOrPush = __bind(this.assignOrPush, this);
+ var key, value, _ref;
if (!(this instanceof exports.Parser)) {
return new exports.Parser(opts);
}
@@ -188,6 +181,21 @@
this.reset();
}
+ Parser.prototype.assignOrPush = function(obj, key, newValue) {
+ if (!(key in obj)) {
+ if (!this.options.explicitArray) {
+ return obj[key] = newValue;
+ } else {
+ return obj[key] = [newValue];
+ }
+ } else {
+ if (!(obj[key] instanceof Array)) {
+ obj[key] = [obj[key]];
+ }
+ return obj[key].push(newValue);
+ }
+ };
+
Parser.prototype.reset = function() {
var attrkey, charkey, err, ontext, stack,
_this = this;
@@ -210,7 +218,7 @@
attrkey = this.options.attrkey;
charkey = this.options.charkey;
this.saxParser.onopentag = function(node) {
- var key, obj, _ref;
+ var key, newValue, obj, _ref;
obj = {};
obj[charkey] = "";
if (!_this.options.ignoreAttrs) {
@@ -220,10 +228,11 @@
if (!(attrkey in obj) && !_this.options.mergeAttrs) {
obj[attrkey] = {};
}
+ newValue = node.attributes[key];
if (_this.options.mergeAttrs) {
- obj[key] = node.attributes[key];
+ _this.assignOrPush(obj, key, newValue);
} else {
- obj[attrkey][key] = node.attributes[key];
+ obj[attrkey][key] = newValue;
}
}
}
@@ -273,7 +282,8 @@
})()).concat(nodeName).join("/");
try {
obj = _this.options.validator(xpath, s && s[nodeName], obj);
- } catch (err) {
+ } catch (_error) {
+ err = _error;
_this.emit("error", err);
}
}
@@ -293,22 +303,7 @@
obj = node;
}
if (stack.length > 0) {
- if (!_this.options.explicitArray) {
- if (!(nodeName in s)) {
- return s[nodeName] = obj;
- } else if (s[nodeName] instanceof Array) {
- return s[nodeName].push(obj);
- } else {
- old = s[nodeName];
- s[nodeName] = [old];
- return s[nodeName].push(obj);
- }
- } else {
- if (!(s[nodeName] instanceof Array)) {
- s[nodeName] = [];
- }
- return s[nodeName].push(obj);
- }
+ return _this.assignOrPush(s, nodeName, obj);
} else {
if (_this.options.explicitRoot) {
old = obj;
View
@@ -25,7 +25,8 @@
"Chris Tavares <ctavares@microsoft.com> (https://github.com/christav)",
"Frank Xu <yyfrankyy@gmail.com> (http://f2e.us/)",
"Guido D'Albore <guido@bitstorm.it> (http://www.bitstorm.it/)",
- "Jack Senechal (http://jacksenechal.com/)"
+ "Jack Senechal (http://jacksenechal.com/)",
+ "Matthias Hölzl <tc@xantira.com> (https://github.com/hoelzl)"
],
"main" : "./lib/xml2js",
"directories" : {
View
@@ -142,6 +142,16 @@ class exports.Parser extends events.EventEmitter
@reset()
+ assignOrPush: (obj, key, newValue) =>
+ if key not of obj
+ if not @options.explicitArray
+ obj[key] = newValue
+ else
+ obj[key] = [newValue]
+ else
+ obj[key] = [obj[key]] if not (obj[key] instanceof Array)
+ obj[key].push newValue
+
reset: =>
# remove all previous listeners for events, to prevent event listener
# accumulation
@@ -179,10 +189,11 @@ class exports.Parser extends events.EventEmitter
for own key of node.attributes
if attrkey not of obj and not @options.mergeAttrs
obj[attrkey] = {}
+ newValue = node.attributes[key]
if @options.mergeAttrs
- obj[key] = node.attributes[key]
+ @assignOrPush obj, key, newValue
else
- obj[attrkey][key] = node.attributes[key]
+ obj[attrkey][key] = newValue
# need a place to store the node name
obj["#name"] = if @options.normalizeTags then node.name.toLowerCase() else node.name
@@ -243,19 +254,7 @@ class exports.Parser extends events.EventEmitter
# check whether we closed all the open tags
if stack.length > 0
- if not @options.explicitArray
- if nodeName not of s
- s[nodeName] = obj
- else if s[nodeName] instanceof Array
- s[nodeName].push obj
- else
- old = s[nodeName]
- s[nodeName] = [old]
- s[nodeName].push obj
- else
- if not (s[nodeName] instanceof Array)
- s[nodeName] = []
- s[nodeName].push obj
+ @assignOrPush s, nodeName, obj
else
# if explicitRoot was specified, wrap stuff in the root tag name
if @options.explicitRoot
@@ -8,7 +8,7 @@
Line One
Line Two
</whitespacetest>
- <listtest>
+ <listtest attr="Attribute">
<item>
This <subitem>Foo(1)</subitem> is
<subitem>Foo(2)</subitem>
@@ -19,6 +19,7 @@
</item>
<item>Qux.</item>
<item>Quux.</item>
+ <single>Single</single>
</listtest>
<arraytest>
<item><subitem>Baz.</subitem></item>
@@ -44,7 +44,7 @@ validator = (xpath, currentValue, newValue) ->
return newValue
# shortcut, because it is quite verbose
-equ = assert.equal
+equ = assert.strictEqual
module.exports =
'test parse with defaults': skeleton(undefined, (r) ->
@@ -85,19 +85,39 @@ module.exports =
'test parse with mergeAttrs': skeleton(mergeAttrs: true, (r) ->
console.log 'Result object: ' + util.inspect r, false, 10
- equ r.sample.chartest[0].desc, 'Test for CHARs'
+ equ r.sample.chartest[0].desc[0], 'Test for CHARs'
equ r.sample.chartest[0]._, 'Character data here!'
- equ r.sample.cdatatest[0].desc, 'Test for CDATA'
- equ r.sample.cdatatest[0].misc, 'true'
+ equ r.sample.cdatatest[0].desc[0], 'Test for CDATA'
+ equ r.sample.cdatatest[0].misc[0], 'true'
equ r.sample.cdatatest[0]._, 'CDATA here!'
- equ r.sample.nochartest[0].desc, 'No data'
- equ r.sample.nochartest[0].misc, 'false'
+ equ r.sample.nochartest[0].desc[0], 'No data'
+ equ r.sample.nochartest[0].misc[0], 'false'
equ r.sample.listtest[0].item[0].subitem[0], 'Foo(1)'
equ r.sample.listtest[0].item[0].subitem[1], 'Foo(2)'
equ r.sample.listtest[0].item[0].subitem[2], 'Foo(3)'
equ r.sample.listtest[0].item[0].subitem[3], 'Foo(4)'
equ r.sample.listtest[0].item[1], 'Qux.'
- equ r.sample.listtest[0].item[2], 'Quux.')
+ equ r.sample.listtest[0].item[2], 'Quux.'
+ equ r.sample.listtest[0].single[0], 'Single'
+ equ r.sample.listtest[0].attr[0], 'Attribute')
+
+ 'test parse with mergeAttrs and not explicitArray': skeleton(mergeAttrs: true, explicitArray: false, (r) ->
+ console.log 'Result object: ' + util.inspect r, false, 10
+ equ r.sample.chartest.desc, 'Test for CHARs'
+ equ r.sample.chartest._, 'Character data here!'
+ equ r.sample.cdatatest.desc, 'Test for CDATA'
+ equ r.sample.cdatatest.misc, 'true'
+ equ r.sample.cdatatest._, 'CDATA here!'
+ equ r.sample.nochartest.desc, 'No data'
+ equ r.sample.nochartest.misc, 'false'
+ equ r.sample.listtest.item[0].subitem[0], 'Foo(1)'
+ equ r.sample.listtest.item[0].subitem[1], 'Foo(2)'
+ equ r.sample.listtest.item[0].subitem[2], 'Foo(3)'
+ equ r.sample.listtest.item[0].subitem[3], 'Foo(4)'
+ equ r.sample.listtest.item[1], 'Qux.'
+ equ r.sample.listtest.item[2], 'Quux.'
+ equ r.sample.listtest.single, 'Single'
+ equ r.sample.listtest.attr, 'Attribute')
'test parse with explicitChildren': skeleton(explicitChildren: true, (r) ->
console.log 'Result object: ' + util.inspect r, false, 10
@@ -188,9 +208,9 @@ module.exports =
'test ignore attributes': skeleton(ignoreAttrs: true, (r) ->
console.log 'Result object: ' + util.inspect r, false, 10
- equ r.sample.chartest, 'Character data here!'
- equ r.sample.cdatatest, 'CDATA here!'
- assert.equal r.sample.nochartest[0], ''
+ equ r.sample.chartest[0], 'Character data here!'
+ equ r.sample.cdatatest[0], 'CDATA here!'
+ equ r.sample.nochartest[0], ''
equ r.sample.listtest[0].item[0]._, '\n This is\n \n character\n \n data!\n \n '
equ r.sample.listtest[0].item[0].subitem[0], 'Foo(1)'
equ r.sample.listtest[0].item[0].subitem[1], 'Foo(2)'
@@ -314,9 +334,9 @@ module.exports =
demo = '<xml><foo>Bar</foo></xml>'
withNew = new xml2js.Parser
withNew.parseString demo, (err, resWithNew) ->
- equ err, undefined
+ equ err, null
withoutNew = xml2js.Parser()
withoutNew.parseString demo, (err, resWithoutNew) ->
- equ err, undefined
+ equ err, null
assert.deepEqual resWithNew, resWithoutNew
test.done()

0 comments on commit 6391ea2

Please sign in to comment.