I personally find this method of relative indexing based on siblings and children quickly becomes convoluted, so I prefer to use another method of accessing values in XML documents which we'll now discuss. As well as keeping track of the associations between nodes in terms of children, siblings, parents, et al. Flash keeps arrays of all nodes within another node. This array is called the 'childNodes' array because it lists all children for a specific node and it's a great way to easily get to any specific node in an XML document. If we want to view all children of the Details node, we could use the following code:

trace(xmlDoc_xml.firstChild.childNodes);

This provides us with a (long) comma separated list of all the children of the Details node. To get access to the first child of the Details node, we just use standard Array notation:

trace(xmlDoc_xml.firstChild.childNodes[0]);

(Remembering that arrays in Flash are 0-indexed, so the first element is element 0.)

This way we can write a function which loops through each child and uses the same code to extrapolate the value of every child node:

function processBook(xmlDoc_xml) {
        // xmlDoc_xml is now a reference to the XML
        // object where our information is stored
        for (var n = 0; n<xmlDoc_xml.firstChild.childNodes.length; n++) {
                trace(xmlDoc_xml.firstChild.childNodes[n].firstChild.nodeValue);
        }
}

This code will loop through each child of the Details node and output the value between the child node's tags. (If this looks foreign to you please revise my Scripted Loops tutorial.) Below is a copy of the output from the above code:

059600396X
ActionScript for Flash MX: The Definitive Guide, 2nd Edition
Book
null
19 December, 2002
O'Reilly & Associates
http://images.amazon.com/images/P/059600396X.01.THUMBZZZ.jpg
http://images.amazon.com/images/P/059600396X.01.MZZZZZZZ.jpg
http://images.amazon.com/images/P/059600396X.01.LZZZZZZZ.jpg
$54.95
$38.47

See the problem? The problem occurs when we reach the Author child of the Details node (the fourth line of the above output) at which time the script outputs the value 'null' instead of the name(s) of the author(s) of this book. Can you think why? Revise the tree structure of the XML document we're using, (shown below in Figure 4).


Figure 4: Tree representation of sample XML document

The incorrect output is caused by the fact that the Authors node has children of its own (the Author nodes), and it is within these children that the actual names of the authors reside, so when we ask for the nodeValue of the Authors node, we're told it is 'null' because that node contains nothing but other nodes. In order to actually print out the names of the authors we will have to add another call to firstChild to drill-down into the Authors node and pull the values out of the Author node children. This can be done by checking to see when we've reached the Authors node, and catching that special case with some extra code as follows.

function processBook(xmlDoc_xml) {
        // xmlDoc_xml is now a reference to the XML
        // object where our information is stored
        for (var n = 0; n<xmlDoc_xml.firstChild.childNodes.length; n++) {
                if (xmlDoc_xml.firstChild.childNodes[n].nodeName == "Authors") {
                        trace(xmlDoc_xml.firstChild.childNodes[n].firstChild.firstChild.nodeValue);
                } else {
                        trace(xmlDoc_xml.firstChild.childNodes[n].firstChild.nodeValue);
                }
        }
}

The above code checks as it rolls through the children of the Details node, whether or not the next node to be processed is the "Authors" node using the nodeName property and a conditional statement. When the Authors node is found, we drill down one more level to reach the actual name of the author of the book. Note that I said author not authors. This adapted code presents a problem of its own in that it doesn't take into account the fact that there may well be (and often are) more than one author involved in this book, which would mean that there would be more than one Author node within the Authors parent. Can you think of how to handle this? One solution would be another loop which iterates through the children of the Authors node, printing out each one as it goes. This concept is explained well in the Nested Loops tutorial.

The above code could in fact be written more efficiently to recursively search for children as it goes along if the main objective is just to print out all values stored within the nodes but this method shows you how to make use of some of the other built in properties of the XML Object in Flash.

