Skip to content
This repository was archived by the owner on Jan 7, 2021. It is now read-only.

Commit 8407d45

Browse files
committed
adds json2xml parser
1 parent b7d5598 commit 8407d45

6 files changed

Lines changed: 165 additions & 135 deletions

File tree

lib/index.js

Lines changed: 3 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,4 @@
1-
var expat = require('node-expat');
2-
var fs = require('fs');
3-
4-
// This object will hold the final result.
5-
var obj = currentObject = {};
6-
var ancestors = [];
7-
8-
var options = {}; //configuration options
9-
10-
function startElement(name, attrs) {
11-
if (! (name in currentObject)) {
12-
currentObject[name] = attrs;
13-
} else if (! (currentObject[name] instanceof Array)) {
14-
// Put the existing object in an array.
15-
var newArray = [currentObject[name]];
16-
// Add the new object to the array.
17-
newArray.push(attrs);
18-
// Point to the new array.
19-
currentObject[name] = newArray;
20-
} else {
21-
// An array already exists, push the attributes on to it.
22-
currentObject[name].push(attrs);
23-
}
24-
25-
// Store the current (old) parent.
26-
ancestors.push(currentObject);
27-
28-
// We are now working with this object, so it becomes the current parent.
29-
if (currentObject[name] instanceof Array) {
30-
// If it is an array, get the last element of the array.
31-
currentObject = currentObject[name][currentObject[name].length - 1];
32-
} else {
33-
// Otherwise, use the object itself.
34-
currentObject = currentObject[name];
35-
}
36-
}
37-
38-
function text(data) {
39-
data = data.trim();
40-
if (!data.length) {
41-
return;
42-
}
43-
currentObject['$t'] = data;
44-
}
45-
46-
function endElement(name) {
47-
// This should check to make sure that the name we're ending
48-
// matches the name we started on.
49-
var ancestor = ancestors.pop();
50-
if (!options.reversible) {
51-
if ((Object.keys(currentObject).length == 1) && ('$t' in currentObject)) {
52-
if (ancestor[name] instanceof Array) {
53-
//console.log("list-replacing $t in " + name);
54-
ancestor[name].push(ancestor[name].pop()['$t']);
55-
} else {
56-
//console.log("replacing $t in " + name);
57-
ancestor[name] = currentObject['$t'];
58-
}
59-
} else {
60-
//console.log("final " + name + ":");
61-
//console.log(currentObject);
62-
}
63-
}
64-
65-
currentObject = ancestor;
66-
}
67-
68-
69-
module.exports.toJson = function(xml, _options) {
70-
var parser = new expat.Parser('UTF-8');
71-
72-
parser.on('startElement', startElement);
73-
parser.on('text', text);
74-
parser.on('endElement', endElement);
75-
76-
obj = currentObject = {};
77-
ancestors = [];
78-
79-
options = {
80-
object: false,
81-
reversible: false
82-
};
83-
84-
for (var opt in _options) {
85-
options[opt] = _options[opt];
86-
}
87-
88-
if (!parser.parse(xml)) {
89-
console.log('-->'+ xml + '<--');
90-
throw new Error('There are errors in your xml file: ' + parser.getError());
91-
}
92-
93-
if (options.object) {
94-
return obj;
95-
}
96-
97-
return JSON.stringify(obj);
98-
};
1+
var exports = module.exports;
992

3+
exports.toJson = require('./xml2json');
4+
exports.toXml = require('./json2xml');

lib/json2xml.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
var xml = '';
2+
module.exports = function toXml(json) {
3+
if (json instanceof Buffer) {
4+
json = json.toString();
5+
}
6+
7+
var obj = null;
8+
if (typeof(json) == 'string') {
9+
try {
10+
obj = JSON.parse(json);
11+
} catch(e) {
12+
throw new Error("The JSON structure is invalid");
13+
}
14+
} else {
15+
obj = json;
16+
}
17+
18+
var keys = Object.keys(obj);
19+
var len = keys.length;
20+
21+
for (var i = 0; i < len; i++) {
22+
var key = keys[i];
23+
24+
if (Array.isArray(obj[key])) {
25+
var elems = obj[key];
26+
var l = elems.length;
27+
for (var j = 0; j < l; j++) {
28+
xml += '<' + key + '>';
29+
toXml(elems[j]);
30+
xml += '</' + key + '>';
31+
}
32+
} else if (typeof(obj[key]) == 'object') {
33+
xml += '<' + key + '>';
34+
toXml(obj[key]);
35+
xml += '</' + key + '>';
36+
} else if (typeof(obj[key]) == 'string') {
37+
if (key == '$t') {
38+
xml += obj[key];
39+
} else {
40+
xml = xml.replace(/>$/, '');
41+
xml += ' ' + key + "='" + obj[key] + "'>";
42+
}
43+
}
44+
}
45+
46+
return xml;
47+
};
48+

