Beyond the Basics -- More Scripting Techniques

The simple email sample file shown above demonstrates how you can access the XML object model and work with XML data. A closer look at the document and its scripts reveals that simplicity comes at a cost. In an effort to keep the scripts on the easy side, some techniques have been incorporated that would prove to be less than ideal in many situations. Consider the following:

  • The script code that accesses the XML document tree and extracts the data assumes that we know not only how many elements exist but that the order of the elements is the same as in our original, since we address each one by index. While this type of code might work in some applications, it would be totally inadequate in others.
  • The script code addresses each element separately. While this might work fine for small documents, it would become tedious and potentially error-prone in large or complex documents.
  • The HTML document is not totally data-independent. The HTML tags used for layout and formatting contain text (such as To: and From:). If this document needed to be translated into other languages, it would require that both the XML document and the HTML document be edited.

We will now look at some scripting techniques that will help us avoid some of the issues just described.

Walking the XML Document Tree

While in the previous example the author was required to know the number and type of elements in the XML document, this situation can be easily avoided by using some other properties and methods in the XML object model.

One of these useful properties is childNodes, which returns a list of the children of the current node. The length property of childNodes contains the number of children. Thus, it is pretty easy to step through the children of a node, as demonstrated in Code Listing 21-2.

Code Listing 21-2.

 <HTML> <HEAD> <TITLE>Code Listing 21-2</TITLE> <SCRIPT LANGUAGE="JavaScript">   var xmlDoc=new ActiveXObject("Microsoft.XMLDOM")   xmlDoc.async=false   xmlDoc.load("email.xml")   root = xmlDoc.documentElement   for (var i=0; i<root.childNodes.length; i++){     alert(root.childNodes.item(i).nodeName+" = "+           root.childNodes.item(i).text)   } </SCRIPT> </HEAD> </HTML> 

Figure 21-2. A dialog box containing the name and contents of the first element.

Loading the HTML file now should produce a series of five dialog boxes that each contain the name of an element in the XML document and its contents. The first one should look like Figure 21-2. The preceding code uses the property root.childNodes.length to ask the XML document how many child elements the root element contains. The script then enters a loop and goes through all the children of the root element, getting the name of each child node (with the nodeName property) and the text contained in each node until the last one is reached.

However, this code just walks one level of the tree. If any of the children of the root element had children of their own, they would have been ignored by Code Listing 21-2. The inbox.xml file is an example of a more complicated document (shown on the following page and in chap21\inbox.xml on the companion CD) in which there are multiple levels to the tree. Note that the first email even contains an element (CC) not found in the other emails.

 <?xml version="1.0"?> <INBOX>  <EMAIL>    <TO>Bill_Pardi@hotmail.com</TO>    <FROM>Eric_Schurman@hotmail.com</FROM>    <CC>DHTML_in_Action@hotmail.com</CC>    <SUBJECT>My document is a tree.</SUBJECT>    <BODY>This is an example of a tree structure.</BODY>  </EMAIL>  <EMAIL>    <TO>Bill_Pardi@hotmail.com</TO>    <FROM>Eric_Schurman@hotmail.com</FROM>    <SUBJECT>XML is cool.</SUBJECT>    <BODY>This is a simple message.</BODY>  </EMAIL>  <EMAIL>    <TO>Bill_Pardi@hotmail.com</TO>    <FROM>Eric_Schurman@hotmail.com</FROM>    <SUBJECT>Here is that code.</SUBJECT>    <BODY>I send too many emails.</BODY>  </EMAIL> </INBOX> 

This requires more sophisticated script to get the same type of results that we found in Code Listing 21-1, in which the contents of the email were displayed in the browser. Code Listing 21-3 starts at the beginning of the XML document and then progressively walks down the tree and displays the contents of each node. If a node has children, they are visited and their contents are displayed. Figure 21-3 shows the results of running this code.

