Previous Page
Next Page

Hack 4. Receive Data as XML

Ajax and server programs provide a DOM Document object that's ready to go.

Many technologies currently exchange data in Extensible Markup Language format, mostly because XML is a standardized and extensible format widely supported by the software world. Thus, different parties can use existing, well-known technologies to generate, send, and receive XML, without having to adapt to the software tools used by the parties with whom they are exchanging the XML data.

An example is a Global Positioning System (GPS) device that can share the data it has recorded about, say, a hike or a bike ride with a location-aware web application. You just stick the USB cable attached to the GPS device into a USB computer port, launch software that sends the device data to the Web, and that's it. The data format is usually an XML language that has been defined already for GPS software. The web application and the GPS device "speak the same language."

Although this book is not the place for an extensive introduction to XML, you have probably seen these text files in one form or another. XML is used as a "meta" language that describes and categorizes specific types of information. XML data starts with an optional XML declaration (e.g., <?xml version="1.0" encoding="UTF-8"?>), followed by a root element and zero or more child elements. An example is:

<?xml version="1.0" encoding="UTF-8"?>
<gps>
<gpsMaker>Garmin</gpsMaker>
<gpsDevice>
Forerunner 301
</gpsDevice>
</gps>

Here, gps is the root element, and gpsMaker and gpsDevice are child elements.

Ajax and the request object can receive data as XML, which is very useful for handling web-services responses that use XML. Once the HTTP request is complete, the request object has a property named responseXML. This object is a DOM Document object that your Ajax application can use. Here's an example:

function handleResponse(  ){
    if(request.readyState == 4){
        if(request.status == 200){
            var doc = request.responseXML;
...
}

In the previous code sample, the doc variable is a DOM Document object, offering a similar API to a browser's display page. This hack receives XML from a server, then initiates a little DOM programming with the Document object to pull some information out of the XML.

If you just want to see the raw XML text, use the request.responseText property instead.


The HTML file for this hack is basically the same as the one used in "Use the Request Object to POST Data to the Server" [Hack #2], but a div element is added at the end, where the code displays information about the returned XML. Here's the code for the HTML page:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">
<html>
<head>
    <script type="text/javascript" src="js/hack3.js"></script>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>Receive XML response</title>
</head>
<body>
<h3>A Few Facts About Yourself...</h3>
<form action="javascript:void%200" onsubmit="sendData(  );return false">
    <p>First name: <input type="text" name="firstname" size="20"> </p>
    <p>Last name: <input type="text" name="lastname" size="20"> </p>
    <p>Gender: <input type="text" name="gender" size="2"> </p>
    <p>Country of origin: <input type="text" name="country" size="20"> </p>
    <p><button type="submit">Send Data</button></p>
    <div id="docDisplay"></div>
</form>
</body>
</html>

Figure 1-3 shows what the page looks like before the user enters any information.

Figure 1-3. All set up to receive XML


The JavaScript code in the hack3.js file POSTs its data to a server application, which sends back a response in XML format. The field validation step [Hack #22] has been skipped for the sake of brevity, but web applications using forms should always implement this task.

Like other examples in this chapter, the server program echoes the parameter names and values back to the client, as in <params><firstname>Bruce</firstname></params>. "Use the Request Object to POST Data to the Server" [Hack #2] shows some of the code for the server component that puts together the return value. This technique suits our purpose for showing a simple example of programming XML in an Ajax application:

var request;
var queryString;   //will hold the POSTed data

function sendData(  ){
    setQueryString(  );
    var url="http://www.parkerriver.com/s/sender";
    httpRequest("POST",url,true);
}
//event handler for XMLHttpRequest
function handleResponse(  ){
    if(request.readyState == 4){
        if(request.status == 200){
            var doc = request.responseXML;
            var info = getDocInfo(doc);
            stylizeDiv(info,document.getElementById(""docDisplay""));
        } else {
            alert(""A problem occurred with communicating between ""+
                  ""the XMLHttpRequest object and the server program."");
        }
    }//end outer if
}

/* Initialize a request object that is already constructed */
function initReq(reqType,url,bool){
    /* Specify the function that will handle the HTTP response */
    request.onreadystatechange=handleResponse;
    request.open(reqType,url,bool);
    request.setRequestHeader(""Content-Type"",
            ""application/x-www-form-urlencoded; charset=UTF-8"");
    /* Only works in Mozilla-based browsers */
    //request.overrideMimeType(""text/xml"");
    request.send(queryString);
}

/* Wrapper function for constructing a request object.
 Parameters:
  reqType: The HTTP request type, such as GET or POST.
  url: The URL of the server program.
  asynch: Whether to send the request asynchronously or not. */
function httpRequest(reqType,url,asynch){
    //Snipped...See Hack #1
}
function setQueryString(  ){
    queryString="";
    var frm = document.forms[0];
    var numberElements =  frm.elements.length;
    for(var i = 0; i < numberElements; i++) {
        if(i < numberElements-1) {
            queryString += frm.elements[i].name+"="+
                           encodeURIComponent(frm.elements[i].value)+"&";
        } else {
            queryString += frm.elements[i].name+"="+
                           encodeURIComponent(frm.elements[i].value);
        }
    }
}
/* Provide the div element's content dynamically. We can add
style information to this function if we want to jazz up the div */
function stylizeDiv(bdyTxt,div){
    //reset DIV content
    div.innerHTML="";
    div.style.backgroundColor="yellow";
    div.innerHTML=bdyTxt;
}

/* Get information about an XML document via a DOM Document object */
function getDocInfo(doc){
    var root = doc.documentElement;
    var info = "<h3>Document root element name: <h3 />"+ root.nodeName;
    var nds;
    if(root.hasChildNodes(  )) {
        nds=root.childNodes;
        info+= "<h4>Root node's child node names/values:<h4/>";
        for (var i = 0; i < nds.length; i++){
            info+=  nds[i].nodeName;
            if(nds[i].hasChildNodes(  )){
                info+=  " : \\"+nds[i].firstChild.nodeValue+"\\"<br />";
            } else {
                info+=  " : Empty<br />";
            }
        }
    }
    return info;
}

Mozilla Firefox can use the request.overrideMimeType( ) function to force the interpretation of the response stream as a certain mime type, as in request.overrideMimeType("text/xml"). Internet Explorer's request object does not have this function. This function call does not work with Safari 1.3, either.


After the code POSTs its data and receives a response, it calls a method named getDocInfo( ), which builds a string that displays some information about the XML document and its child or subelements:

var doc = request.responseXML;
var info = getDocInfo(doc);

The geTDocInfo( ) function gets a reference to the root XML element (var root = doc.documentElement;); it then builds a string specifying the name of the root element and information about any of its child nodes or elements, such as the child node name and value. The code then feeds this information to the stylizeDiv( ) method. The stylizeDiv( ) method uses the div element at the end of the HTML page to dynamically display the gathered information:

function stylizeDiv(bdyTxt,div){
    //reset div content
    div.innerHTML="";
    div.style.backgroundColor="yellow";
    div.innerHTML=bdyTxt;
}

Figure 1-4 shows what the web page looks like after the application receives the XML response.

Figure 1-4. Delving into XML return values


The text nodes that the application shows are newline characters in the returned XML.


The core DOM API offered by the browser's JavaScript implementation provides developers with a powerful tool for programming complex XML return values.


Previous Page
Next Page