lib/xml2json.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
var expat = require('node-expat');
2+
var fs = require('fs');
3+
4+
// This object will hold the final result.
5+
var obj = currentObject = {};
6+
var ancestors = [];
7+
8+
var options = {}; //configuration options
9+
function startElement(name, attrs) {
10+
if (! (name in currentObject)) {
11+
currentObject[name] = attrs;
12+
} else if (! (currentObject[name] instanceof Array)) {
13+
// Put the existing object in an array.
14+
var newArray = [currentObject[name]];
15+
// Add the new object to the array.
16+
newArray.push(attrs);
17+
// Point to the new array.
18+
currentObject[name] = newArray;
19+
} else {
20+
// An array already exists, push the attributes on to it.
21+
currentObject[name].push(attrs);
22+
}
23+
24+
// Store the current (old) parent.
25+
ancestors.push(currentObject);
26+
27+
// We are now working with this object, so it becomes the current parent.
28+
if (currentObject[name] instanceof Array) {
29+
// If it is an array, get the last element of the array.
30+
currentObject = currentObject[name][currentObject[name].length - 1];
31+
} else {
32+
// Otherwise, use the object itself.
33+
currentObject = currentObject[name];
34+
}
35+
}
36+
37+
function text(data) {
38+
data = data.trim();
39+
if (!data.length) {
40+
return;
41+
}
42+
currentObject['$t'] = data;
43+
}
44+
45+
function endElement(name) {
46+
// This should check to make sure that the name we're ending
47+
// matches the name we started on.
48+
var ancestor = ancestors.pop();
49+
if (!options.reversible) {
50+
if ((Object.keys(currentObject).length == 1) && ('$t' in currentObject)) {
51+
if (ancestor[name] instanceof Array) {
52+
ancestor[name].push(ancestor[name].pop()['$t']);
53+
} else {
54+
ancestor[name] = currentObject['$t'];
55+
}
56+
}
57+
}
58+
59+
currentObject = ancestor;
60+
}
61+
62+
module.exports = function(xml, _options) {
63+
var parser = new expat.Parser('UTF-8');
64+
65+
parser.on('startElement', startElement);
66+
parser.on('text', text);
67+
parser.on('endElement', endElement);
68+
69+
obj = currentObject = {};
70+
ancestors = [];
71+
72+
options = {
73+
object: false,
74+
reversible: false
75+
};
76+
77+
for (var opt in _options) {
78+
options[opt] = _options[opt];
79+
}
80+
81+
if (!parser.parse(xml)) {
82+
console.log('-->' + xml + '<--');
83+
throw new Error('There are errors in your xml file: ' + parser.getError());
84+
}
85+
86+
if (options.object) {
87+
return obj;
88+
}
89+
90+
return JSON.stringify(obj);
91+
};
92+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"domain":{"type":"qemu","name":{"$t":"QEmu-fedora-i686"},"uuid":{"$t":"c7a5fdbd-cdaf-9455-926a-d65c16db1809"},"memory":{"$t":"219200"},"currentMemory":{"$t":"219200"},"vcpu":{"$t":"2"},"os":{"type":{"arch":"i686","machine":"pc","$t":"hvm"},"boot":{"dev":"cdrom"}},"devices":{"emulator":{"$t":"/usr/bin/qemu-system-x86_64"},"disk":[{"type":"file","device":"cdrom","source":{"file":"/home/user/boot.iso"},"target":{"dev":"hdc"},"readonly":{}},{"type":"file","device":"disk","source":{"file":"/home/user/fedora.img"},"target":{"dev":"hda"}}],"interface":{"type":"network","source":{"network":"default"}},"graphics":{"type":"vnc","port":"-1"}},"ah":[{"type":"rare","foo":"bar","$t":"cosa1"},{"type":"normal","$t":"cosa2"},{"$t":"cosa3"}]}}

