Section 3.2. The XMLDocument Object


3.2. The XMLDocument Object

The responseXML property of the XMLHttpRequest object expects the return value of the remote call to be in the form of an XMLDocument object. This requires the server code to return well-formed XML data so that the client script can parse it. However, it is easy to access this XML data; you have full DOM support for doing so.

JavaScript supports a set of DOM features to access specific nodes in the XML file or to navigate the tree structure of the XML document. Appendix B contains a complete list of methods and properties of the XMLDocument object. The following example shows how to use quite a lot of them.

Imagine that the return data of the server request is the following XML data:

 <book title="Programming Atlas" author="Christian Wenz">   <chapters>     <chapter number="1" title="Introduction" />     <chapter number="2" title="JavaScript" />     <chapter number="3" title="Ajax" />   </chapters> </book> 

It is important that when XML is returned, the Content-type HTTP header of the response is explicitly set to "text/xml". If this header is omitted, some browsers (most notably, Mozilla and derivatives) refuse to parse the return data, and the responseXML object is set to null. The following C# code in an ASP.NET page shows how to set the content type appropriately:

 void Page_Load() {    if (Request.QueryString["sendData"] != null &&        Request.QueryString["sendData"] == "ok")    {     string xml = "<book title=\"Programming Atlas\"     author=\"Christian Wenz\"><chapters><chapter number=\"1\" title=\"Introduction\" /><chapter number=\"2\" title=\"JavaScript\" /><chapter number=\"3\" title=\"Ajax\" /></chapters></book>";     Response.ContentType = "text/xml";    Response.Write(xml);     Response.End();   } } 


In the client JavaScript for this example, some of the XML data is extracted and then printed out, such as the attributes of the root node and the information about the various chapters of the book object.

Printing out is intentionally not done using document.write(), because that would clear the current page, which works nicely in Mozilla browsers, but Internet Explorer does not seem to support that. So instead, the script creates new HTML elements. There are two general approaches: set the contents of existing elements or create new elements.

To set the contents of an element, set the innerHTML property of an HTML element. Imagine an HTML document that contains the following <p> element:

 <p >Wait and see ...</p> 

With the following JavaScript code, you can replace the content of the element:

 document.getElementById("output").innerHTML = "Now you see!"; 

Alternatively, you can create new elements and add them to the page. For instance, here is an empty bulleted list:

 <ul ></ul> 

The following JavaScript code adds two elements to the list:

 var list = document.getElementById("list"); var listItem1 = document.createElement("li"); var listItemText1 = document.createTextNode("Item 1"); listItem1.appendChild(listItemText1); list.appendChild(listItem1); var listItem2 = document.createElement("li"); var listItemText2 = document.createTextNode("Item 2"); listItem2.appendChild(listItemText2); list.appendChild(listItem2); 

Back to the task at hand, reading out data from the XML document. There are actually two approaches you can use. The first is to directly access tags by their names and then read their attributes, as shown in the following code:

 var xml = XMLHTTP.responseXML; var root = xml.documentElement; document.getElementById("output").innerHTML =   root.getAttribute("title") +   " by " +   root.getAttribute("author"); var list = document.getElementById("list"); var chapters = xml.getElementsByTagName("chapter"); for (var i=0; i<chapters.length; i++) {   var listItem = document.createElement("li");   var listItemText = document.createTextNode(     chapters[i].getAttribute("number") +     ": " +     chapters[i].getAttribute("title"));   listItem.appendChild(listItemText);   list.appendChild(listItem); } 

Alternatively, you can walk the XML tree using the structure of the XML document. In the following code snippet, the <chapters> element is selected using getElementsByTagName(), but then the script navigates along the tree, looking at all subelements of <chapters>. When a <chapter> node is found, its attributes are printed out.

 var xml = XMLHTTP.responseXML; var root = xml.documentElement; document.getElementById("output").innerHTML =                root.getAttribute("title") +                " by " +                root.getAttribute("author"); var list = document.getElementById("list"); var chapters = xml.getElementsByTagName("chapters")[0]; for (var i=0; i<chapters.childNodes.length; i++) {   if (chapters.childNodes[i].nodeName == "chapter") {     var listItem = document.createElement("li");     var listItemText = document.createTextNode(       chapters.childNodes[i].getAttribute("number") +       ": " +       chapters.childNodes[i].getAttribute("title"));     listItem.appendChild(listItemText);     list.appendChild(listItem);   } } 

