Pages

Thursday, February 5, 2009

I don't really enjoy writing articles that are primarily about something that you shouldn't do. Most of the time, it's a pretty silly type of thing to write. I spend half an article explaining something, just so I can spend the rest of the article explaining what a bad idea it is to use the techniques you've just learned about. Such was the case, to a large degree, with previous article, which taught you how to use XML as the data format for your Ajax apps' requests.

Hopefully, this article will redeem the time you spent learning about XML requests. In Ajax apps, while there are very few reasons to use XML as the sending data format, there are a lot of reasons why we may want a server to send XML back from a server, to a client. So everything we see about XML in the last article will definitely start to have some value in this article.

Servers can't say much (sometimes)


Before we go deeper into the technical details of getting an XML response from a server, we need to understand why it's such a good idea for a server to send XML in response to a request (and how that's different from a client sending that request in XML).

Clients speak in name/value pairs


As we recall from the last article, clients don't need to use XML in most cases because they can send requests using name/value pairs. So we might send a name like this: name=haki . We can stack those up by simply adding an ampersand ( & ) between successive name/value pairs, like this: name=haki&job=programmer . Using simple text and these name/value pairs; clients can send requests with multiple values to a server easily. There's rarely a need for the additional structure (and overhead) that XML provides.

In fact, almost all the reasons we'd need to send XML to a server can be grouped into two basic categories:


  • The server only accepts XML requests. In these cases, we don't have a choice. The basics in last month's article should give us all the tools you need to send these sorts of requests.

  • We're calling a remote API that only accepts XML or SOAP requests. This is really just a specialized case of the previous point, but it's worth mentioning on its own. If we want to use the APIs from Google or Amazon in an asynchronous request, there are some particular considerations. We'll look at those, and a few examples of making requests to APIs like this, in next month's article.


Servers can't send name/value pairs (in a standard way)


When we send name/value pairs, the Web browser sending the requests and the platform responding to that request and hosting a server program cooperate to turn those name/value pairs into data that a server program can work with easily. Practically every server-side technology -- from servlets to PHP to Perl to Ruby on Rails -- allows you to call a variety of methods to get at values based on a name. So getting the name attribute is trivial.

This isn't the case going in the other direction. If a server replied to an app with the string name=haki&job=programmer , the client has no standardized, easy way to break up the two name/value pairs, and then break each pair into a name and value. You'll have to parse the returned data manually. If a server returns a response made up of name/value pairs, that response is no easier (or harder) to interpret than a response with elements separated by semicolons, or pipe symbols, or any other nonstandard formatting character.


What that leaves us with, then, is no easy way to use plain text in our responses and have the client get that response and interpret it in a standard way, at least when the response contains multiple values. If our server simply sent back the number 42, say, plain text would be great. But what about if it's sending back the latest ratings for Movies Aundathi, Neninthe, and king, all at once? While we can chose many ways to send this response using plain text (see listing below for few examples), none are particularly easy to interpret without some work by the client, and none are standardized at all.

Listing.. Server response for movie ratings (various types)


movie=arundathi&ratings=14.2|movie=Neninthe&ratings=6.5|movie=King&rating=9.1

arundathi =14.2| Neninthe =6.5|King =9.1  

arundathi|14.2|Neninthe|6.5|King|9.1

Even though it's not too hard to figure out how to break up these response strings, a client will have to parse and split the string up based on the semicolons, equal signs, pipes, and ampersands. This is hardly the way to write robust code that other developers can easily understand and maintain.

Enter XML


When we realize that there's no standard way for a server to respond to clients with name/value pairs, the reason behind using XML becomes pretty clear. When sending data to the server, name/value pairs are a great choice because servers and server-side languages can easily interpret the pairs; the same is true for using XML when returning data to a client. We saw the use of the DOM to parse XML in several earlier articles, and will see how JSON provides yet another option to parse XML in a future article. And on top of all that, we can treat XML as plain text, and get values out of it that way. So there are several ways to take an XML response from a server, and, with fairly standard code, pull the data out and use it in a client.

As an added bonus, XML is generally pretty easy to understand. Most people who program can make sense of the data in listing below, for example.

<ratings>
<movie>

<title>Arundathi</title><rating>14.2</rating>