test/fixtures/domain.xml

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1 @@
1-
<domain type='qemu'>
2-
<name>QEmu-fedora-i686</name>
3-
<uuid>c7a5fdbd-cdaf-9455-926a-d65c16db1809</uuid>
4-
<memory>219200</memory>
5-
<currentMemory>219200</currentMemory>
6-
<vcpu>2</vcpu>
7-
<os>
8-
<type arch='i686' machine='pc'>hvm</type>
9-
<boot dev='cdrom'/>
10-
</os>
11-
<devices>
12-
<emulator>/usr/bin/qemu-system-x86_64</emulator>
13-
<disk type='file' device='cdrom'>
14-
<source file='/home/user/boot.iso'/>
15-
<target dev='hdc'/>
16-
<readonly/>
17-
</disk>
18-
<disk type='file' device='disk'>
19-
<source file='/home/user/fedora.img'/>
20-
<target dev='hda'/>
21-
</disk>
22-
<interface type='network'>
23-
<source network='default'/>
24-
</interface>
25-
<graphics type='vnc' port='-1'/>
26-
</devices>
27-
<ah type='rare' foo='bar'>cosa1</ah>
28-
<ah type='normal'>cosa2</ah>
29-
<ah>cosa3</ah>
30-
</domain>
1+
<domain type='qemu'><name>QEmu-fedora-i686</name><uuid>c7a5fdbd-cdaf-9455-926a-d65c16db1809</uuid><memory>219200</memory><currentMemory>219200</currentMemory><vcpu>2</vcpu><os><type arch='i686' machine='pc'>hvm</type><boot dev='cdrom'></boot></os><devices><emulator>/usr/bin/qemu-system-x86_64</emulator><disk type='file' device='cdrom'><source file='/home/user/boot.iso'></source><target dev='hdc'></target><readonly></readonly></disk><disk type='file' device='disk'><source file='/home/user/fedora.img'></source><target dev='hda'></target></disk><interface type='network'><source network='default'></source></interface><graphics type='vnc' port='-1'></graphics></devices><ah type='rare' foo='bar'>cosa1</ah><ah type='normal'>cosa2</ah><ah>cosa3</ah></domain>

test/test.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,35 @@ fs.readdir(fixturesPath, function(err, files) {
1414
var basename = path.basename(file, '.xml');
1515

1616
var data = fs.readFileSync(fixturesPath + '/' + file);
17-
var result = parser.toJson(data);
17+
var result = parser.toJson(data, {reversible: true});
18+
1819
var data2 = fs.readFileSync(fixturesPath + '/' + file);
1920
result = parser.toJson(data2);
2021

21-
var jsonFile = basename + '.json'
22+
var jsonFile = basename + '.json';
2223
var expected = fs.readFileSync(fixturesPath + '/' + jsonFile) + '';
2324

24-
if (result) {
25-
result = result.trim();
26-
}
27-
2825
if (expected) {
2926
expected = expected.trim();
3027
}
3128
assert.deepEqual(result, expected, jsonFile + ' and ' + file + ' are different');
32-
console.log('All tests passed!');
29+
console.log('[xml2json: ' + file + '->' + jsonFile + '] passed!');
30+
} else if( ext == '.json') {
31+
var basename = path.basename(file, '.json');
32+
if (basename.match('reversible')) {
33+
var data = fs.readFileSync(fixturesPath + '/' + file);
34+
var result = parser.toXml(data);
35+
36+
var xmlFile = basename.split('-')[0] + '.xml';
37+
var expected = fs.readFileSync(fixturesPath + '/' + xmlFile) + '';
38+
39+
if (expected) {
40+
expected = expected.trim();
41+
}
42+
//console.log(result + '<---');
43+
assert.deepEqual(result, expected, xmlFile + ' and ' + file + ' are different');
44+
console.log('[json2xml: ' + file + '->' + xmlFile + '] passed!');
45+
}
3346
}
3447
}
3548
});

0 commit comments

Comments
 (0)