XML


XML (Extensible Markup Language) is a popular choice for XHRs, simply because it is the standard intermediate language that all programming languages are able to share. It is also supported both on the server side and client side, which makes it the most flexible solution. XML is essentially a custom tag-based structure that you, the developer, define. XML's tag-based structure is similar to that of HTML, except that HTML has predefined tags that represent its structure, such as the head, the body, tables, and so on. The following is an extremely simple example of an HTML table, which could easily be translated or used as XHTML:

<table><tr><td></td></tr></table>


XML can be passed between the front end and the back end for easy communication of multiple languages. Having this common language between the front end and the back end is extremely powerful. It enables us to create direct connections from the GUI to a server-side language and, ultimately, if desired, a database. Communicating with XML between the GUI and the front end allows for complete separation of the two application layers. Separation of the GUI and the back-end logic is extremely important because it enables us to have a completely decoupled application in which GUI developers can work on the front end, while the back-end developers work on the back end. This might seem like common sense, but it is an approach lacking approach in many companies. It keeps specific parts of the application separated for easier management, and allows teams or individual developers to focus on the layer that is in need of growth. Not only is this approach ideal for teams of developers, it is also important for any individual developer who might be working on every part of the application. With this structure, an individual developer can focus on specific layers of the application without interfering or having to make changes to the adjacent layers.

XML formatting is trivial, but there are important principles to consider when planning a solution. Imagine having to format email data into a structure that could be requested through an Ajax engine and displayed with client-side JavaScript objects. This is a structure that we will be creating for the sample in this book. When architecting this structure, we want to keep in mind that we may use it in multiple objects or locations of the application and should therefore keep it as abstract as possible. We will start by defining the main elements that will create this structure.

Elements

XML is composed of custom tags called elements, which are defined in the architecture phase of a web application. They can represent any name, value, or data type that will be used in your application. When creating an XML structure, you become the architect of your application, deciding what data you will need to display certain items on the screen, or what response should happen based on a user's interaction.

It is important to keep our structures as abstract as possible by not naming items specific to the target application, but there are often unique situations that prevent us from being as abstract as we need to be. In these cases, it is not beneficial to spend the extra time to make our XML structure abstract because it might not even be necessary to reuse the XML data in multiple areas of the application. With that said, it is possible to be abstract with our email XML sample and it will be reused in other aspects of the application. The following is a usable XML format, but not an extremely scalable or reusable option:

<categories>     <From/>     <Subject/>     <Date/> </categories>


In order to keep these categories abstracted, we will change the names of the elements to category (see Listing 3.1).

Listing 3.1. An Abstract List of Categories (.xml)

<categories>     <category>From</category>     <category>Subject</category>     <category>Date</category> </categories>

This option provides the flexibility that allows us to add additional categories with ease. There are many reasons that this option is more scalable; an important one to remember is the fact that we can add a new category without having to change the structure of our XML data. This is why it is so flexible and a more scalable option than the previous example. Also, if we create object-oriented objects to display the data, we do not need to add additional parsing and display code to handle the new elements. This is why it is so important to architect the solution with abstract structures that can be scalable and easily ported to other applications or objects. For instance, imagine that you need to display the same list of categories in two different ways, such as in a data grid and an email preview. This same set of elements can be used in both objects, which eliminates any redundancies in code from our application.

Although elements are what make XML, there is a limit to what can be achieved with elements alone. Let's take a look at attributes and how they help us add additional information to our XML data.

Attributes

XML attributes are additional properties that can be added to your elements to provide more information specific to the structure. From the email sample, let's focus on an email element. An email has many attributes, such as an action that is triggered when the email is selected, and an icon association, such as a sealed or opened envelope, based on the read status of the email. In order to represent our emails in the XML, we will create a group of items that can eventually become a collection of objects or an array when they are parsed on the client side. This is where we will add our action and icon attributes. Attributes are easy additions to elements. Take a look at Listing 3.2 to get an idea of how we will add the action and icon attributes to an XML element.

Listing 3.2. An Abstract List of Items (email.xml)

<items action="alert('Grace Hopper');" icon="img/mail.gif">     <item><![CDATA[Grace Hopper]]></item>     <item><![CDATA[<b>BUG Found</b>]]></item>     <item>2006-03-31 09:27:26</item> </items>

There are some issues that are very important to be aware of when using attributes, especially in large applications where making a mistake in the architecture stage can create havoc when scaling. One of the biggest issues with attributes is not having the ability to add multiple values in one attribute. This could create an issue if you later decide that you need to have more than one instance of a specific detail that was already defined as an attribute, leaving you or your fellow developers having to make changes in multiple locations where there are references to the attributes.