But this is not the end of our work. Internet Explorer once again behaves differently on some systems (depending on loading or execution speed), especially with the second approach. The reason: the XMLHttpRequest call is executed "too fast" (from our example's point of view), so that the whole HTML document might not have been parsed by the time the example code runs. Therefore, it is mandatory that the Ajax magic starts only when the document has been fully loaded and parsed. Again, this can be done using anonymous functions, as shown in the following snippet:

 var XMLHTTP; window.onload = function() {   XMLHTTP = getXMLHTTP();   if (XMLHTTP != null) {     XMLHTTP.open("GET", "xmldocument2.aspx?sendData=ok");     XMLHTTP.onreadystatechange = stateChanged;     XMLHTTP.send(null);   } } 

The preceding code snippet does the XMLHttpRequest call only when the whole HTML page has been loaded.

To sum it up, Example 3-2 shows the complete code for the first approach, which is provided in the file xmldocument.aspx in the code download repository for this book (http://www.oreilly.com/catalog/atlas). The second approach (not illustrated here) can be found in the file xmldocument2.aspx.

Example 3-2. Reading and writing data using JavaScript, Ajax, and DOM

 xmldocument.aspx <%@ Page Language="C#" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <script runat="server">   void Page_Load()   {     if (Request.QueryString["sendData"] != null &&         Request.QueryString["sendData"] == "ok")     {       string xml = "<book title=\"Programming Atlas\" author=\"Christian Wenz\"> <chapters><chapter number=\"1\" title=\"JavaScript\" /><chapter number=\"2\" title=\"ASP.NET\" /><chapter number=\"3\" title=\"Ajax\" /></chapters></book>";       Response.ContentType = "text/xml";       Response.Write(xml);       Response.End();     }   } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head  runat="server">   <title>Ajax with ASP.NET</title>   <script language="Javascript" type="text/javascript"> function getXMLHTTP() {   var XMLHTTP = null;   if (window.ActiveXObject) {     try {       XMLHTTP = new ActiveXObject("Msxml2.XMLHTTP");     } catch (e) {       try {         XMLHTTP = new ActiveXObject("Microsoft.XMLHTTP");       } catch (e) {       }     }   } else if (window.XMLHttpRequest) {     try {       XMLHTTP = new XMLHttpRequest();     } catch (e) {     }   }   return XMLHTTP; } var XMLHTTP; window.onload = function() {   XMLHTTP = getXMLHTTP();   if (XMLHTTP != null) {     XMLHTTP.open("GET", "xmldocument.aspx?sendData=ok");     XMLHTTP.onreadystatechange = stateChanged;     XMLHTTP.send(null);   } } function stateChanged() {   if (XMLHTTP.readyState == 4 &&       XMLHTTP.status == 200) {     var xml = XMLHTTP.responseXML;     var root = xml.documentElement;     document.getElementById("output").innerHTML =       root.getAttribute("title") +       " by " +       root.getAttribute("author");     var list = document.getElementById("list");     var chapters = xml.getElementsByTagName("chapter");     for (var i=0; i<chapters.length; i++) {       var listItem = document.createElement("li");       var listItemText = document.createTextNode(         chapters[i].getAttribute("number") +         ": " +         chapters[i].getAttribute("title"));       listItem.appendChild(listItemText);       list.appendChild(listItem);     }   } }   </script> </head> <body>   <p >Wait and see ...</p>   <ul ></ul> </body> </html> 

The results of running this script are shown in Figure 3-6.

Figure 3-6. The XML data in a readable form





Programming Atlas
Programming Atlas
ISBN: 0596526725
EAN: 2147483647
Year: 2006
Pages: 146

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net