分享

JavaScript Remote Scripting: Processing XML Files

 pengyan 2006-11-19
http://www./c/a/JavaScript/JavaScript-Remote-Scripting-Processing-XML-Files/

JavaScript Remote Scripting: Processing XML Files

(Page 1 of 6 )

In this article, you will learn how to use AJAX for reading and manipulating simple XML files, in order to implement a basic Web service. Specifically, you will learn how to develop a JavaScript application that fetches data from an XML file. By the end of this article, you will know the basics for using client-side parsed XML in your own applications.

Here you have it. Welcome to the second part of the series “JavaScript Remote Scripting.” Based on the theoretical concepts explained in the first tutorial, as well as their application in an illustrative example, I’ve demonstrated how to read file data from the server by using AJAX as the primary method for making http requests in the background, without having to reload the current page.

Stepping back for a moment to the script that I previously developed in the first article, it implements a simple mechanism for fetching data from a plain text file and displaying the information through a predefined sequence. Although the example is rather basic, it does exposes the foundations of AJAX technology for building more complex and polished applications, by utilizing as core programming logic the powerful capabilities for sending silent http requests on the fly.

The best thing with this approach is that it offers a broad range of applications for fetching data from the server in multiple formats. Of course you have already seen how easy it is to fetch data from flat text files and display their contents directly on the browser, all without messing up things too much with complex server-side programs. Moreover, AJAX comes with native support for pulling out data served as XML, by using the “responseXML” property that belongs to the XMLHtttpRequest object.

Considering that XML is today one of the most common data carriers used when working with Web services, this second part of the series will put strong attention to developing a JavaScript application that fetches data from an XML file, by taking advantage of the native capabilities that AJAX brings to developers for working with this markup language. In my attempt to illustrate the relevant role of AJAX within the area of remote scripting, by the end of this article you will know the basics for using client-side parsed XML in your own applications.

Now that you know the objectives of this second part of the series, it’s time to move on to learn more about JavaScript-based XML processing. Let’s get going!


JavaScript Remote Scripting: Processing XML Files - XML in the client: the basics of AJAX XML processing
(Page 2 of 6 )

In addition to the “responseText” property that you saw in the first article, the XMLHttpRequest object offers the “responseXML” property, useful for processing server response, which has been sent back to the client as XML data. Using regular DOM methods, it’s possible to parse basically XML in the client and implement some kind of interaction, either for boosting the capabilities of user interfaces or the application layer itself.

With reference to the above deployed concepts, in conjunction with the sample news rotator that I developed in part one of this series, what I’ll do next is write a simple script that retrieves some headlines from a XML file, then processes them and finally displays the results directly on the browser. Considering that client-side flat text file processing has already been covered, the next example will illustrate how to parse XML files once the corresponding http request has been successfully completed.

As you might guess, in order to get the script parsing XML, first I’ll need to work with sample data served as XML. In this particular case, I’ll define a simple XML file, which contains some headlines to be included in the news rotator. Its definition is the following:

<?xml version="1.0" encoding="iso-8859-1"?>
<news>
<message>
<title>Learn advanced concepts about AJAX and Remote Scripting. Visit DevArticles.com now!</title>
<url>http://www.</url>
</message>
<message>
<title>PHP 5.1 now presents new key improvements such as PDO (PHP Data Objects)</title>
<url>http://www.</url>
</message>
<message>
<title>Google to continue extending its GoogleMaps API</title>
<url>http://www.google.com/apis/maps/documentation/</url>
</message>
<message>
<title>MySQL releases Open Source Database Tools for Macintosh OS X</title>
<url>http://www.</url>
</message>
<message>
<title>Release of Flash Player 8 allows to develop richer applications and communications</title>
<url>http://www.macromedia.com</url>
</message>
<message>
<title>PHP introduces more improvements in regards to SOAP, streams and SPL</title>
<url>http://www.</url>
</message>
</news>

As you can see, the above listed XML file presents a simple structure for defining the appropriate headlines to be displayed, as well as the URLs tied to them. With reference to the document hierarchy, I’ve defined a general <news> tag, which is placed on top of the document tree, and then created a few <message> nodes to wrap up both <title> and <url> child elements. Of course neither style data nor element attributes have been defined for the document, thus its structure is very simple and understandable.