Another important issue, and one that we will discuss a solution for in the next section, is adding HTML to your XML. HTML cannot be added to attributes because it will create an invalid structure. The only way to add HTML to an XML structure is within an element. It is much safer to add an element than an attribute because if you realize that you made a mistake and forgot to format the element properly to contain HTML, you can always reformat it later to accept HTML without breaking any code that might be referencing it. In order to add HTML to elements so that it is readable by the programming language that is parsing it and does not break the validation of the XML, we need to add CDATA tags to the element tags.

CDATA

CDATA makes XMLand, ultimately, the web applications that use itextremely powerful by allowing us to add HTML to elements. The HTML can then be used to display formatted data directly into a DOM element in our Ajax application front end. When XML is parsed by the programming language that we are using, the value between the element tags is also parsed. The following example shows a group of <item> elements that are nested in an </items> element:

<items action="alert('Grace Hopper');" icon="img/mail.gif">     <item>Grace Hopper</item>     <item>BUG Found</item>     <item>2006-03-31 09:27:26</item> </items>


These nested elements need to be parsed into subelements by the parser in order to be interpreted by the programming language as child nodes, for example. This means that nesting HTML tags inside of XML elements will not work because the parser will see these elements as nested or child elements of the parent element rather than HTML tags, which will make the XML invalid, causing parsing errors or unexpected results. The following XML will parse with the HTML bold tag (</b>) as an XML element because the parser will see the bold tags as nested XML tags rather than HTML:

<item><b>BUG Found</b></item>


In order to add HTML to the XML element, we are required to use CDATA. XML parsers do not parse the data immediately following these tags, leaving us with a valid XML structure and ultimately the HTML format that we would like to display in the page. The following code shows valid XML with HTML tags nested in an element using CDATA:

<item> <![CDATA[<b>BUG Found</b>]]></item>


When this data is parsed by the client-side scripting language, which in our case will be JavaScript, the HTML will render as is between the tags. For example, the text value of BUG Found will display as bold text to the user in the GUI if we write the data to the document. The data can be written to the document by simply targeting an HTML tag using the DOM and appending the value with JavaScript's intrinsic innerHTML property, or we could simply use document.write(); to write the value directly to the location in which we place this line of code. Let's take a deeper look at parsing the response.

Parsing XML

When planning the format and tag names that you will be using in your XML, it is important to keep a number of things in mind. For instance, it is usually beneficial to have unique names for elements that are at different depths in your file. This will eliminate parsing issues when using JavaScript's intrinsic getElementsByTagName method. Using this method will return an array of all the elements by the name that you specify without looking at the depth in which they reside. One issue that this could cause is that groups of values from different depths that do not belong together can be combined into one array that does not delineate the correct location of the data, causing a parsing nightmare for you or your fellow developers. There are ways to parse data that use nested tags with duplicate names, such as targeting with the childNodes property, but this can become difficult and lengthen the development process. You could also create an object that has methods for parsing specific items by name at specific depths, such as XPath does in other languages, or use attributes to distinguish different nodes with the same name. But for our purposes, we will simply define our structure in a way that we do not have to worry about such issues.

There are fairly standard ways of parsing XML with different languages, but parsing XML with JavaScript is a bit different. As I have mentioned, JavaScript has an intrinsic method named getElementsByTagName, which can target a group of elements directly by name and allow us access to them so that we can easily parse element or attribute values. This method will either return a single element or a group of elements by the tag name specified as the parameter, as in the following example:

response.getElementsByTagName('items');


When the method finds a group of elements, it will return an array of childNodes that you will need to parse to receive their inner nodeValues. To use this method in your parsing, it is important to target the XHR object correctly after the response has been made. Let's take a look at Listing 3.3 for the completed XML sample that we will use as a parsing example.

Listing 3.3. The Final Email XML File (email.xml)

<?xml version="1.0" encoding="iso-8859-1"?> <data>     <categories>         <category>From</category>         <category>Subject</category>         <category>Date</category>     </categories>     <row>         <items action="alert('Grace Hopper');" icon="img/mail.gif">             <item><![CDATA[Grace Hopper]]></item>             <item><![CDATA[<b>BUG Found</b>]]></item>             <item>2006-03-31 09:27:26</item>         </items>     </row>     <row>         <items action="alert('Pi Sheng');" icon="img/mail.gif">             <item><![CDATA[Pi Sheng]]></item>             <item><![CDATA[Movable type]]></item>             <item>2006-01-15 12:32:45</item>         </items>     </row> </data>

In order to sample our parsing methods, we will need to create an HTML file that will have two hyperlinks: one that will request an XML file as a response, and another that will request a JSON response. Listing 3.4 shows the index HTML file that will contain the requesting hyperlinks.

Listing 3.4. The Index File for XML and JSON Request Samples (index.html)

<html> <head> <title>The Response</title> <script type="text/javascript" src="/books/1/87/1/html/2/javascript/ajax.js"></script> </head> <body> <a href="javascript:makeRequest('services/email.xml', onXMLResponse);">xml</a> &nbsp;|&nbsp; <a href="javascript:makeRequest('services/email.js', onJSONResponse);">json</a> <br/><hr noshade="noshade"> <div ></div> <div ></div> </body> </html>

