From e982acb038e4402f7f6ae463d62c6f467c691f89 Mon Sep 17 00:00:00 2001 From: Arek W Date: Fri, 8 Mar 2013 17:00:09 +1100 Subject: [PATCH 1/2] Add toJson arrayNotation option --- README.md | 12 +++++++----- lib/xml2json.js | 23 +++++++++++++---------- test/fixtures/array-notation.json | 1 + test/fixtures/array-notation.xml | 8 ++++++++ test/test-array-notation.js | 12 ++++++++++++ test/test.js | 6 ++++-- 6 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 test/fixtures/array-notation.json create mode 100644 test/fixtures/array-notation.xml create mode 100644 test/test-array-notation.js diff --git a/README.md b/README.md index 311974c..f9a27fe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Simple SAX-based XML2JSON Parser. -It does not parse the following elements: +It does not parse the following elements: * CDATA sections (*) * Processing instructions @@ -13,7 +13,7 @@ It does not parse the following elements: $ npm install xml2json ``` -## Usage +## Usage ```javascript var parser = require('xml2json'); @@ -39,7 +39,8 @@ var options = { reversible: false, coerce: true, sanitize: true, - trim: true + trim: true, + arrayNotation: false }; ``` @@ -47,10 +48,11 @@ var options = { * **reversible:** Makes the JSON reversible to XML (*) * **coerce:** Makes type coercion. i.e.: numbers and booleans present in attributes and element values are converted from string to its correspondent data types. * **trim:** Removes leading and trailing whitespaces as well as line terminators in element values. +* **arrayNotation:** XML child nodes are always treated as arrays * **sanitize:** Sanitizes the following characters present in element values: ```javascript -var chars = { +var chars = { '<': '<', '>': '>', '(': '(', @@ -88,4 +90,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. \ No newline at end of file +IN THE SOFTWARE. diff --git a/lib/xml2json.js b/lib/xml2json.js index f9a5548..6e608ae 100644 --- a/lib/xml2json.js +++ b/lib/xml2json.js @@ -2,7 +2,7 @@ var expat = require('node-expat'); var fs = require('fs'); // This object will hold the final result. -var obj = {}; +var obj = {}; var currentObject = {}; var ancestors = []; var currentElementName = null; @@ -18,7 +18,11 @@ function startElement(name, attrs) { } if (! (name in currentObject)) { - currentObject[name] = attrs; + if(options.arrayNotation) { + currentObject[name] = [attrs]; + } else { + currentObject[name] = attrs; + } } else if (! (currentObject[name] instanceof Array)) { // Put the existing object in an array. var newArray = [currentObject[name]]; @@ -49,7 +53,7 @@ function text(data) { /*if (!data.trim().length) { return; }*/ - + if (options.trim) { data = data.trim(); } @@ -65,7 +69,7 @@ function endElement(name) { if (currentElementName !== name) { delete currentObject['$t']; } - // This should check to make sure that the name we're ending + // This should check to make sure that the name we're ending // matches the name we started on. var ancestor = ancestors.pop(); if (!options.reversible) { @@ -85,14 +89,14 @@ function coerce(value) { if (!options.coerce) { return value; } - + var num = Number(value); if (!isNaN(num)) { return num; } var _value = value.toLowerCase(); - + if (_value == 'true' || _value == 'yes') { return true; } @@ -106,7 +110,7 @@ function coerce(value) { /** - * Simple sanitization. It is not intended to sanitize + * Simple sanitization. It is not intended to sanitize * malicious element values. * * character | escaped @@ -151,7 +155,7 @@ function sanitize(value) { * characterized by the presence of the property $t. * - sanitize_values: If true, the parser escapes any element value in the xml * that has any of the following characters: <, >, (, ), #, #, &, ", '. - * + * * @return {String|Object} A String or an Object with the JSON representation * of the XML. */ @@ -190,7 +194,6 @@ module.exports = function(xml, _options) { //See: http://timelessrepo.com/json-isnt-a-javascript-subset json = json.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029'); - + return json; }; - diff --git a/test/fixtures/array-notation.json b/test/fixtures/array-notation.json new file mode 100644 index 0000000..b86c85f --- /dev/null +++ b/test/fixtures/array-notation.json @@ -0,0 +1 @@ +{"abcd":[{"efg":[{"hijk":["qrstuv",{"lmnop":["wxyz"]}]}]}]} \ No newline at end of file diff --git a/test/fixtures/array-notation.xml b/test/fixtures/array-notation.xml new file mode 100644 index 0000000..b2b7fc7 --- /dev/null +++ b/test/fixtures/array-notation.xml @@ -0,0 +1,8 @@ + + + qrstuv + + wxyz + + + diff --git a/test/test-array-notation.js b/test/test-array-notation.js new file mode 100644 index 0000000..afa6b5e --- /dev/null +++ b/test/test-array-notation.js @@ -0,0 +1,12 @@ +var fs = require('fs'); +var parser = require('../lib'); +var assert = require('assert'); + +var xml = fs.readFileSync('./fixtures/array-notation.xml'); +var expectedJson = JSON.parse( fs.readFileSync('./fixtures/array-notation.json') ); + +var json = parser.toJson(xml, {object: true, arrayNotation: true}); + +assert.deepEqual(json, expectedJson); + +console.log('xml2json options.arrayNotation passed!'); diff --git a/test/test.js b/test/test.js index 9088faf..d45a98e 100644 --- a/test/test.js +++ b/test/test.js @@ -25,6 +25,8 @@ fs.readdir(fixturesPath, function(err, files) { result = parser.toJson(data2, {coerce: false}); } else if (file.indexOf('large') >= 0) { result = parser.toJson(data2, {coerce: false, trim: true, sanitize: false}); + } else if (file.indexOf('array-notation') >= 0) { + result = parser.toJson(data2, {arrayNotation: true}); } else { result = parser.toJson(data2, {trim: false}); } @@ -45,10 +47,10 @@ fs.readdir(fixturesPath, function(err, files) { if (basename.match('reversible')) { var data = fs.readFileSync(fixturesPath + '/' + file); var result = parser.toXml(data); - + var xmlFile = basename.split('-')[0] + '.xml'; var expected = fs.readFileSync(fixturesPath + '/' + xmlFile) + ''; - + if (expected) { expected = expected.trim(); } From 44670f80ebd1718b398a6ba4a03b083bca2afa79 Mon Sep 17 00:00:00 2001 From: Arek W Date: Sun, 28 Apr 2013 12:42:46 +1000 Subject: [PATCH 2/2] 25% faster --- lib/xml2json.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/xml2json.js b/lib/xml2json.js index 6e608ae..44c6146 100644 --- a/lib/xml2json.js +++ b/lib/xml2json.js @@ -12,9 +12,9 @@ function startElement(name, attrs) { currentElementName = name; if(options.coerce) { // Looping here in stead of making coerce generic as object walk is unnecessary - Object.keys(attrs).forEach(function(key) { + for(key in attrs) { attrs[key] = coerce(attrs[key]); - }); + } } if (! (name in currentObject)) { @@ -73,7 +73,7 @@ function endElement(name) { // matches the name we started on. var ancestor = ancestors.pop(); if (!options.reversible) { - if ((Object.keys(currentObject).length == 1) && ('$t' in currentObject)) { + if (('$t' in currentObject) && (Object.keys(currentObject).length == 1)) { if (ancestor[name] instanceof Array) { ancestor[name].push(ancestor[name].pop()['$t']); } else {