faqts : Computers : Programming : Languages : JavaScript : XML

+ Search
Add Entry AlertManage Folder Edit Entry Add page to http://del.icio.us/
Did You Find This Entry Useful?

248 of 301 people (82%) answered Yes
Recently 6 of 10 people (60%) answered Yes

Entry

How can I load an XML document to script it with DOM methods?

Mar 20th, 2005 04:27
Martin Honnen, http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/xmobjXMLHttpRequest.asp http://www.xulplanet.com/references/objref/XMLHttpRequest.html


IE5+/Win provides several ways, there are two ways using a scriptable
ActiveXObject, the first creating an empty XMLDOM document and using its
load method to load and parse the XML data, the second using the more
versatile XMLHTTP ActiveXObject to make a HTTP request and have the
response parsed as XML in the form of the responseXML property. And
there is a third way in IE using so called XML data islands in an HTML
document. All those ways make use of MSXML, Microsoft's COM based XML
software package, which exists in different versions, IE 6 comes with
MSXML 3.
With other browsers there are different ways, Mozilla (respectively
Mozilla based browsers like Netscape 6/7) was the first to expose the
XMLHttpRequest constructor function to client-side script in an attempt
to give scripters in Mozilla the same API as the XMLHTTP ActiveXObject
of MSXML 3 provides. By now other browser like Safari (since version 1.2
I think) and Opera (since version 7.60 preview respectively 8.00 beta)
have followed to implement XMLHttpRequest although so far it has to be
said that unfortunately those implementations are not as complete as the
MSXML respectively Mozilla implementation.
Nevertheless, currently your best bet across browsers to load an XML
document from a URL to get a scriptable DOM document is to use XMLHTTP
in IE respectively XMLHttpRequest in Mozilla and other browsers, only
the creation of the request object differs, then you have a compatible
API, you use the open method to make a GET request with the URL as the
second parameter, you set up an onreadystatechange event handler to
check when the readyState is 4 (means complete) and the HTTP response
status is 200 and then you can access the responseXML property which is
a DOM XML document being automatically created, of course all the action
in the onreadystatechange handler happening after the HTTP request has
been started by calling send(null).
Here is an example for asynchronous loading, the preferred way with
client-side script in current browsers where synchrous loading would
block the browser user interface unnecessarily:
--- asynchronous loading with XMLHTTP/XMLHttpRequest ----------------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
          "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Asynchronous loading with XMLHttpRequest</title>
<script type="text/javascript">
function loadXMLFromURL (url, loadHandler) {
  var httpRequest = null;
  if (typeof XMLHttpRequest != 'undefined') {
    httpRequest = new XMLHttpRequest();
  }
  else if (typeof ActiveXObject != 'undefined') {
    /*@cc_on @*/
    /*@if (@_jscript_version >= 5)
    try {
      httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
    }
    catch (e) { }
    @end @*/  
  }
  if (httpRequest != null) {
    httpRequest.open('GET', url, true);
    httpRequest.onreadystatechange = function () {
      if (httpRequest.readyState == 4 && httpRequest.status == 200) {
        loadHandler(httpRequest.responseXML);
      }
    };
    httpRequest.send(null);
  }
}
</script>
<script type="text/javascript">
function exampleLoadHandler (xmlDocument) {
  // process XML document here with W3C DOM
  // e.g. check document element
  output(xmlDocument.documentElement.nodeName); // shows 'gods'
  // access elements
  var godElements = xmlDocument.getElementsByTagName('god');
  output('Found ' + godElements.length + ' <god> elements.');// shows 2
  // access attribute
  output(godElements[0].getAttribute('home'));
  // create new element and insert
  var newGod = xmlDocument.createElement('god');
  newGod.appendChild(xmlDocument.createTextNode('Maho'));
  xmlDocument.documentElement.appendChild(newGod);
}
function output (text) {
  document.forms.gui.elements.output.value +=
    text + '\r\n';
}
window.onload = function (evt) {
  loadXMLFromURL('test2005032001.xml', exampleLoadHandler);
};
</script>
</head>
<body>
<h1>Asynchronous loading with XMLHttpRequest</h1>
<form name="gui"
      action="" onsubmit="return true;">
