- - By Craig Buckler

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:

  • No distinction is made between XML attributes and child elements — if they have the same name, an array of items will be returned with the attribute at index 0.
  • XML2jsobj should only be used when it’s practical. If you are retrieving just one or two XML node values, accessing them with DOM or XPath methods would be faster.
  • The code is cross-browser compatible (including IE6) and can process large XML documents quickly. That said, it may not be suitable for every situation. It probably shouldn’t be used in preference to returning JSON from your server.
  • 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!

    Sponsors