Section IV.9. Blending XML Data into HTML Pages


IV.9. Blending XML Data into HTML Pages

With recent browsers, you have at your disposal the power to "include" XML data from the same domain into a Web page. The retrieval process occurs behind the scenes, where scripts load XML-formatted data into a virtual document. From there, your client-side scripts can inspect the XML document tree and perform scripted transforms of the data to generate familiar HTML constructs, such as tables.

The engine behind this power is a global object called XMLHttpRequest. Online Section II is dedicated to this object's features, so I'll only introduce some of the details here as a way to demonstrate how to convert incoming XML data into renderable HTML content.

IV.9.1. Embedding XML Data

For this demonstration, I'll use the same raw Super Bowl results data used earlier for dynamic tables, but this time formatted as an external XML document, rather than embedded JavaScript objects. The XML data will be retrieved in its native state, and then parsed to extract values that ultimately render inside an HTML table.

Let's start with the XML document. Although this example loads the data from a file, the data could just as easily arrive from a server process (e.g., database lookup) that returns data with an appropriate XML content type. The structure of the XML file for this demonstration is as follows:

 <?xml version="1.0"?> <results>     <bowl>         <number>I</number>         <year>1967</year>         <winner>Packers</winner>         <winscore>35</winscore>         <loser>Chiefs</loser>         <losscore>10</losscore>     </bowl>     <bowl>         ...     </bowl> ... </results> 

This structure is fairly typical of XML returned from a database lookup in that the bulk of the meaningful data consists of multiple containers (the bowl elements here) that are, themselves, contained within an outer element (the results element here). It's also common for an XML document to contain a section of elements (akin to an HTML document's head element) that convey information about the query. The focus here, however, is on the set of "records" within the data.

IV.9.2. Retrieving the XML

Because of different implementations of the XMLHttpRequest object (an ActiveX object in IE 5, 5.5, and 6; a native global object beginning with IE 7, Mozilla 1.0, Safari 1.2, and Opera 8), the code that loads an external XML data source requires some branching based on object detection. In all cases, the code generates an instance of the XMLHttpRequest object. For the sake of simplicity in this example, that instance is preserved as a global variable named req (a more object-oriented approach is demonstrated in Online Section VII).

