How to Convert XML to a JSON-Like JavaScript Object
In my post How to Create an XML to JSON Proxy Server in PHP we created a system which translated XML messages into Ajax-ready JSON. That’s great if you’re running PHP or another suitable server-side process. But what if you’re limited to JavaScript only?
Randomly accessing data from an XML document isn’t fun. You can use DOM or XPath methods, but they’re not as easy as native (JSON-generated) JavaScript object properties such as myobj.list[0].property1
. If you’re frequently accessing data from the same XML document, it may be practical to translate it to a JavaScript object first. Ready to write some code?…
The XML2jsobj Function
We’re going to write a function which recursively analyzes each node of an XML document’s DOM tree and returns a JavaScript object. The function is passed a starting node — which will normally be the root documentElement — and returns an object (internally named data):
function XML2jsobj(node) {
var data = {};
We’ll now define an Add() function within XML2jsobj. This appends a name/value pair to the data object, e.g. data[name] = value. However, if that name already exists, it must convert data[name] to an array so two or more values can be applied:
// append a value
function Add(name, value) {
if (data[name]) {
if (data[name].constructor != Array) {
data[name] = [data[name]];
}
data[name][data[name].length] = value;
}
else {
data[name] = value;
}
};
We now require a loop to examine the XML node’s attributes (e.g. <node attrib1="1" attrib2="2">) and append them to the data object using the Add() function:
// element attributes var c, cn; for (c = 0; cn = node.attributes
; c++) {
Add(cn.name, cn.value);
}
The next loop examines all child nodes. Comments and white space are ignored but, if a child contains a single item of textual data, it’s appended to the data object using Add(). If that child has its own children, we recursively call XML2jsobj to generate the object:
// child elements for (c = 0; cn = node.childNodes
; c++) {
if (cn.nodeType == 1) {
if (cn.childNodes.length == 1 && cn.firstChild.nodeType == 3) {
// text value
Add(cn.nodeName, cn.firstChild.nodeValue);
}
else {
// sub-object
Add(cn.nodeName, XML2jsobj(cn));
}
}
}
Finally, we return the data object to our calling function:
return data; }
Converting XML
Our Ajax call can retrieve XML from a web service:
// example XML feed var url = "example.xml"; // AJAX request var xhr = (window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")); xhr.onreadystatechange = XHRhandler; xhr.open("GET", url, true); xhr.send(null);
Our XMLHttpRequest onreadystatechange handler receives the XML data and converts it to JavaScript object:
// handle response function XHRhandler() { if (xhr.readyState == 4) { var obj = XML2jsobj(xhr.responseXML.documentElement); // do something with our returned data... console.log(obj); xhr = null; } }
So, if example.xml returned the following XML data:
<?xml version="1.0"?> <statuses> <status id="one"> <id>1</id> <text>Hello!</text> </status> </statuses>
XML2jsobj(xhr.responseXML.documentElement) would return the following object:
{ status: { id: ["one", 1], text: "Hello!" } }
You can therefore use obj.status.text to retrieve the “Hello!” text.
Buyer Beware!
A few notes about XML2jsobj:
Grab the Code
Please view the demonstration page or download the code and examples for your own projects.
I hope you find it useful — let me know if eases a few XML headaches!