Import XML Document

At the moment it only works in Explorer 5+ on Windows and Mozilla.

Mark Wilton-Jones wrote a script that makes XML importing work in the other browsers, by using a hidden iframe to receive the XML and then reading out the data from the hidden iframe.

Many thanks to Dylan Schiemann for putting me on the right track with the importing of XML documents.

On this page I import an XML document and then read out the data and put them in a table on the page.

I think importing XML documents will become more and more important in the future. You can manage the XML document as a kind of database, while the HTML document contains all information about the displaying of the data.

Anyway, try it first by clicking the link and loading some crucial information about the Roman emperors of the Julian-Claudian dynasty. You can also view the XML document separately.

First I import the document emperors.xml, then I enter the XML document through the W3C DOM and extract the data I need, while building a table to display the data.

The script

function importXML()
{
	if (document.implementation && document.implementation.createDocument)
	{
		xmlDoc = document.implementation.createDocument("", "", null);
		xmlDoc.onload = createTable;
	}
	else if (window.ActiveXObject)
	{
		xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.onreadystatechange = function () {
			if (xmlDoc.readyState == 4) createTable()
		};
 	}
	else
	{
		alert('Your browser can\'t handle this script');
		return;
	}
	xmlDoc.load("emperors.xml");
}

function createTable()
{
	var x = xmlDoc.getElementsByTagName('emperor');
	var newEl = document.createElement('TABLE');
	newEl.setAttribute('cellPadding',5);
	var tmp = document.createElement('TBODY');
	newEl.appendChild(tmp);
	var row = document.createElement('TR');
	for (j=0;j<x[0].childNodes.length;j++)
	{
		if (x[0].childNodes[j].nodeType != 1) continue;
		var container = document.createElement('TH');
		var theData = document.createTextNode(x[0].childNodes[j].nodeName);
		container.appendChild(theData);
		row.appendChild(container);
	}
	tmp.appendChild(row);
	for (i=0;i<x.length;i++)
	{
		var row = document.createElement('TR');
		for (j=0;j<x[i].childNodes.length;j++)
		{
			if (x[i].childNodes[j].nodeType != 1) continue;
			var container = document.createElement('TD');
			var theData = document.createTextNode(x[i].childNodes[j].firstChild.nodeValue);
			container.appendChild(theData);
			row.appendChild(container);
		}
		tmp.appendChild(row);
	}
	document.getElementById('writeroot').appendChild(newEl);
}

Importing the XML

First of all I import the XML document and make it accessible through the object xmlDoc. When the document has finished loading, I want the script createTable() that construes the table to be executed immediately. Of course, the coding for all this is browser specific.

Clicking the link activates the function importXML.

function importXML()
{

Mozilla

Netscape imports an XML document through the method document.implementation.createDocument(). First check if document.implementation is supported, then check if document.implementation.createDocument() is supported. Explorer 5 on Mac also supports document.implementation, but not the createDocument method, so it shouldn't execute this script.

	if (document.implementation && document.implementation.createDocument)
	{

Then create the document and give it an onLoad event handler: as soon as the document has been loaded the script createTable() is executed, creating the table:

		xmlDoc = document.implementation.createDocument("", "", null);
		xmlDoc.onload = init;
	}

Explorer

Explorer on Windows doesn't support document.implementation . Instead, you must create an Active X Object that will contain the XML document. So we see if the browser can create ActiveXObjects:

	else if (window.ActiveXObject)
	{

If it does, we can proceed by creating the object

		xmlDoc = new ActiveXObject("Microsoft.XMLDOM");

Unfortunately there's no onLoad event for this object. To see if it's ready we should use the MS proprietary ReadyStateChange event. I don't quite understand all this myself, but it works. When the onReadyStateChange event handler fires, the readyState has a value between 1 and 4. 4 means that all data has been received (= onLoad). So if it's 4, start creating the table.

		xmlDoc.onreadystatechange = function () {
			if (xmlDoc.readyState == 4) createTable()
		};
	}

Other browsers

If the browser supports neither way, give an alert and end everything:

	else
	{
		alert('Your browser can\'t handle this script');
		return;
	}

Load document

Finally, load the actual document. Surprisingly, the command for this is the same in both browsers:

	xmlDoc.load("emperors.xml");
}