As you can see, this file simply has two hyperlinks that, when clicked, make a request through the makeRequest method that we created in Chapter 2. The only difference with the method is that I have now added a variable callback method. This allows us to pass a callback method of our choice, which provides us with the opportunity to parse the response as we would like, based on the specific request being made. We also have two div tags in place to display different data. One div tag has an id value of loading and the other of body. The loading div is used for the loading message that is returned while checking the ready state. The body div is used to display the actual data after we parse the response. This data can be formatted any way we chooseit can be displayed as anything from a simple list of data to an entire GUI that is formatted with XHTML and contains interaction data. To begin parsing the XML response, we must first add the callback method that we specified in the request. We will add a method named onXMLResponse to the ajax.js that we are importing in the index, check the ready state, and target the XML data with a property of the XHR called responseXML (see Listing 3.5).

Listing 3.5. Creating a Response Method and Checking the Ready State (ajax.js)

function onXMLResponse() {     if(checkReadyState(request, 'loading') == true)     {         var response = request.responseXML.documentElement;         //Parse here     } }

By checking the ready state, we are accomplishing two things. First, we are checking the status of the request to decipher whether it has completed loading and is ready to be parsed. Second, we are passing a div id to display the ready state messages with its innerHTML property. There are two properties listed in Table 2.1 that can be used to target data with the XHRone is responseText and the other is responseXML. The responseText property returns a string version of the response from the server, and the responseXML property returns a DOM-compatible document object of the response from the server. In this case, we will use the responseXML property because we need a DOM-compatible object for the XML response so that we can target specific items in the file. After we have this code written, we can begin to parse values from the elements. We will start by parsing the category values from the XML file and adding them to the body div via the innerHTML property as shown in Listing 3.6.

Listing 3.6. Retrieving the Category Values from the XML (ajax.js)

[View full width]

// Categories document.getElementById("body").innerHTML = "------------<br/>"; document.getElementById("body").innerHTML += "<b>Categories</b><br/>"; document.getElementById("body").innerHTML += "------------<br/>"; var categories = response.getElementsByTagName('category'); for(var i=0; i<categories.length; i++) {     document.getElementById("body").innerHTML += response.getElementsByTagName ('category')[i].firstChild.data +"</br>"; }

In order to target each of the categories, we need to use the getElementsByTagName method and pass category as the parameter. This will provide us with an array of categories that we can iterate and add one by one to the body div. As we add the categories to the document, we are targeting the data within each of the tags in order to display the actual value of each element.

After we have the categories displayed, we can move on to the item tags from the XML. We will parse these slightly different by targeting the parents, which are the row tags, and receiving an array of rows. Then we will iterate through the rows to target the action and icon attributes within the items tags through JavaScript's intrinsic getAttribute method. After we are finished writing the attribute values to the div, we can target the individual items within each row. We will do this by nesting two for loops within the for loop that we are using for the rows, leaving us with a three-layer loop. One loop will be used to iterate the items tag and the other to iterate the node values within the individual item tags as shown in Listing 3.7.

Listing 3.7. Retrieving the Item Values from the XML (ajax.js)

// Items document.getElementById("body").innerHTML += "------------<br/>"; document.getElementById("body").innerHTML += "<b>Items</b><br/>"; document.getElementById("body").innerHTML += "------------<br/>"; var row = response.getElementsByTagName('row'); for(var i=0; i<row.length; i++) {     var action = response.getElementsByTagName('items')[i].getAttribute('action');     var icon = response.getElementsByTagName('items')[i].getAttribute('icon');     document.getElementById("body").innerHTML += action +"<br/>"+ icon +"</br>";     var items = response.getElementsByTagName('items')[i].childNodes;     for(var j=0; j<items.length; j++)     {         for(var k=0; k<items[j].childNodes.length; k++)         {             document.getElementById("body").innerHTML += items[j].childNodes[k].nodeValue +"</br>";         }     }     document.getElementById("body").innerHTML += "------------<br/>"; }

Parsing requested XML is fairly simple if you know what format to expect as the response from the server. If we did not know what to expect in the previous example of the response, we could have started by using the responseText property to display the XML structure as a string and decipher what tags we needed to target.

function onXMLResponse() {     if(checkReadyState(request, 'loading') == true)     {         var response = request.responseText;         alert(response);     } }


This would have provided us with the entire XML structure in an alert prompt. At that point, we would be able to take a look at the structure and figure out what we wanted to parse with the responseXML property.

As you can see, XML can basically accomplish any type of data structureit is essentially up to the objects that read the XML to do something useful with it. Let's take a look at how JSON compares and what the benefits are when formatting a response.



Ajax for Web Application Developers
Ajax for Web Application Developers
ISBN: 0672329123
EAN: 2147483647
Year: 2007
Pages: 129
Authors: Kris Hadlock

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