Raymond Camden's Blog Rss

Spry 1.4: documentToObject makes XML handling easy

6

Posted in ColdFusion | Posted on 12-17-2006 | 2,993 views

In my chat demo post last week, I talked about how I had trouble figuring out how to work with XML in JavaScript. It wasn't terribly hard, it just took me a while to find some decent docs, as well as to find something that worked in both Firefox and the Devil's Browser.

One of the cool new features of Spry 1.4 would have really helped me out. There are two new functions, Spry.XML.nodeToObject() and Spry.XML.documentToObject(), which make working with XML a lot easier.

Kin Blas, one of the Adobe Spry guys, took the time to rewrite part of my chat app and write some cool documentation for what he did as well. Here is the new version of chatResp, my code to handle the result from the back end of the chat demo:

view plain print about
1function chatResp(request) {
2    var xml = Spry.XML.documentToObject(request.xhRequest.responseXML);
3
4     if (xml.chats) {
5        // There was a chats node in the XML we just loaded, so iterate over
6        // any chat nodes it contains.
7        if (xml.chats.chat) {
8            // We have one or more chat nodes. If there is a single
9            // chat node, xml.chats.chat will be an object that represents
10            // that node. If there were multiple chat nodes, then xml.chats.chat
11            // will be an array of chat objects.
12            //
13            // I'm going to cheat a bit here and make sure that we *always* have
14            // an array of chats to simplify the logic below. So if xml.chats.chat
15            // is not an array, I make it one with a single object in it.
16            if (!xml.chats._propertyIsArray("chat")) xml.chats.chat = [ xml.chats.chat ];
17
18            // Grab the number of chats so we don't have to do it for *every*
19            // iteration of the loop below. Also, instead of writing out directly
20            // to the div through each iteration, it's more of a performance boost
21            // to collect a string, and then slam it in when we're done.
22            var numChats = xml.chats.chat.length;
23            var newContent = "";
24
25            for (var i = 0; i < numChats; i++) {
26                // Extract out the values for user, message and time into local variables
27                // so we save the JS interpreter some processing time.
28                var user = xml.chats.chat[i].user._value();
29                var message = xml.chats.chat[i].message._value();
30                var time = xml.chats.chat[i].time._value();
31                var lastId = xml.chats.chat[i]["@id"];
32
33                if (user && message && time) {
34                    // We have values for everything! Add it to our content string.
35                    newContent += "<span class='chat_time'>[" + time + "]</span> ";
36 newContent += "<span class='chat_talk'>" + user + " said: " + message + "</span><br>";
37                    var cdiv = $("div_chat");
38                    cdiv.innerHTML += newContent;
39                    cdiv.scrollTop = cdiv.scrollHeight;
40                }
41            }
42    
43            if(lastId != "") lastToken = parseInt(lastId)+1;
44
45        }
46
47    }
48
49    setTimeout('loadChat()', pingDur*1000);
50
51}

There is a lot going on here but since Kin provided great comments, I don't have to add a lot. I do want to point out a few things though. First - lets look at how you get an XML value in the old code:

view plain print about
1message = chatNode.getElementsByTagName("message")[0].childNodes[0].nodeValue;

Now compare it to the new version:

view plain print about
1var message = xml.chats.chat[i].message._value();

Nice, eh? I typically use shortcuts when working in arrays, so if I had written I would have ended up with something even shorter:

view plain print about
1var message = thechat.message._value();

You can view the updated chat demo here:

http://ray.camdenfamily.com/demos/chat

I'll have more 1.4 demos during the week. Enjoy. Oh, and I've attached the code again to this blog entry. I made the ColdFusion side a bit tighter to help decrease the white space returned by the code.

Edited: I forgot something. Kin had sent me yet another update to this code. Look above at this code block:

view plain print about
1if (!xml.chats._propertyIsArray("chat")) xml.chats.chat = [ xml.chats.chat ];

He explains why this is necessary (in case chat isn't an array but one item). There is a utility method to make this simpler.

view plain print about
1xml.chats.chat = xml.chats._getPropertyAsArray("chat");

This will let you treat the data as an array no matter what.

Download attached file

Comments

[Add Comment] [Subscribe to Comments]

Spry is beginning to get filled out as a framework. Each release brings some good additional features and it is good to see the framework evolve into a good Ajax Solution.

I wonder if spry will be incorporated into Scorpio?
Ray,

Is there a way to use spry to access XML items that have a . in the name.

ie
<people>
<person>
<programmer.firstname> Ray </programmer.firstname>
<programmer.lastname> Camden</programmer.lastname>
</person>
</people>
Did you try bracket notation?
Yup, bracket notation worked
Not working in IE 8
Err, well, this blog entry is about 3 years old now. WAY before IE8 was released. I don't use Spry anymore, but I'm sure if you use updated libraries from the Spry folks that it will most likely work right.

[Add Comment] [Subscribe to Comments]