<div>
<input type="button" value="load"
       onclick="loadXMLFromURL('test2005032001.xml', exampleLoadHandler);">
</div>
<div>
<label>
debug output:
<br>
<textarea name="output" rows="10" cols="80"></textarea>
</label>
</div>
</form>
</body>
</html>
The example XML at URL test2005032001.xml looks as follows:
<?xml version="1.0" encoding="UTF-8"?>
<gods>
  <god home="http://www.kibo.com/">Kibo</god>
  <god>Xibo</god>
</gods>
For completeness we show synchronous loading too, but keep in mind that
it is usually not a good way as the script blocks the browser user
interface while waiting for the HTTP response after the send method has
been executed:
--- synchronous loading with XMLHTTP/XMLHttpRequest -----------------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
          "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Asynchronous loading with XMLHttpRequest</title>
<script type="text/javascript">
function loadXMLFromURL (url, loadHandler) {
  var httpRequest = null;
  if (typeof XMLHttpRequest != 'undefined') {
    httpRequest = new XMLHttpRequest();
  }
  else if (typeof ActiveXObject != 'undefined') {
    /*@cc_on @*/
    /*@if (@_jscript_version >= 5)
    try {
      httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
    }
    catch (e) { }
    @end @*/  
  }
  if (httpRequest != null) {
    httpRequest.open('GET', url, false);
    httpRequest.send(null);
    loadHandler(httpRequest.responseXML);
  }
}
</script>
<script type="text/javascript">
function exampleLoadHandler (xmlDocument) {
  // process XML document here with W3C DOM
  // e.g. check document element
  output(xmlDocument.documentElement.nodeName); // shows 'gods'
  // access elements
  var godElements = xmlDocument.getElementsByTagName('god');
  output('Found ' + godElements.length + ' <god> elements.');// shows 2
  // access attribute
  output(godElements[0].getAttribute('home'));
  // create new element and insert
  var newGod = xmlDocument.createElement('god');
  newGod.appendChild(xmlDocument.createTextNode('Maho'));
  xmlDocument.documentElement.appendChild(newGod);
}
function output (text) {
  document.forms.gui.elements.output.value +=
    text + '\r\n';
}
window.onload = function (evt) {
  loadXMLFromURL('test2005032001.xml', exampleLoadHandler);
};
</script>
</head>
<body>
<h1>Asynchronous loading with XMLHttpRequest</h1>
<form name="gui"
      action="" onsubmit="return true;">
<div>
<input type="button" value="load"
       onclick="loadXMLFromURL('test2005032001.xml', exampleLoadHandler);">
</div>
<div>
<label>
debug output:
<br>
<textarea name="output" rows="10" cols="80"></textarea>
</label>
</div>
</form>
</body>
</html>
---------------------------------------------------------------------
As explained above IE5+/Win also allows you solve the problem of loading
an XML document and getting a scriptable DOM document by creating an
empty XMLDOM document object and calling its load method. Again you can
do that asynchronously (preferred way in a browser environment) or
synchronously. First you create the empty document:
  var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
To load asynchronously set the async property to true and set up on
onreadystatechange event handler which checks whether the readyState is
4 (meaning complete) and whether there was no parse error, then the XML
has been parsed and the DOM is accessible:
--- IE5+/Win asynchronous loading with XMLDOM ----------------------
  var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
  xmlDocument.async = true;
  xmlDocument.onreadystatechange = function () {
    if (xmlDocument.readyState == 4 && xmlDocument.parseError.errorCode
== 0) {
      loadHandler(xmlDocument);
    };
  };
  xmlDocument.load('test2005032001.xml');
  function loadHandler (xmlDocument) {
    alert(xmlDocument.documentElement.nodeName); // alerts 'gods'
    var godElements = xmlDocument.getElementsByTagName('god');
    alert('Found ' + godElements.length + ' <god> elements.'); 
    // alerts 2
    alert(godElements[0].getAttribute('home'));
  }