Now we wait for the XML document to be loaded completely, then the function createTable() is started up.

Strangely, Mozilla sometimes only accepts a URL to the XML file that is relative to the page with the script, which in practice means that you can only access local XML files. Only the Linux version does accept absolute paths in all cases.

You might be able to solve the problem by putting the page containing the script on a real web server instead of a local host. However, this does not help in all cases.

Creating output

This function is entirely specific for the XML document I created. Each XML document is different, each way of displaying the content is different, so the function I wrote is only an example.

The XML document

The XML document consists of nodes named <emperor>, which all contain the same children. As an example, this is the structure of the first node:

                                  <emperor>
                                      |
                  ------------------------------------------
                  |                   |                    |
               <name>              <rule>               <death>
                  |                   |                    |
              Augustus            27BC-14AD             Peaceful

In the script below I assume that every emperor has this structure. If one hasn't, it could lead to huge problems, but this way I keep the script simple.

Creating the table

Function createTable() starts by creating an array of all the tags <emperor> in the XML document. For each of these tags I want to create a TR containing several TD's with the data.

function createTable()
{
	var x = xmlDoc.getElementsByTagName('emperor');

Then we create a new TABLE with CELLPADDING=5. Note the special spelling cellPadding, Explorer requires this and it doesn't hurt Netscape.

	var newEl = document.createElement('TABLE');
	newEl.setAttribute('cellPadding',5);

Explorer requires that we also create a TBODY and append it to the table. Don't ask me why, I think TBODY is a completely useless tag, but without it the example doesn't work in Explorer.

	var tmp = document.createElement('TBODY');
	newEl.appendChild(tmp);

First of all, a row with TH's for the headers. Create a TR

	var row = document.createElement('TR');

then go through the childNodes of the first emperor.

	for (j=0;j<x[0].childNodes.length;j++)
	{

A problem here: the XML document looks like this:

	<emperor>
		<name>

which means that Netscape considers the empty text node between emperor and name as the first child of emperor. Since these nodes are only a nuisance, we have to check if the nodeType of the childNode is 1 (= it's a tag). If it isn't, continue with the next child:

		if (x[0].childNodes[j].nodeType != 1) continue;

Create a container element (TH):

		var container = document.createElement('TH');

then read out the name of the childNode (ie. name, rule and death). I want these names to be printed inside the TH. So first I append the name to the TH, then I append the container to the TR

		var theData = document.createTextNode(x[0].childNodes[j].nodeName);
		container.appendChild(theData);
		row.appendChild(container);
	}

Finally, append the row to the TBODY tag

	tmp.appendChild(row);

Then we go through all elements emperor and create a TR for each one

	for (i=0;i<x.length;i++)
	{
		var row = document.createElement('TR');

Go through the childNodes of each emperor, check if it's a node (tag) and create a TD to hold the data

		for (j=0;j<x[i].childNodes.length;j++)
		{
			if (x[i].childNodes[j].nodeType != 1) continue;
			var container = document.createElement('TD');

Then extract the actual data. Remember that the text inside a tag is the nodeValue of the first childNode of that tag

			var theData = document.createTextNode(x[i].childNodes[j].firstChild.nodeValue);

Append the text to the TD and the TD to the TR

			container.appendChild(theData);
			row.appendChild(container);
		}

and when you've finished going through the emperor, append the TR to the TBODY

		tmp.appendChild(row);
	}

Finally, when you've gone through each emperor, append the TABLE to the special P with ID="writeroot" I created:

	document.getElementById('writeroot').appendChild(newEl);
}

and a table has been magically created.