Code Listing 21-3.

 <HTML> <HEAD> <TITLE>Code Listing 21-3</TITLE> <SCRIPT LANGUAGE="JavaScript">   var xmlDoc = new ActiveXObject("microsoft.xmldom")   xmlDoc.async=false   xmlDoc.load("inbox.xml")   root=xmlDoc.documentElement   newHTML=""      function start(){   buildTree(root)   content.innerHTML=newHTML } function buildTree(passedNode){ var children = passedNode.childNodes.length   for (var j=0; j<children; j++){     Node=passedNode.childNodes.item(j)     if (Node.nodeName=="EMAIL"){ newHTML+=("<P>"+Node.nodeName+" "+j) }     if (!Node.hasChildNodes()){       newHTML+=( "<BR><B>"+Node.parentNode.nodeName+":</B> "+Node.text )     }     buildTree(Node)   } } </SCRIPT> </HEAD> <BODY onload="start()"> <SPAN ID="content"></SPAN> </BODY> </HTML> 

click to view at full size.

Figure 21-3. Displaying the XML document content.

Let's walk through this code. When the page is loading, the script block loads the XML file, assigns the XML document element to the variable root, and creates the empty newHTML variable, which is used later in the script. When the page finishes loading, the onload event handler in the BODY tag calls the start function, which in turn calls the buildTree function, passing it the root XML element.

The majority of the work in this sample is accomplished in the buildTree function. This is a recursive function; that is, it calls itself when certain conditions are met. This function essentially looks at the current node and checks to see how many children it has. If it has children, the function calls itself again, passing itself the first of the children. Once it reaches a node with no children, it adds to the newHTML variable some HTML code describing the data in the current node, and then it returns to the parent node. By repeating this, it can travel across the entire data tree. Let's take a look at parts of the function in depth.

 var children = passedNode.childNodes.length for (var j=0; j<children; j++){ 

The beginning of the function finds out how many children the current node has and assigns that value to the children variable. The next line starts a for loop that will be repeated for each child of the current node.

 Node=passedNode.childNodes.item(j) if (Node.nodeName=="EMAIL"){ newHTML+=("<P>"+Node.nodeName+" "+j) } if (!Node.hasChildNodes()){   newHTML+=( "<BR><B>"+Node.parentNode.nodeName+":</B> "+Node.text ) } 

Next the current child is assigned to the variable Node. We would like each one of the emails in our data to be separated. This is accomplished by the second line above. If the Node is named EMAIL, that line adds a paragraph tag to newHTML in addition to the node's name and the number of this email. We could have also tested whether Node.parentNode==root, because the only elements just below the root are EMAIL elements.

 buildTree(Node) 

The final line of the for loop calls the buildTree function again, passing it Node. Ultimately, the function is called for every item in the XML data tree. A much more flexible and full-featured XML tree walker can be found at microsoft.com/gallery/samples/xml/tree_viewer/default.asp or on the companion CD. See Tools and Samples; samples; XML; and XML Tree Viewer.

Note that while using these techniques can make an HTML document much more flexible and powerful, the document is still only a template for a specific class of XML document or documents. This makes HTML and XML perfect complements to one another.

Error Handling

The XML object model provides several ways for authors to handle errors when they occur as a result of the XML document. One of these is the Document object's parseError property, which provides information about problems that occur in an XML document so that authors can deal with them and users might not have to.

The parseError property provides a code for every error that might occur. An author can use these codes to:

  • Help debug XML documents or scripts
  • Inform the user of problems and provide suggestions for resolution
  • Trap for certain kinds of errors and fix them behind the scenes

The sample code below shows how the parseError property might be used to inform a user of a problem.

 var xmlDoc = new ActiveXObject("microsoft.xmldom"); xmlDoc.load("email.xml"); if (xmlDoc.parseError.reason == ""){   alert("Document loaded successfully") } else{  alert("The following error occurred: "+xmlDoc.parseError.errorCode) } 

This technique can be used both for debugging and for shielding users from errors.



Dynamic HTML in Action
Dynamic HTML in Action
ISBN: 0735605637
EAN: 2147483647
Year: 1999
Pages: 128

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