Skip to content
This repository was archived by the owner on Jan 7, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -13,7 +13,7 @@ It does not parse the following elements:
$ npm install xml2json
```

## Usage
## Usage
```javascript
var parser = require('xml2json');

Expand All @@ -39,18 +39,20 @@ var options = {
reversible: false,
coerce: true,
sanitize: true,
trim: true
trim: true,
arrayNotation: false
};
```

* **object:** Returns a Javascript object instead of a JSON string
* **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 = {
'<': '&lt;',
'>': '&gt;',
'(': '&#40;',
Expand Down Expand Up @@ -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.
IN THE SOFTWARE.
29 changes: 16 additions & 13 deletions lib/xml2json.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -12,13 +12,17 @@ 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)) {
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]];
Expand Down Expand Up @@ -49,7 +53,7 @@ function text(data) {
/*if (!data.trim().length) {
return;
}*/

if (options.trim) {
data = data.trim();
}
Expand All @@ -65,11 +69,11 @@ 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) {
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 {
Expand All @@ -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;
}
Expand All @@ -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
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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;
};

1 change: 1 addition & 0 deletions test/fixtures/array-notation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"abcd":[{"efg":[{"hijk":["qrstuv",{"lmnop":["wxyz"]}]}]}]}
8 changes: 8 additions & 0 deletions test/fixtures/array-notation.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<abcd>
<efg>
<hijk>qrstuv</hijk>
<hijk>
<lmnop>wxyz</lmnop>
</hijk>
</efg>
</abcd>
12 changes: 12 additions & 0 deletions test/test-array-notation.js
Original file line number Diff line number Diff line change
@@ -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!');
6 changes: 4 additions & 2 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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});
}
Expand All @@ -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();
}
Expand Down