</movie>
<movie>

<title>Neninthe</title><rating>6.5</rating>

</movie>

<movie>

<title>King</title><rating>9.1</rating>
</movie>
</ratings>

The code in above has no consideration about what a particular semicolon or apostrophe means.

Receiving XML from a server


Because the focus of this series is on the client side of the Ajax equation, we won't bother into much detail about how a server-side program can generate a response in XML. However, we need to know about some special considerations when your client receives XML.

First, you can treat an XML response from a server in two basic ways:

  • As plain text that just happens to be formatted as XML

  • As an XML document, represented by a DOM Document object.


Second, presume a simple response XML from a server for example's sake. Listing below shows the same TV listings as detailed above (this is, in fact, the same XML as in listing above reprinted for your convenience). I'll use this sample XML in the discussions in this section.

Listing.. XML-formatted movie for examples

<ratings> <movie> <title>Arundathi</title> <rating>14.2</rating> </movie> < movie> <title>Neninthe</title> <rating>6.5</rating> </movie > < movie > <title>King</title> <rating>9.1</rating> </movie> </ratings>

Dealing with XML as plain text


The easiest option to handle XML, at least in terms of learning new programming techniques, is to treat it like any other piece of text returned from a server. In other words, we basically ignore the data format, and just grab the response from the server.

In this situation, we use the responseText property of your request object, just as you would when the server sends you a non-XML response (see Listing below).

Listing.. Treating XML as a normal server response


function updatePage()

{

if (request.readyState == 4)

{

if (request.status == 200)

{

var response = request.responseText;  

// response has the XML response from the server

alert(response);

}

}

}

In this code fragment, updatePage() is the callback, and request is the XMLHttpRequest object. You end up with the XML response, all strung together, in the response variable. If you printed out that variable, we'd have something like Listing below. (Note that the code in listing below normally is one, continuous line. Here, it is shown on multiple lines for display purposes.)

Listing.. Value of response variable


<ratings><movie><title>Arundathi</title><rating>14.2</rating></movie> <movie><title>Neninthe</title><rating>6.5</rating></movie> <movie><title>King</title><rating>9.1</rating></movie></ratings>

The most important thing to note here is that the XML is all run together. In most cases, servers will not format XML with spaces and carriage returns; they'll just string it all together, like you see in Listing above. Of course, our apps don't care much about spacing, so this is no problem; it does make it a bit harder to read, though.

At this point, we can use the JavaScript split function to break up this data, and basic string manipulation to get at the element names and their values. Of course, that's a pretty big pain, and it ignores the handy fact that you spent a lot of time looking at the DOM, the Document Object Model, earlier in this series. So I'll urge you to keep in mind that you can use and output a server's XML response easily using responseText , but I won’t show you much more code; we shouldn't use this approach to get at the XML data when you can use the DOM, as you'll see next.

Treating XML as XML


While we can treat a server's XML-formatted response like any other textual response, there's no good reason to do so. First, if you've read this series faithfully, you know how to use the DOM, a JavaScript-friendly API with which we can manipulate XML. Better yet, JavaScript and the XMLHttpRequest object provide a property that is perfect for getting the server's XML response, and getting it in the form of a DOM Document object.

To see this in action, check out listing below. This code is similar to listing above, but rather than use the responseText property, the callback uses the responseXML property instead. This property, available on XMLHttpRequest , returns the server's response in the form of a DOM document.
Listing.. Treating XML as XML


function updatePage()

{

if (request.readyState == 4)

{

if (request.status == 200)

{

var xmlDoc = request.responseXML;  

// work with xmlDoc using the DOM

}

}

}

Now we have a DOM Document , and we can work with it just like any other XML. For example, we might then grab all the show elements, as in listing below

Listing.. Grabbing all the show elements


function updatePage()

{

if (request.readyState == 4)

{

if (request.status == 200)

{

var xmlDoc = request.responseXML;

var movieElements = xmlDoc.getElementsByTagName("movie");

}

}

}

If one are familiar with DOM, they should start to feel familiar. Here, we can use all the DOM methods that are already learned, and easily manipulate the XML you received from the server.