Now that you have a pretty clear idea of how the sample XML file looks, I can move on to start writing the complete JavaScript application.

JavaScript Remote Scripting: Processing XML Files - Reading XML files with AJAX: defining the “sendRequest()” function
(Page 3 of 6 )

If you’ve read the first part of this series, the “sendRequest()” function should be already pretty familiar. Essentially, it performs two well-delimited tasks: the first one consists of instantiating cross-browser XMLHttpRequest objects, while the second one is responsible for sending the proper http request and fetching the contents of the file passed as a function argument. Here is its definition:

function sendRequest(doc){
    // check for existing requests
    if(xmlobj!=null&&xmlobj.readyState!=0&&xmlobj.readyState!=4){
        xmlobj.abort();
    }
    try{
        // instantiate object for Mozilla, Nestcape, etc.
        xmlobj=new XMLHttpRequest();
    }
    catch(e){
        try{
            // instantiate object for Internet Explorer
            xmlobj=new ActiveXObject(‘Microsoft.XMLHTTP‘);
        }
        catch(e){
            // Ajax is not supported by the browser
            xmlobj=null;
            return false;
        }
    }
    // assign state handler
    xmlobj.onreadystatechange=stateChecker;
    // open socket connection
    xmlobj.open(‘GET‘,doc,true);
    // send GET request
    xmlobj.send(null);
}

In simple terms, the above defined function is flexible enough to handle multiple data formats, so it’s not only restricted to reading XML files. Notice that the “doc” argument could be any file feasible for being processed through a GET request, a feature that turns the function into a very versatile piece of code.

Also, by studying the snippet a little bit deeper, it becomes clear that it allows for the fetching of content that is dynamically generated. Instead of passing in only the name of the file to be fetched, it’s possible to append some variables to the querystring, because it’s done with regular links. For instance, if the requested file is “script_file.php”, it’s extremely easy to add a few parameters for processing on the server, in the form “script_file.php?param1=1&param2=2”. I guess this is enough of an explanation for you to start tweaking the code to pull out dynamic content.

Having explained how the “sendRequest()” function does its business, it’s time to take a look at the next function “stateChecker()”, which as you’ll see in a moment, controls the flow of the whole program.

JavaScript Remote Scripting: Processing XML Files - Checking the progress of a request: a quick look at the “stateChecker()” function
(Page 4 of 6 )

If you’re used to writing JavaScript functions that verify the status of http requests, then the “statusChecker()” function should be pretty straightforward. First off, let’s see how it looks and then discuss its logic:

function stateChecker(){
    // if request is completed
    if(xmlobj.readyState==4){
        // if status == 200 display text file
        if(xmlobj.status==200){
            // create data container
            createDataContainer();
            // read XML data
            data=xmlobj.responseXML.getElementsByTagName(‘message‘);
 // display XML data
            displayData();
        }
        else{
            alert(‘Failed to get response :‘+ xmlobj.statusText);
        }
    }
}

With reference to the function above, its logic can be explained through two simple steps. Of course, the first one involves checking the request’s status by verifying the values of both “readyState” and “status” properties. Once the request has been successfully completed, the second step takes place. Notice that the code calls the “createDataContainer()” function, which is tasked with building the required (X)HTML structure for displaying headlines. However, let’s pause for a moment and pay attention to the following line:

data=xmlobj.responseXML.getElementsByTagName(‘message‘);

What this line of code does is simply store in the “data” array all the “<message>” nodes defined within the XML file that you saw previously, by applying the “getElementsByTagName()” method to the “responseXML” property. In a nutshell, this expression shows how easy it is to fetch XML data, by utilizing only DOM methods.

As you can see, the rest of the functions are fairly straightforward. After reading and storing all the “<message>” nodes in an array structure, the only thing left to be done is display the appropriate headlines. As you’ll see shortly, this operation is performed by the “displayData()” function.

JavaScript Remote Scripting: Processing XML Files - Displaying XML data: defining the “createDataContainer()” and “displayData()” functions
(Page 5 of 6 )

In order to display XML data fetched from a file, I’ll use a couple of functions aimed at dealing with visual output. The first relevant function, “createDataContainer()” builds up a containing <div> element, which will be used to house all the headlines. Since the function only uses some common DOM methods, it shouldn’t be difficult to understand at all. Below is its corresponding definition:

function createDataContainer(){
    var div=document.getElementById(‘container‘);
    if(div){return};
    var div=document.createElement(‘div‘);
    div.setAttribute(‘id‘,‘container‘);
    document.getElementsByTagName(‘body‘)[0].appendChild(div);
}

As I said previously, the above snippet creates a <div> element, then assigns to it an ID attribute and finally appends it to the document tree. By leaving out the boring details, the only point worth noting is the following checking line:

if(div){return};

Since I don’t want to have multiple data containers on the same document each time this function is invoked, I avoid this condition simply by checking for an existing containing element. In case I have such a structure, program flow is returned to calling code, without appending any element.

Having explained how an XML data container is created through the DOM, the next step consists of defining a function that builds the required (X)HTML markup for displaying XML data. This is precisely the task of the “displayData()” function, which looks like this:

function displayData(){
    // reset data container
    document.getElementById(‘container‘).innerHTML=‘‘;
    var ul=document.createElement(‘ul‘);
    for(var i=0;i<data.length;i++){
    // create links
        var li=document.createElement(‘li‘);
        var a=document.createElement(‘a‘);
        // assign ‘href‘ attribute
        a.setAttribute(‘href‘,data[i].getElementsByTagName(‘url‘)
[0].firstChild.nodeValue);
        // add link labels
        a.appendChild(document.createTextNode(data
[i].getElementsByTagName(‘title‘)[0].firstChild.nodeValue));
 li.appendChild(a);
     ul.appendChild(li);
    }
    document.getElementById(‘container‘).appendChild(ul);
}

As you can see, the above function creates dynamically the required structure for displaying the headlines. Regarding this particular case, I’ve decided to show the headlines as a set of regular links, wrapped up into an unordered (X)HTML list.

In addition to using regular DOM methods, such as “createElement()” and “createTextNode()” for dynamic element generation, there is a couple of specific lines of code that deserve special attention. Notice the following statements:

a.setAttribute(‘href‘,data[i].getElementsByTagName(‘url‘)
[0].firstChild.nodeValue);
a.appendChild(document.createTextNode(data
[i].getElementsByTagName(‘title‘)[0].firstChild.nodeValue));

Used within a loop, the first line is responsible for adding the “<url>" nodes to the “href” attribute of each link, while the second one builds the labels for each <a> tag. As a result, a list of links displaying headlines is created on the fly, by parsing the XML <message> collection defined originally within the XML document.

After running the script, the corresponding output, spiced up with some CSS styles, is depicted below:

At this point, the complete set of functions has been discussed and explained, thus the script is now capable of requesting a given XML file and displaying its contents, after applying some styling. Of course, if you want to get a higher level of abstraction for manipulating XML files, this is easy to achieve by using more generic DOM constructs to navigate the document tree, such as the “childNodes” collection. This brings up an important point, since the way you build the XML document can affect the tree structure, causing the script to break down if you don’t adjust its code to handle a new tree.

There is still one additional improvement, easily applicable to the “displayData()” function. For displaying headlines at a given time interval through an automated mechanism, a JavaScript timer helps get the job done, thus the rewritten function might be defined as follows:

function displayData(){
    // reset data container
    document.getElementById(‘container‘).innerHTML=‘‘;
    var ul=document.createElement(‘ul‘);
    for(var i=0;i<data.length;i++){
    // create links
        var li=document.createElement(‘li‘);
        var a=document.createElement(‘a‘);
        // assign ‘href‘ attribute
        a.setAttribute(‘href‘,data[i].getElementsByTagName(‘url‘)
[0].firstChild.nodeValue);
        // add link labels
        a.appendChild(document.createTextNode(data
[i].getElementsByTagName(‘title‘)[0].firstChild.nodeValue));
 li.appendChild(a);
     ul.appendChild(li);
    }
    document.getElementById(‘container‘).appendChild(ul);
    // update headlines each 1 hour
    setTimeout("sendRequest(‘news.xml‘)",3600*1000);
}

Assuming that headlines are stored in the “news.xml” file, the modified version of the function now will request that file each hour, therefore by setting up the appropriate http headers to tell the browser not to cache the document, any changes introduced within the XML file will be automatically reflected by the output of the script.