--------------------------------------------------------------------
To load synchronously you simply set the async property to false and
then the load call blocks until the XML is loaded and parsed or an error
occurs:
--- IE5+/Win synchronous loading with XMLDOM -----------------------
  var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
  xmlDocument.async = false;
  var loaded = xmlDocument.load('test2005032001.xml');
  if (loaded && xmlDocument.parseError.errorCode == 0) {
    loadHandler(xmlDocument);
  }
  function loadHandler (xmlDocument) {
    alert(xmlDocument.documentElement.nodeName); // alerts 'gods'
    var godElements = xmlDocument.getElementsByTagName('god');
    alert('Found ' + godElements.length + ' <god> elements.'); 
    // alerts 2
    alert(godElements[0].getAttribute('home'));
  }
--------------------------------------------------------------------
Mozilla (respectively Mozilla based browsers like Netscape 6 or later,
the Mozilla suite, Firefox) do not only provide XMLHttpRequest but have
also implemented the load method that MSXML exposes for XML DOM
documents. But before Mozilla 1.4 (corresponds to Netscape 7.1) only
asynchronous loading was possible and contrary to the onreadystatechange
event handler in MSXML with Mozilla you need to set up a load handler.
Anyway, if only Mozilla is your target you can do as follows:
--- Mozilla asynchronous load with XML DOM document ---------------
  var xmlDocument = document.implementation.createDocument('',
'dummy-root', null);
  xmlDocument.addEventListener(
    'load',
    function (evt) {
      loadHandler(this);
    },
    false
  );
  xmlDocument.load('test2005032001.xml');
  function loadHandler (xmlDocument) {
    alert(xmlDocument.documentElement.nodeName); // alerts 'gods'
    var godElements = xmlDocument.getElementsByTagName('god');
    alert('Found ' + godElements.length + ' <god> elements.'); 
    // alerts 2
    alert(godElements[0].getAttribute('home'));
  }
--- Mozilla 1.4 and later synchronous load with XML DOM document ----
  var xmlDocument = document.implementation.createDocument('',
'dummy-root', null);
  xmlDocument.async = false;
  var loaded = xmlDocument.load('test2005032001.xml');
  if (loaded) {
    loadHandler(xmlDocument);
  }
  function loadHandler (xmlDocument) {
    alert(xmlDocument.documentElement.nodeName); // alerts 'gods'
    var godElements = xmlDocument.getElementsByTagName('god');
    alert('Found ' + godElements.length + ' <god> elements.'); 
    // alerts 2
    alert(godElements[0].getAttribute('home'));
  }
---- XML data island used with IE5+/Win inside of HTML document -----
To load an XML document as an XML data island inside of an HTML document the
  XML
element (as an HTML element!!) was introduced:
  <XML ID="anXMLDocument" SRC="test.xml"></XML>
inserted in an HTML document loads the URI given by the SRC attribute
and makes it scriptable as a DOM document:
  var xmlDocument = 
    document.getElementById('anXMLDocument').XMLDocument;
You can then script the XML document with DOM methods e.g. if test.xml is
<?xml version="1.0" encoding="UTF-8"?>
<gods>
  <god home="http://www.kibo.com/">Kibo</god>
  <god>Xibo</god>
</gods>
you can then check the node name of the document element e.g.
  alert(xmlDocument.documentElement.nodeName); // alerts 'gods'
or you can access all <god> elements e.g.
  var godElements = xmlDocument.getElementsByTagName('god');
  alert('Found ' + godElements.length + ' <god> elements.');// alerts 2
or you can access an attribute e.g.
  alert(godElements[0].getAttribute('home'));
It has to be said that XML data islands are an IE/Win only feature, IE's
HTML parser has been extended to recognize the HTML(!) <xml> tag to then
delegate the task of loading and parsing the XML data to MSXML. Any
attempts to use XML data islands in HTML documents across browsers
usually fail as those browsers simply treat the <xml> elements and its
content as unknown elements in an HTML document. Thus if you want to
load and script XML data across browsers use the script methods outlined
earlier above.
On an IE/Win only intranet XML data islands may have its use, for
example for databinding.
The documentation for IE/Win XML data islands in HTML documents is here:
<http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/objects/xml.asp>
<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/xmconXMLDataIslands.asp>