Just briefly, assuming you want to do something more useful with the information you're processing than just tracing it out, you may need to store the information after you process it in some manner. It would of course be more efficient if you used the information as you processed it, as extensive XML documents can require large arrays or objects to store their values, leading to more pressure on Flash in terms of processing power, but if you can’t use the information as you process it, here's a brief example of how to store it. The follow code has just a few extra lines which create a new object in Flash then move each node’s value into the object, using the node name as the object's attribute name.

function processBook(xmlDoc_xml) {
        // xmlDoc_xml is now a reference to the XML
        // object where our information is stored
        book = new Object();
        book.authors = new Array();
        for (var n = 0; n<xmlDoc_xml.firstChild.childNodes.length; n++) {
                if (xmlDoc_xml.firstChild.childNodes[n].nodeName == "Authors") {
                        trace(xmlDoc_xml.firstChild.childNodes[n].firstChild.firstChild.nodeValue);
                        book.authors.push(xmlDoc_xml.firstChild.childNodes[n].firstChild.firstChild.nodeValue);
             } else {
                        trace(xmlDoc_xml.firstChild.childNodes[n].firstChild.nodeValue);
                        book[xmlDoc_xml.firstChild.childNodes[n].nodeName] = xmlDoc_xml.firstChild.childNodes[n].firstChild.nodeValue;
                }
        }
        trace(book.ImageUrlSmall);
        trace(book.ImageUrlMedium);
        trace(book.ImageUrlLarge);
}

Attributes


We will finish up this tutorial with a short discussion of XML node attributes and how to read them. An attribute is generally a qualifying piece of information stored within the tag of an XML node (not between the tags as with the node's value). An example of an attribute can be found in the first line of the XML document we've been working with all this time:

<Details url="http://www.amazon.com/exec/obidos/redirect?tag=webservices-20%26creative=D2NLY43DS22YAW%26camp=2025%26link_code=xm2%26path=ASIN/059600396X">

Here the Details node contains an extra piece of information, the url attribute (which I'd hazard to guess is the URL you can visit if you wish to buy this product). This extra piece of information occurs within the opening XML tag only, so the closing tag of the Details node is just "</Details>", it needn't (and shouldn't) include the url attribute listed in the opening tag. When you actually interface with Amazon Web Services the XML document which is returned includes 10 Details nodes, one after the other, and the url attribute (which is different for each Details node) can be used to distinguish quickly between one Details node and another, without having to drill down into the nodes to find out any information about them.

Attributes are stored in an Object in Flash, corresponding to the level of the node they are defined in. So if we stick to the same XML document we've been using all along, to access the URL attribute I can use the following code.

trace(xmlDoc_xml.firstChild.attributes.url);

Get it? The first part is the reference to the XML Object. The call to firstChild moves us on to the Details node, and the attributes call connects us to the Object named 'attributes' which Flash generates when processing this XML document.
Want another example? Imagine the Asin child of the Details node was defined as follows:

<Asin fake="this isn't a real node"> 059600396X</Asin>

To access its attribute we would use:

trace(xmlDoc_xml.firstChild.firstChild.attributes.fake);

Because Asin is the firstChild of Details, which is the firstChild of the document, and fake is the name of the attribute which is stored in the Flash-generated 'attributes' Object.

I'll leave it at that for this Beginner / Intermediate level tutorial. Comments and suggestions welcome as always. Please post questions or requests for help on the Forums. Let me also say that I'm not an authority on XML so if I've done something dumb here, let me know about it. Spreading misinformation isn't my goal!

Jesse Stratford is the Co-Master of ActionScript.org and a freelance Flash developer and teacher. He is based in Australia and enjoys all things Flash.

NB: If you have comments or feedback please feel free to email me, but please do not email me Flash questions; the forums are provided for that purpose and you will get a faster answer by posting you question there.

If you have found this tutorial helpful, I hope that you will take 30 seconds to visit The Hunger Site where, with just one click you can make a free donation of food to a starving person in a third-world country. We do not benefit financially from this action; it is purely an act of charity.
This tutorial is protected by International Intellectual Property Rights laws and may not be reproduced or redistributed in full or part, without the prior written consent of the author. Unauthorized reproduction of this tutorial or its contents may result in prosecution. I've worked hard on this tutorial, please don't steal it.