libxml-to-js
Advanced tools
Comparing version 0.3.10 to 0.3.11
@@ -0,1 +1,5 @@ | ||
## v0.3.11 | ||
* Adds more CDATA support [#13](https://github.com/SaltwaterC/libxml-to-js/issues/13). Thanking XApp-Studio for the patch. | ||
* jslint compliant. | ||
## v0.3.10 | ||
@@ -2,0 +6,0 @@ * Fixes a couple of global variable leaks [#10](https://github.com/SaltwaterC/libxml-to-js/pull/10). |
@@ -0,5 +1,8 @@ | ||
'use strict'; | ||
var lodash = require('lodash'); | ||
var libxmljs = require('libxmljs'); | ||
/** | ||
* Simple object merger | ||
* Wraps the lodash object merger | ||
* | ||
@@ -12,11 +15,3 @@ * @param obj1 | ||
var obj3 = {}; | ||
for (var attrname in obj1) { | ||
obj3[attrname] = obj1[attrname]; | ||
} | ||
for (var attrname in obj2) { | ||
obj3[attrname] = obj2[attrname]; | ||
} | ||
lodash.merge(obj3, obj1, obj2); | ||
return obj3; | ||
@@ -26,31 +21,20 @@ }; | ||
/** | ||
* Checks if an object is empty | ||
* @param obj | ||
* @returns bool | ||
*/ | ||
var isEmpty = function (obj) { | ||
for (var prop in obj) { | ||
if(obj.hasOwnProperty(prop)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
/** | ||
* The core function of this module | ||
* @param obj | ||
* @param recurse | ||
* @param namespaces | ||
* @returns parsedObj | ||
* | ||
* @param {Object} obj | ||
* @param {Boolean} recurse | ||
* @param {Object} namespaces | ||
* @returns {Object} parsedObj | ||
*/ | ||
var libxml2js = function (obj, recurse, namespaces) { | ||
if (namespaces == undefined) { | ||
var i, j, k, atlen, chlen, chtlen, val, old, recValue; | ||
if (namespaces === undefined) { | ||
namespaces = {}; | ||
} | ||
if ( ! recurse) { | ||
obj = obj.root(); | ||
if (obj.namespace()) { | ||
namespaces['xmlns'] = obj.namespace().href(); | ||
namespaces.xmlns = obj.namespace().href(); | ||
} | ||
@@ -63,3 +47,3 @@ } | ||
jsobj['@'] = {}; | ||
for (var i = 0, atlen = attributes.length; i < atlen; i++) { | ||
for (i = 0, atlen = attributes.length; i < atlen; i++) { | ||
jsobj['@'][attributes[i].name()] = attributes[i].value(); | ||
@@ -69,11 +53,13 @@ } | ||
for (var i = 0, chlen = children.length; i < chlen; i++) { | ||
for (i = 0, chlen = children.length; i < chlen; i++) { | ||
// <"text" kludge> | ||
if (children[i].name() == 'text' && children[i].type() == 'text') { | ||
if (children[i].name() === 'text' && children[i].type() === 'text') { | ||
jsobj['#'] = children[i].text().trim(); | ||
if (jsobj['#'].match(/^\s*$/)) { | ||
delete(jsobj['#']); | ||
} | ||
for (var j = 0, chtlen = children[i].childNodes().length; j < chtlen; j++) { | ||
if (children[i].child(j).name() == 'text') { | ||
for (j = 0, chtlen = children[i].childNodes().length; j < chtlen; j++) { | ||
if (children[i].child(j).name() === 'text') { | ||
var text = {}, textattrs = children[i].child(j).attrs(); | ||
@@ -85,48 +71,56 @@ text['#'] = children[i].child(j).text(); | ||
for (var k = 0, atlen = textattrs.length; k < atlen; i++) { | ||
for (k = 0, atlen = textattrs.length; k < atlen; i++) { | ||
text['@'][textattrs[k].name()] = textattrs[k].value(); | ||
} | ||
jsobj['text'] = text; | ||
jsobj.text = text; | ||
break; // only allow one "<text></text>" element for now | ||
} | ||
} | ||
continue; | ||
} | ||
// </"text" kludge> | ||
var ns = ''; | ||
var namespace = children[i].namespace(); | ||
if (namespace && namespace.prefix() != null) { | ||
ns = namespace.prefix() + ':'; | ||
namespaces[namespace.prefix()] = namespace.href(); | ||
} | ||
var key = ns + children[i].name(); | ||
if (typeof jsobj[key] == 'undefined') { | ||
if (children[i].childNodes().length == 1 && children[i].attrs().length == 0 && (children[i].childNodes()[0].type() == 'text' || children[i].childNodes()[0].type() == 'cdata')) { | ||
var val = children[i].childNodes()[0].toString().trim(); | ||
if (children[i].childNodes()[0].type() == 'cdata') { | ||
val = val.replace(/^\<\!\[CDATA\[/, '').replace(/\]\]\>$/, ''); | ||
} else if (children[i].type() === 'cdata') { | ||
val = children[i].toString().trim(); | ||
val = val.replace(/^<\!\[CDATA\[/, '').replace(/\]\]\>$/, ''); | ||
jsobj['#']=val; | ||
} else { | ||
// </"text" kludge> | ||
var ns = ''; | ||
var namespace = children[i].namespace(); | ||
if (namespace && namespace.prefix() !== null) { | ||
ns = namespace.prefix() + ':'; | ||
namespaces[namespace.prefix()] = namespace.href(); | ||
} | ||
var key = ns + children[i].name(); | ||
if (typeof jsobj[key] === 'undefined') { | ||
if (children[i].childNodes().length === 1 && children[i].attrs().length === 0 && (children[i].childNodes()[0].type() === 'text' || children[i].childNodes()[0].type() === 'cdata')) { | ||
val = children[i].childNodes()[0].toString().trim(); | ||
if (children[i].childNodes()[0].type() === 'cdata') { | ||
val = val.replace(/^<\!\[CDATA\[/, '').replace(/\]\]\>$/, ''); | ||
} | ||
jsobj[key] = val; | ||
} else { | ||
if (children[i].name() !== undefined) { | ||
recValue = libxml2js(children[i], true, namespaces); | ||
jsobj[key] = recValue.jsobj; | ||
merge(namespaces, recValue.namespaces); | ||
} | ||
} | ||
jsobj[key] = val; | ||
} else { | ||
if (children[i].name() !== undefined) { | ||
var recValue = libxml2js(children[i], true, namespaces); | ||
jsobj[key] = recValue.jsobj; | ||
merge(namespaces, recValue.namespaces); | ||
if (typeof jsobj[key] === 'string') { | ||
old = jsobj[key]; | ||
jsobj[key] = []; | ||
jsobj[key].push({'#': old}); | ||
} else if (typeof jsobj[key] === 'object' && jsobj[key].push === undefined) { | ||
old = jsobj[key]; | ||
jsobj[key] = []; | ||
jsobj[key].push(old); | ||
} | ||
} | ||
} else { | ||
if (typeof jsobj[key] == 'string') { | ||
var old = jsobj[key]; | ||
jsobj[key] = []; | ||
jsobj[key].push({'#': old}); | ||
} else if (typeof jsobj[key] == 'object' && ! ('push' in jsobj[key])) { | ||
var old = jsobj[key]; | ||
jsobj[key] = []; | ||
jsobj[key].push(old); | ||
} | ||
var recValue = libxml2js(children[i], true, namespaces); | ||
jsobj[key].push(recValue.jsobj); | ||
merge(namespaces, recValue.namespaces); | ||
recValue = libxml2js(children[i], true, namespaces); | ||
jsobj[key].push(recValue.jsobj); | ||
merge(namespaces, recValue.namespaces); | ||
} | ||
} | ||
@@ -136,3 +130,3 @@ } | ||
if ( ! recurse) { | ||
if (namespaces && ! isEmpty(namespaces)) { | ||
if (namespaces && ! lodash.isEmpty(namespaces)) { | ||
if ( ! jsobj['@']) { | ||
@@ -143,11 +137,19 @@ jsobj['@'] = {}; | ||
} | ||
return jsobj; | ||
} else { | ||
return { | ||
jsobj: jsobj, | ||
namespaces: namespaces | ||
} | ||
} | ||
return { | ||
jsobj: jsobj, | ||
namespaces: namespaces | ||
}; | ||
}; | ||
/** | ||
* The module wrapper, with XPath support | ||
* | ||
* @param {String} xml | ||
* @param {String} xpath | ||
* @param {Function} callback | ||
*/ | ||
module.exports = function (xml, xpath, callback) { | ||
@@ -158,9 +160,13 @@ if ( ! callback) { | ||
} | ||
var xmlDocument, jsDocument, selected = [], xmlns = null, error, result; | ||
try { | ||
xmlDocument = libxmljs.parseXmlString(xml); | ||
jsDocument = libxml2js(xmlDocument); | ||
if (jsDocument['@'] && jsDocument['@'].xmlns) { | ||
xmlns = jsDocument['@'].xmlns; | ||
} | ||
if ( !! xpath) { | ||
@@ -177,5 +183,7 @@ xmlDocument.find(xpath, xmlns).forEach(function(item) { | ||
var code = 0; | ||
if (err && err.message) { | ||
message = err.message; | ||
} | ||
error = new Error(message); | ||
@@ -186,2 +194,3 @@ if (err && err.code) { | ||
} | ||
if ( ! error) { | ||
@@ -188,0 +197,0 @@ callback(null, result); |
{ | ||
"name": "libxml-to-js", | ||
"version": "0.3.10", | ||
"version": "0.3.11", | ||
"main": "./lib/libxml-to-js.js", | ||
"description": "XML to JavaScript object parser based on libxmljs", | ||
"dependencies": { | ||
"libxmljs": ">=0.5.x" | ||
"libxmljs": ">=0.5.x", | ||
"lodash": "*" | ||
}, | ||
@@ -37,2 +38,6 @@ "engines": { | ||
"url": "https://github.com/TokyoIncidents" | ||
}, | ||
{ | ||
"name": "XApp-Studio", | ||
"url": "https://github.com/XApp-Studio" | ||
} | ||
@@ -39,0 +44,0 @@ ], |
@@ -1,4 +0,4 @@ | ||
## About | ||
## About [![build status](https://secure.travis-ci.org/SaltwaterC/libxml-to-js.png?branch=master)](http://travis-ci.org/SaltwaterC/libxml-to-js) ![still maintained](http://stillmaintained.com/SaltwaterC/libxml-to-js.png) | ||
This is a XML to JavaScript object parser. It uses the [libxmljs](https://github.com/polotek/libxmljs) module for the actual XML parsing. It aims to be an easy [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) replacement, but it doesn't follow the xml2js API. I used xml2js for my own needs, but the error reporting of the underlying SAX parser is quite broken. This is how libxml-to-js saw the day light. | ||
This is a XML to JavaScript object parser. It uses the [libxmljs](https://github.com/polotek/libxmljs) module for the actual XML parsing. It aims to be an easy [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) v1 replacement, but it doesn't follow the xml2js API. | ||
@@ -13,2 +13,4 @@ libxml-to-js uses the string parser method of libxmljs. Basically a modified version of the algorithm from [here](http://mscdex.net/code-snippets/) in order to fit the formal specifications of xml2js output. | ||
The installation of the underlying dependency, **libxmljs**, fails if you don't have gcc (or compatible compiler), the [libxml2](http://en.wikipedia.org/wiki/Libxml2) development headers, and the xml2-config script. Under various Linux distributions you may install the appropriate libxml2 development package: libxml2-dev (Debian, Ubuntu, etc), libxml2-devel (RHEL, CentOS, Fedora, etc). | ||
## Usage mode | ||
@@ -87,1 +89,2 @@ | ||
* @[TokyoIncidents](https://github.com/TokyoIncidents): fixes a couple of global variables leaks [#10](https://github.com/SaltwaterC/libxml-to-js/pull/10) | ||
* @[XApp-Studio](https://github.com/XApp-Studio): more support for CDATA elements [#13](https://github.com/SaltwaterC/libxml-to-js/issues/13) |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var parser = require('../'); | ||
@@ -6,9 +8,14 @@ | ||
var callback = false; | ||
var callbackXPath = false; | ||
var common = require('./includes/common.js'); | ||
var callbacks = { | ||
parse: 0, | ||
parseXpath: 0 | ||
}; | ||
var xml = '<thing><real id="width">300</real><real id="height">200</real></thing>'; | ||
parser(xml, function (err, res) { | ||
callback = true; | ||
callbacks.parse++; | ||
assert.ifError(err); | ||
@@ -32,3 +39,4 @@ assert.deepEqual({ | ||
parser(xml, '//thing/real', function (err, res) { | ||
callbackXPath = true; | ||
callbacks.parseXpath++; | ||
assert.ifError(err); | ||
@@ -51,5 +59,2 @@ assert.deepEqual([ | ||
process.on('exit', function () { | ||
assert.ok(callback); | ||
assert.ok(callbackXPath); | ||
}); | ||
common.teardown(callbacks); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var parser = require('../'); | ||
@@ -6,12 +8,15 @@ | ||
var callback = false; | ||
var common = require('./includes/common.js'); | ||
var callbacks = { | ||
parse: 0 | ||
}; | ||
parser('This is a broken XML file.', function (err, res) { | ||
callback = true; | ||
callbacks.parse++; | ||
assert.ok(err instanceof Error); | ||
assert.equal(err.code, 4); | ||
assert.strictEqual(err.code, 4); | ||
}); | ||
process.on('exit', function () { | ||
assert.ok(callback); | ||
}); | ||
common.teardown(callbacks); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var parser = require('../'); | ||
@@ -6,24 +8,29 @@ | ||
var callback = false; | ||
var callbackXPath = false; | ||
var common = require('./includes/common.js'); | ||
var xml = fs.readFileSync('data/ec2-describeimages.xml').toString(); | ||
var callbacks = { | ||
parse: 0, | ||
parseXpath: 0 | ||
}; | ||
parser(xml, function (err, res) { | ||
callback = true; | ||
fs.readFile('data/ec2-describeimages.xml', function (err, xml) { | ||
assert.ifError(err); | ||
assert.equal(res.imagesSet.item[0].imageId, 'ami-be3adfd7'); | ||
assert.equal(res.imagesSet.item[1].imageId, 'ami-be3adfd9'); | ||
parser(xml, function (err, res) { | ||
callbacks.parse++; | ||
assert.ifError(err); | ||
assert.strictEqual(res.imagesSet.item[0].imageId, 'ami-be3adfd7'); | ||
assert.strictEqual(res.imagesSet.item[1].imageId, 'ami-be3adfd9'); | ||
}); | ||
parser(xml, '//xmlns:blockDeviceMapping', function (err, res) { | ||
callbacks.parseXpath++; | ||
assert.ifError(err); | ||
assert.strictEqual(res.length, 2); | ||
assert.strictEqual(res[0].item.deviceName, '/dev/sda'); | ||
}); | ||
}); | ||
parser(xml, '//xmlns:blockDeviceMapping', function (err, res) { | ||
callbackXPath = true; | ||
assert.ifError(err); | ||
assert.strictEqual(res.length, 2); | ||
assert.strictEqual(res[0].item.deviceName, '/dev/sda'); | ||
}); | ||
process.on('exit', function () { | ||
assert.ok(callback); | ||
assert.ok(callbackXPath); | ||
}); | ||
common.teardown(callbacks); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var parser = require('../'); | ||
@@ -6,15 +8,25 @@ | ||
var callback = false; | ||
var common = require('./includes/common.js'); | ||
parser(fs.readFileSync('data/ec2-describevolumes-large.xml').toString(), function (err, res) { | ||
callback = true; | ||
var callbacks = { | ||
parse: 0 | ||
}; | ||
fs.readFile('data/ec2-describevolumes-large.xml', function (err, xml) { | ||
assert.ifError(err); | ||
for (var i in res.volumeSet.item) { | ||
var volume = res.volumeSet.item[i]; | ||
assert.equal(volume.volumeId, 'vol-00000000'); | ||
} | ||
parser(xml, function (err, res) { | ||
var i; | ||
callbacks.parse++; | ||
assert.ifError(err); | ||
for (i in res.volumeSet.item) { | ||
if (res.volumeSet.item.hasOwnProperty(i)) { | ||
var volume = res.volumeSet.item[i]; | ||
assert.strictEqual(volume.volumeId, 'vol-00000000'); | ||
} | ||
} | ||
}); | ||
}); | ||
process.on('exit', function () { | ||
assert.ok(callback); | ||
}); | ||
common.teardown(callbacks); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var parser = require('../'); | ||
@@ -6,19 +8,29 @@ | ||
var callback = false; | ||
var common = require('./includes/common.js'); | ||
parser(fs.readFileSync('data/namespace.xml').toString(), function (err, res) { | ||
callback = true; | ||
assert.ifError(err); | ||
assert.equal(res['@'].xmlns.atom, 'http://www.w3.org/2005/Atom'); | ||
for (var i in res['atom:link']) { | ||
var atom = res['atom:link'][i]; | ||
assert.equal(atom['@'].rel, 'self'); | ||
assert.equal(atom['@'].type, 'application/rss+xml'); | ||
} | ||
assert.equal(res['atom:link'][0]['@'].href, 'http://localhost/wordpress/?feed=rss'); | ||
assert.equal(res['atom:link'][1]['@'].href, 'http://localhost/wordpress/?feed=rss2'); | ||
var callbacks = { | ||
parse: 0 | ||
}; | ||
fs.readFile('data/namespace.xml', function (err, xml) { | ||
parser(xml, function (err, res) { | ||
var i; | ||
callbacks.parse++; | ||
assert.ifError(err); | ||
assert.strictEqual(res['@'].xmlns.atom, 'http://www.w3.org/2005/Atom'); | ||
for (i in res['atom:link']) { | ||
if (res['atom:link'].hasOwnProperty(i)) { | ||
var atom = res['atom:link'][i]; | ||
assert.strictEqual(atom['@'].rel, 'self'); | ||
assert.strictEqual(atom['@'].type, 'application/rss+xml'); | ||
} | ||
} | ||
assert.strictEqual(res['atom:link'][0]['@'].href, 'http://localhost/wordpress/?feed=rss'); | ||
assert.strictEqual(res['atom:link'][1]['@'].href, 'http://localhost/wordpress/?feed=rss2'); | ||
}); | ||
}); | ||
process.on('exit', function () { | ||
assert.ok(callback); | ||
}); | ||
common.teardown(callbacks); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var parser = require('../'); | ||
@@ -6,54 +8,58 @@ | ||
var callback = false; | ||
var callbackXPath = false; | ||
var common = require('./includes/common.js'); | ||
var xml = fs.readFileSync('data/text.xml').toString(); | ||
var callbacks = { | ||
parse: 0, | ||
parseXpath: 0 | ||
}; | ||
parser(xml, function (err, res) { | ||
callback = true; | ||
fs.readFile('data/text.xml', function (err, xml) { | ||
assert.ifError(err); | ||
assert.deepEqual({ | ||
'news': [{ | ||
parser(xml, function (err, res) { | ||
callbacks.parse++; | ||
assert.ifError(err); | ||
assert.deepEqual({ | ||
'news': [{ | ||
"auteur": "Bizzard5", | ||
"date": "17 Août 2008", | ||
"text": {} | ||
}, { | ||
"auteur": "Little", | ||
"date": "18 Août 2007", | ||
"text": { | ||
"test": "test" | ||
} | ||
}, { | ||
"auteur": "Bizzard5", | ||
"date": "17 Août 2008", | ||
"text": "C'est un teste" | ||
}, { | ||
"auteur": "Little", | ||
"date": "18 Août 2007", | ||
"text": "Allo" | ||
}, { | ||
"auteur": "Little", | ||
"date": "18 Août 2007", | ||
"text": { | ||
"text": "test" | ||
} | ||
}] | ||
}, | ||
res); | ||
}); | ||
parser(xml, '//nouvelle/news', function (err, res) { | ||
callbacks.parseXpath++; | ||
assert.ifError(err); | ||
assert.deepEqual({ | ||
"auteur": "Bizzard5", | ||
"date": "17 Août 2008", | ||
"text": {} | ||
}, { | ||
"auteur": "Little", | ||
"date": "18 Août 2007", | ||
"text": { | ||
"test": "test" | ||
} | ||
}, { | ||
"auteur": "Bizzard5", | ||
"date": "17 Août 2008", | ||
"text": "C'est un teste" | ||
}, { | ||
"auteur": "Little", | ||
"date": "18 Août 2007", | ||
"text": "Allo" | ||
}, { | ||
"auteur": "Little", | ||
"date": "18 Août 2007", | ||
"text": { | ||
"text": "test" | ||
} | ||
}] | ||
}, | ||
res); | ||
}, | ||
res[0]); | ||
}); | ||
}); | ||
parser(xml, '//nouvelle/news', function (err, res) { | ||
callbackXPath = true; | ||
assert.ifError(err); | ||
assert.deepEqual({ | ||
"auteur": "Bizzard5", | ||
"date": "17 Août 2008", | ||
"text": {} | ||
}, | ||
res[0]); | ||
}); | ||
process.on('exit', function () { | ||
assert.ok(callback); | ||
assert.ok(callbackXPath); | ||
}); | ||
common.teardown(callbacks); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var parser = require('../'); | ||
@@ -6,28 +8,33 @@ | ||
var callback = false; | ||
var callbackXPath = false; | ||
var common = require('./includes/common.js'); | ||
var xml = fs.readFileSync('data/wordpress-rss2.xml').toString(); | ||
var callbacks = { | ||
parse: 0, | ||
parseXpath: 0 | ||
}; | ||
parser(xml, function (err, res) { | ||
callback = true; | ||
fs.readFile('data/wordpress-rss2.xml', function (err, xml) { | ||
assert.ifError(err); | ||
assert.equal(res['@'].version, '2.0'); | ||
assert.equal(res['@'].xmlns.atom, 'http://www.w3.org/2005/Atom'); | ||
assert.equal(res.channel.title, 'WordPress'); | ||
assert.equal(res.channel['atom:link']['@'].href, 'http://localhost/wordpress/?feed=rss2'); | ||
assert.equal(res.channel.item.title, 'Hello world!'); | ||
assert.equal(res.channel.item.category, 'Uncategorized'); // CDATA element | ||
parser(xml, function (err, res) { | ||
callbacks.parse++; | ||
assert.ifError(err); | ||
assert.strictEqual(res['@'].version, '2.0'); | ||
assert.strictEqual(res['@'].xmlns.atom, 'http://www.w3.org/2005/Atom'); | ||
assert.strictEqual(res.channel.title, 'WordPress'); | ||
assert.strictEqual(res.channel['atom:link']['@'].href, 'http://localhost/wordpress/?feed=rss2'); | ||
assert.strictEqual(res.channel.item.title, 'Hello world!'); | ||
assert.strictEqual(res.channel.item.category, 'Uncategorized'); // CDATA element | ||
}); | ||
parser(xml, '//dc:creator', function (err, res) { | ||
callbacks.parseXpath++; | ||
assert.ifError(err); | ||
assert.strictEqual(res.length, 1); | ||
assert.strictEqual(res[0]['#'], 'admin'); | ||
}); | ||
}); | ||
parser(xml, '//dc:creator', function (err, res) { | ||
callbackXPath = true; | ||
assert.ifError(err); | ||
assert.strictEqual(res.length, 1); | ||
assert.strictEqual(res[0]['#'], 'admin'); | ||
}); | ||
process.on('exit', function () { | ||
assert.ok(callback); | ||
assert.ok(callbackXPath); | ||
}); | ||
common.teardown(callbacks); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
73463
27
439
89
2
2
9
+ Addedlodash@*
+ Addedlodash@4.17.21(transitive)