Now that you have a clear idea about how to use AJAX for parsing XML files, it’s time to list the full source code for the script, so it’s available to you in one place. In this way, you can use it for your own convenience.

JavaScript Remote Scripting: Processing XML Files - Putting the pieces together: listing the complete script
(Page 6 of 6 )

As I said before, below is the list of the whole script, including a few additional lines to run the program after the page has been loaded:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"
http://www./TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>READING XML FILES WITH AJAX</title>
<script type="text/javascript">
// initialize XMLHttpRequest object
var xmlobj=null;
var data=new Array();
// send http request
function sendRequest(doc){
    // check for existing requests
    if(xmlobj!=null&&xmlobj.readyState!=0&&xmlobj.readyState!=4){
        xmlobj.abort();
    }
    try{
        // instantiate object for Mozilla, Nestcape, etc.
        xmlobj=new XMLHttpRequest();
    }
    catch(e){
        try{
            // instantiate object for Internet Explorer
            xmlobj=new ActiveXObject(‘Microsoft.XMLHTTP‘);
        }
        catch(e){
            // Ajax is not supported by the browser
            xmlobj=null;
            return false;
        }
    }
    // assign state handler
    xmlobj.onreadystatechange=stateChecker;
    // open socket connection
    xmlobj.open(‘GET‘,doc,true);
    // send GET request
    xmlobj.send(null);
}
// check request status
function stateChecker(){
    // if request is completed
    if(xmlobj.readyState==4){
        // if status == 200 display text file
        if(xmlobj.status==200){
            // create data container
            createDataContainer();
            // read XML data
            data=xmlobj.responseXML.getElementsByTagName
(‘message‘);
 // display XML data
            displayData();
        }
        else{
            alert(‘Failed to get response :‘+ xmlobj.statusText);
        }
    }
}
// create data container
function createDataContainer(){
    var div=document.getElementById(‘container‘);
    if(div){return};
    var div=document.createElement(‘div‘);
    div.setAttribute(‘id‘,‘container‘);
    document.getElementsByTagName(‘body‘)[0].appendChild(div);
}
// display data at a given time interval
function displayData(){
    // reset data container
    document.getElementById(‘container‘).innerHTML=‘‘;
    var ul=document.createElement(‘ul‘);
    for(var i=0;i<data.length;i++){
        // create links
        var li=document.createElement(‘li‘);
        var a=document.createElement(‘a‘);
        // assign ‘href‘ attribute
        a.setAttribute(‘href‘,data[i].getElementsByTagName(‘url‘)
[0].firstChild.nodeValue);
        // add link labels
        a.appendChild(document.createTextNode(data
[i].getElementsByTagName(‘title‘)[0].firstChild.nodeValue));
        li.appendChild(a);
        ul.appendChild(li);
    }
    document.getElementById(‘container‘).appendChild(ul);
    // update headlines each 1 hour
    setTimeout("sendRequest(‘news.xml‘)",5*1000);
}
// execute program when page is loaded
window.onload=function(){
    // check if browser is DOM compatible
    if(document.getElementById&&document.
getElementsByTagName&&document.createElement){
        // load XML file
        sendRequest(‘news.xml‘);
    }
}
</script>
<style type="text/css">
#container {
    background: #eee;
    padding: 5px;
    border: 1px solid #000;
}
li {
    margin-top: 5px;
}
a:link,a:visited {
    font: bold 11px Tahoma, Arial, Helvetica, sans-serif;
    color: #00f;
}
a:hover {
    color: #f00;
}
</style>
</head>
<body>
</body>
</html>

To wrap up

That’s it for now. Throughout this second part of the series, you’ve hopefully learned how to use AJAX for reading and manipulating simple XML files, in order to implement a basic Web service. Certainly, the concepts that I illustrated at the very beginning imply a challenge for developing richer applications that use remote scripting to provide users with a more interactive experience.

The third tutorial of the series goes one step further with remote scripting, by explaining its implementation through the use of fully-standard DOM methods, without getting a single foot into AJAX technology. Want to know more? Just wait for the next part!


DISCLAIMER: The content provided in this article is not warrantied or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation best practices. We are not liable for any negative consequences that may result by implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware.


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多