The following loadXMLDoc( ) function performs a few key operations. First, it creates an instance of the XMLHttpRequest object in the manner supported by the current browser. Second, it assigns a function reference to an event property of the request objectthe handler to run after the XML data has finished loading. Finally, the function sets the request parameters, followed by actually sending the request to the URL passed as a parameter to the loadXMLDoc( ) function.

 var req; function loadXMLDoc(url, loadHandler) {     req = null;     // branch for native XMLHttpRequest object     if(window.XMLHttpRequest) {         try {             req = new XMLHttpRequest( );         } catch(e) {             req = null;         }     // branch for IE/Windows ActiveX versions     } else if(window.ActiveXObject) {         try {             req = new ActiveXObject("Msxml2.XMLHTTP");         } catch(e) {             try {                req = new ActiveXObject("Microsoft.XMLHTTP");             } catch(e) {                req = null;             }         }     }     if(req) {         req.open("GET", url, true);         req.onreadystatechange = loadHandler;         req.setRequestHeader("Content-Type", "text/xml");         req.send("");     } } 

IV.9.3. Parsing the XML Document

Example IV-10 contains the entire listing for this example. The drawTable( ) function operates only if the readyState property of the req object is the value (4) indicating that loading has completed. Then the function extracts the root document node object from the req object by way of the responseXML property. In other words, the xDoc local variable is now the equivalent of a document object, but for the unseen XML document retrieved from the server.

To try out this example on your own in IE, the HTML and XML files must be accessed from a web server.


The drawTable( ) function knows about the structure of the XML document, and begins its parsing by obtaining a reference to the outermost container of records, the results element. As you can see from the XML file shown earlier, the results element consists of multiple bowl child elements, each representing a single record. Looping through all child nodes of results (and working only with those nodes that are elements and not whitespace, that is, nodes whose nodeType property is 1), a table row's cells are populated by individual text nodes from elements within each record. Elements are referred to by their tag names, rather than their position within the record so that additions or reordering of elements within the XML output won't affect the distribution of data within the table.

Example IV-10. Embedding external XML data

 <html> <head> <title>Blending External XML Data</title> <style type="text/css"> body {background-color: #ffffff} table {border-spacing: 0} td {border: 2px groove black; padding: 7px} th {border: 2px groove black; padding: 7px} .ctr {text-align: center} </style> <script type="text/javascript"> // Draw table from parse XML document tree data function drawTable(tbodyID) {     if (req.readyState == 4) {         var tr, td, i, j, oneRecord;         var tbody = document.getElementById(tbodyID);         var xDoc = req.responseXML;         if (!xDoc || !xDoc.childNodes.length) {             alert("This example must be loaded from a web " +             "server for Internet Explorer.");             return;         }         // node tree         var data = xDoc.getElementsByTagName("results")[0];         // for td class attributes         var classes = ["ctr","","","","ctr"];         for (i = 0; i < data.childNodes.length; i++) {             // use only 1st level element nodes             if (data.childNodes[i].nodeType == 1) {                 // one bowl record                 oneRecord = data.childNodes[i];                 tr = tbody.insertRow(tbody.rows.length);                 td = tr.insertCell(tr.cells.length);                 td.setAttribute("class",classes[tr.cells.length-1]);                 td.appendChild(document.createTextNode(                    oneRecord.getElementsByTagName("number")[0].firstChild.nodeValue));                 td = tr.insertCell(tr.cells.length);                 td.setAttribute("class",classes[tr.cells.length-1]);                 td.appendChild(document.createTextNode(                    oneRecord.getElementsByTagName("year")[0].firstChild.nodeValue));                 td = tr.insertCell(tr.cells.length);                 td.setAttribute("class",classes[tr.cells.length-1]);                 td.appendChild(document.createTextNode(                    oneRecord.getElementsByTagName("winner")[0].firstChild.nodeValue));                 td = tr.insertCell(tr.cells.length);                 td.setAttribute("class",classes[tr.cells.length-1]);                 td.appendChild(document.createTextNode(                     oneRecord.getElementsByTagName("loser")[0].firstChild.nodeValue));                 td = tr.insertCell(tr.cells.length);                 td.setAttribute("class",classes[tr.cells.length-1]);                 td.appendChild(document.createTextNode(                      oneRecord.getElementsByTagName("winscore")[0].firstChild. nodeValue +                      " - " +                      oneRecord.getElementsByTagName("losscore")[0].firstChild. nodeValue));             }         }     } } // request object instance var req; function loadXMLDoc(url, loadHandler) {     req = null;     // branch for native XMLHttpRequest object     if(window.XMLHttpRequest) {         try {             req = new XMLHttpRequest( );         } catch(e) {             req = null;         }     // branch for IE/Windows ActiveX version     } else if(window.ActiveXObject) {         try {             req = new ActiveXObject("Msxml2.XMLHTTP");         } catch(e) {             try {                req = new ActiveXObject("Microsoft.XMLHTTP");             } catch(e) {                req = null;             }         }     }     if(req) {         req.open("GET", url, true);         req.onreadystatechange = loadHandler;         req.setRequestHeader("Content-Type", "text/xml");         req.send("");     } } // initialize function init( ) {     loadXMLDoc("superBowls.xml", new Function ("drawTable('bowlData')")); } window.onload = init; </script> </head> <body"> <h1>Super Bowl Games</h1> <hr> <table > <thead> <tr><th>Bowl</th>     <th>Year</th>     <th>Winner</th>     <th>Loser</th>     <th>Score (Win - Lose)</th> </tr> </thead> <tbody ></tbody> </table> </body> </html> 

IV.9.4. Converting XML to JavaScript Objects

One point you can deduce from comparing Examples IV-9 and IV-10 is that if you wish to re-sort the table data without reloading the page, it is far easier and more efficient to use the sorting facilities of JavaScript arrays than it is to manipulate XML data. As a result, you may find it more convenient to convert external XML data into more convenient arrays of JavaScript objects. The typical regularity of XML data greatly simplifies and speeds the creation of the JavaScript counterparts. Example IV-11 shows a function that converts the XML data file from Example IV-10 to corresponding JavaScript data objects.

Example IV-11. XML to JavaScript array function

 // Global holder of JS-formatted data var jsData = new Array( ); // Convert xDoc data into JS array of JS objects function XML2JS(recordsContainer) {     var rawData = req.responseXML.getElementsByTagName(recordsContainer)[0];     var i, j, oneRecord, oneObject;     for (i = 0; i < rawData.childNodes.length; i++) {         if (rawData.childNodes[i].nodeType == 1) {             oneRecord = rawData.childNodes[i];             oneObject = jsData[jsData.length] = new Object( );             for (j = 0; j < oneRecord.childNodes.length; j++) {                 if (oneRecord.childNodes[j].nodeType == 1) {                     oneObject[oneRecord.childNodes[j].tagName] =                       oneRecord.childNodes[j].firstChild.nodeValue;                 }             }         }     } } 

With the data in this format, you can apply the sorting facilities from Example IV-9 to the data.




Dynamic HTML. The Definitive Reference
Dynamic HTML: The Definitive Reference
ISBN: 0596527403
EAN: 2147483647
Year: 2004
Pages: 120
Authors: Danny Goodman

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