O'Reilly logo

JavaScript Cookbook by Shelley Powers

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

19.2. Extracting Pertinent Information from an XML Tree

Problem

You want to access individual pieces of data from an XML document.

Solution

Use the same DOM methods you use to query your web page elements to query the XML document. As an example, the following will get all elements that have a tag name of "story":

var stories = xmlHttpObj.responseXML.getElementsByTagName("story");

Discussion

Once you have the XML document, you can use the DOM methods covered in Chapter 11 to query any of the data in the document via the Ajax responseXML property, or even one that you’ve created yourself from scratch.

To demonstrate, Example 19-1 shows a PHP application that returns an XML result when passed a category value. The application returns a list of stories by category, and their associated URL. If the category string isn’t passed or the category isn’t found, the application returns an error message that’s formatted in the same formatting as the other values, except that the URL value is set to “none”. This ensures a consistent result from the application.

It’s not a complicated application or a complex XML result, but it’s sufficient to demonstrate how XML querying works. Notice that the header is instructed to return the content with a MIME type of text/xml.

Example 19-1. PHP application that returns an XML result

<?php

  //If no search string is passed, then we can't search
  if(empty($_GET['category'])) {
    $result =
"<story><url>none</url><title>No Category Sent</title></story>";
  } else {
    //Remove whitespace from beginning & end of passed search.
    $search = trim($_GET['category']);
    switch($search) {
      case "CSS" :
         $result = "<story><url>
http://realtech.burningbird.net/graphics/css/opacity-returns-ie8
</url>" .
                   "<title>Opacity returns to IE8</title></story>" .
                   "<story>
<url>
http://realtech.burningbird.net/graphics/css/embedded-fonts-font-face
</url>" .
                   "<title>Embedded Fonts with Font Face</title>
</story>";
         break;
      case "ebooks" :
         $result = "<story><url>
http://realtech.burningbird.net/web/ebooks/kindle-clipping-limits
</url>" .
                   "<title>Kindle Clipping Limits</title></story>" .
                   "<story><url>
http://realtech.burningbird.net/web/ebooks/kindle-and-book-freebies
</url>" .
                   "<title>Kindle and Book Freebies</title></story>";
         break;
      case "video" :
         $result = "<story><url>
http://secretofsignals.burningbird.net/science/how-things-work/
video-online-crap-shoot</url>" .
                   "<title>The Video Online Crap Shoot</title>
</story>" .
                   "<story>
<url>http://secretofsignals.burningbird.net/toys-and-technologies/
gadgets/review-flip-ultra-camcorder</url>" .
                   "<title>Review of the Flip Ultra Camcorder</title>
</story>" .
                   "<story><url>
http://secretofsignals.burningbird.net/reviews/movies-disc/gojira

</url>" .
                   "<title>Gojira</title></story>" .
                   "<story><url>
http://secretofsignals.burningbird.net/reviews/movies-disc/
its-raging-squid</url>" .
                   "<title>It's a Raging Squid</title></story>";
         break;
      case "missouri" :
         $result =
"<story><url>http://missourigreen.burningbird.net/times-past/
missouri/tyson-valley-lone-elk-and-bomb</url>" .
         "<title>Tyson Valley, a Lone Elk, and a Bomb</title>
</story>";
         break;
      default :
         $result = "<story><url>none</url><title>No Stories Found</title></story>";
         break;
      }
  }

  $result ='<?xml version="1.0" encoding="UTF-8" ?>' .
              "<stories>" . $result . "</stories>";
  header("Content-Type: text/xml; charset=utf-8");
  echo $result;
?>

Example 19-2 shows a web page with a JavaScript application that processes a radio button selection for a story category. The application forms an Ajax request based on the category, and then processes the returned XML in order to output a list of stories, linked with their URLs.

Example 19-2. JavaScript application to process story information from returned XML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Stories</title>
<meta charset="utf-8" />
<script type="text/javascript">
//<![CDATA[

var xmlHttpObj;

window.onload=function() {
  var radios = document.forms[0].elements["category"];
  for (var i = 0; i < radios.length; i++) {
    radios[i].onclick=getStories;
  }
}

function getStories() {
   // category
   var category = encodeURIComponent(this.value);

   // ajax object
   if (window.XMLHttpRequest) {
      xmlHttpObj = new XMLHttpRequest();
   }

   // build request
   var url = "stories.php?category=" + category;
   xmlHttpObj.open('GET', url, true);
   xmlHttpObj.onreadystatechange = getData;
   xmlHttpObj.send(null);

}
function getData() {
  if (xmlHttpObj.readyState == 4 && xmlHttpObj.status == 200) {
    try {

       var result = document.getElementById("result");
       var str = "<p>";

       var stories =
xmlHttpObj.responseXML.getElementsByTagName("story");
       for (var i = 0; i < stories.length; i++) {
         var story = stories[i];
         var url = story.childNodes[0].firstChild.nodeValue;
         var title = story.childNodes[1].firstChild.nodeValue;
         if (url === "none")
             str += title + "<br />";
         else
             str += "<a href='" + url + "'>" + title + "</a><br />";
       }

       // finish HTML and insert
       str+="</p>";
       result.innerHTML=str;
    } catch (e) {
      alert(e.message);
    }
  }
}
//]]>
</script>
</head>
<body>
<form id="categoryform">
CSS: <input type="radio" name="category" value="CSS" /><br />
eBooks: <input type="radio" name="category" value="ebooks" /><br />
Missouri: <input type="radio" name="category" value="missouri" />
<br />
Video: <input type="radio" name="category" value="video" /><br />
</form>
<div id="result">
</div>
</body>
</html>

When processing the XML code, the application first queries for all story elements, which returns a nodeList. The application cycles through the collection, accessing each story element in order to access the story URL and the title, both of which are child nodes. Each is accessed via the childNodes collection, and their data, contained in the nodeValue attribute, is extracted.

The story data is used to build a string of linked story titles, which is output to the page, as shown in Figure 19-1. Note that rather than use a succession of childNodes element collections to walk the trees, I could have used the Selectors API to access all URLs and titles, and then traversed both collections at one time, pulling the paired values from each, in sequence:

var urls = xmlHttpObj.responseXML.querySelectorAll("story url");
var titles = xmlHttpObj.responseXML.querySelectorAll("story title");

for (var i = 0; i < urls.length; i++) {
        var url = urls[i].firstChild.nodeValue;
        var title = titles[i].firstChild.nodeValue;
        if (url === "none")
            str += title + "<br />";
        else
            str += "<a href='" + url + "'>" + title + "</a><br />";
       }
}

I could have also used getElementsByTagName against each returned story element—anything that works with the web page works with the returned XML.

Processing XML: returning story titles and URLs from a server-side application

Figure 19-1. Processing XML: returning story titles and URLs from a server-side application

The try...catch error handling should catch any query that fails because the XML is incomplete. In the example, the error is printed out in an alert—but you’ll want to use friendlier and more helpful error handling.

Note

The document returned in responseXML, or created using DOMParser, has access to the XML DOM APIs, but not the HTML DOM APIs. For the most part, this shouldn’t be a problem, as most of the functionality you’ll use is based on the more generic XML DOM APIs.

See Also

Chapter 11 covers most of the DOM query techniques that work with the XML returned via responseXML, as well as accessing the web page elements. Recipe 9.4 demonstrates how to process radio button events, and Recipe 12.1 demonstrates how to use innerHTML to update the web page contents.

Recipe 19.1 provides a way to process XML when it’s returned as text, via responseText.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required