We can also, of course, mix in normal JavaScript code. For instance,we might iterate through all the show elements, as in listing below.
Listing.. Iterating through all the show elements

function updatePage()

{

if (request.readyState == 4)

{

if (request.status == 200)

{

var xmlDoc = request.responseXML;  

var showElements = xmlDoc.getElementsByTagName("movie");

for (var x=0; x<showElements.length; x++)

{ // We know that the first child of show is title, and the second is rating

var title = showElements[x].childNodes[0].value;

var rating = showElements[x].childNodes[1].value;  

// Here every thing can be done to title and ratings to display…

}

}

}

}

With this relatively simple code, we treated an XML response like its XML, not just plain unformatted text, and used a little DOM and some simple JavaScript to deal with a server's response. Even more importantly, we worked with a standardized format XML, instead of comma-separated values or pipe-delimited name/value pairs. In other words, we’ve used XML where it made sense, and avoided it when it didn't, like in sending requests to the server.

XML on the server: A brief example


Although I haven't talked much about how to generate XML on the server, it's worth seeing a brief example, without much commentary, just so one can come up with their own ideas on how to deal with such a situation. Listing below shows a simple PHP script that outputs XML in response to a request, presumably from an asynchronous client.

This is the raw approach, where the PHP script is really just pounding out the XML output manually. We can find a variety of toolkits and APIs for PHP and most other server-side languages that also allow you to generate XML responses. In any case, this at least gives us an idea of what server-side scripts that generate and reply to requests with XML look like.
Listing.. PHP script that returns XML


<?php

// Connect to a MySQL database

$conn = @mysql_connect("localhost", "username", "secret-password");

if (!conn) die("Error connecting to database: " . mysql_error());  

if (!mysql_select_db("movie", $conn)) die("Error selecting movie database: " . mysql_error());  

// Get ratings for all TV shows in database

$query = 'SELECT title, rating from ratings';

$queryResult = mysql_query($query);

if (!$queryResult) die("Error retrieving ratings for movies.');  

// Let the client know we're sending back XML

header("Content-Type: text/xml");


echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>";


echo "<ratings>";

while ($row = mysql_fetch_array($queryResult))

{

$title = $row['title'];

$rating = $row['rating'];

echo "<movie> echo "<title>" . $title . "</title>"; echo "<rating>" . $rating . "</rating>"; echo "</movie>";

}  

echo "</ratings>";


mysql_close($conn);

?>

You can be able to output XML in a similar way using your own favorite server-side language.

Other options for interpreting XML


One very popular options for dealing with XML, beyond treating it as unformatted text or using the DOM, is important and worth mentioning. That's JSON, short for JavaScript Object Notation, and it's a free text format that is bundled into JavaScript. I don't have space to cover JSON in this article. You'll probably hear about it as soon as you mention XML and Ajax apps, however, so now you'll know what your co-workers are talking about.

In general, everything that you can do with JSON, you can do with the DOM, or vice versa; it's mostly about preference, and choosing the right approach for a specific application. For now, stick with the DOM, and get familiar with it in the context of receiving a server's response. In next articles, we'll have a good amount of time on JSON, and then you'll be ready to choose between the two on your next app. Lots of more XML could be in next articles.

In conclusion


I've talked about XML nearly non-stop since the last article in this series began, but have still really only scratched the surface of XML's contribution to the Ajax equation.

Your biggest task in the short term, though, is to really think about when XML makes sense for your own applications. In many cases, if your app is working well, then XML is nothing more than a technology buzzword that can cause you headaches, and you should resist the temptation to use it just so you can say you have XML in your application.

If you've a situation where the data the server sends you is limited, though, or in a strange comma- or pipe-delimited format, then XML might offer you real advantages. Consider working with or changing your server-side components so that they return responses in a more standard way, using XML, rather than a proprietary format that almost certainly isn't as robust as XML.

Most of all, realize that the more you learn about the technologies around Ajax, the more careful you have to be about your decisions. It's fun to write these Web 2.0 apps (and in coming articles, you'll return to the user interface and see some of the cool things that you can do), but it also takes some caution to make sure you don't throw technologies at a working Web page just to impress your friends. I know you can write a good app, so go out and do just that. When you're finished, come back here for article, and even more XML.

0 comments: