ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
XML 101
http://www.actionscript.org/resources/articles/9/1/XML-101/Page1.html
Jesse Stratford
Jesse lives and works in Melbourne Australia. He is the Cofounder of http://ActionScript.org. A Flash enthusiast, teacher, author, freelancer and speaker Jesse's main focus nowadays is managing http://ActionScript.org, but he enjoys participating actively in community and the wider Flash scene when he has time. 
By Jesse Stratford
Published on September 9, 2005
 
Tutorial details:
Written by: Jesse Stratford [email:jessestratford@actionscript.org]
Time: Approximately 1 hour
Difficulty Level: Intermediate
Requirements: Flash 5 or higher. Text editor. Some code may work only in MX.
Topics Covered: XML from the ground up. What is it, when to use it, how to use it and more!
Assumed knowledge: Paths, Variables, arrays, Scripted Loops, basic Object Oriented Principles.</TEST>

Page 1 of 3
Tutorial details:
Written by: Jesse Stratford [email:jessestratford@actionscript.org]
Time: Approximately 1 hour
Difficulty Level: Intermediate
Requirements: Flash 5 or higher. Text editor. Some code may work only in MX.
Topics Covered: XML from the ground up. What is it, when to use it, how to use it and more!
Assumed knowledge: Paths, Variables, arrays, Scripted Loops, basic Object Oriented Principles.

Grab the source files to all the examples used in this tutorial right here.

First off let me say that XML, being a data structure is a broad topic. This tutorial will teach you how to load, format and use XML documents in Flash to a certain degree. Being a tutorial for intermediate level users I'll work on the assumption that you have a good understanding of the Flash environment, and a fairly good understanding of ActionScript, but I'll try to make it as painless as possible! For this reason this tutorial has turned out pretty long, so if you already know a bit about XML you might want to use the subheadings to skip the stuff you know and get down to the nitty-gritty.

What is XML?
"Assume no prior knowledge", I say to myself. If you've been living under a rock and have never heard of XML, then let me be the first to welcome you back from your solitude!
For our purposes XML (which stands for eXtensible Markup Language) is a way of structuring, arranging and representing data. One of the benefits of XML is that it allows for customizable and neat representation of data which can be easily parsed (interpreted by a computer) while at the same time being clearly readable to a human.
Before I continue, when reading the next section keep in mind that XML is easy-peasy, so don't let the concepts or tech terms scare you. Keep reading and you'll get it.
XML uses 'tags' (similar to HTML tags) which may or may not include refining elements called 'attributes'. (Since most people know some HTML this is a good example to use but don't get carried away with the similarities: HTML is primarily a markup language, while XML – in relation to Flash at least – is primarily a data structure.) Consider the HTML bold tag – to create some bold HTML text we use:

[code]<b>This is some bold text</b>[/code]

The simple 'tags' at the beginning and end of the text string tell the browser to format that string in a particular manner. XML is similar to the extent that it too uses such tags in its structure, however in XML, instead of being a way of describing the visual representation of data, tags are used to group related pieces of information into 'nodes'. In fact the above snippet is a properly formatted XML node. This will get easier with an example, (below), but let me just pound you with one or two more tech terms first. Nodes are hierarchical, that is, they can contain other nodes within them ('child nodes'), and their children can contain children, just like MovieClips in Flash (see my Paths tutorial). XML is also associative in that two nodes which are children of the same parent node are recognized as being siblings.
XML, unlike HTML, is extremely touchy when it comes to formatting. An XML document must strictly conform to various rules in order to be processable: this is a good way to enforce clean coding. The rules are as follows:
All nodes (except self-contained nodes which we may discuss later) must have a beginning and ending tag, which are alphanumerically identical. That means tags are case-sensitive, for instance this is valid:

[code]<authorName>Jesse Stratford</ authorName>
[/code]

But this is not (note the lack of capitalization in the closing tag):

[code]<authorName>Jesse Stratford</ authorname>
[/code]

Also note that the space after the slash and before the node name in the closing tag is optional.

Nodes which contain nodes must also be closed in the correct order. Consider a box which contains another box. You open the outer box, open the inner box then place something (a cake . . . mmm cake) inside the inner box. Now if you try to close the outer box without closing the inner box, the lid won't go down because the inner box is still open. The same applies for XML, so this is valid:

[code]<outerBox>
        <innerBox>Cake</ innerBox>
</ outerBox>
[/code]

But this is not

[code]<outerBox>
        <innerBox>Cake</ outerBox>
</ innerBox>
[/code]

While this might seem obvious, such rules are often broken in HTML and it's important to get them out of your system now rather than at 1am one night with a deadline looming when you're running around the house, screaming and trying to figure out why your XML isn't working. Don't say I didn't warn you!

Why and when to use XML?
Honestly, I don't know. I think it's because Microsoft are pushing it and small-business people know their competitors are using it, so it must be good. Seriously though, XML is a very useful method of representing data and it's very much the way to go with Flash, but it has its problems like everything. One of the biggest dangers is massively verbose XML tags. The ability to create your own tags in XML means that XML documents can be self-documenting to a certain extent, but some developers may be drawn into abusing this feature and get into using extremely long XML tag names, for instance:

[code]<book>
        <whatUsersWhoHaveReadThisBookThinkAboutIt>...</ whatUsersWhoHaveReadThisBookThinkAboutIt>
</book>
[/code]

Don't laugh; I've seen it happen! The nature of this structure is fine, but the child node would of course be much more easily represented by a 'reviews' node, or something much shorter. The longer your tags are, the more bytes your clients are going to have to download, and that equates directly to them spending more time waiting for your site to load, which we all know is a bad thing.

For this same reason, there are many instances where XML is simply not necessary. For instance, if you have a backend script which hands out the password for the day to various users, you might as well just send it back as a text string, instead of an XML document with one node. The tags would just be useless bytes and the new LoadVars Object contains most of the useful methods that are applicable to such a system.

For many other applications, XML is the way to go. A great example can be found at Amazon.com who recently opened up the back-end databases (through Web Services 2) to the general public. Using the correct protocols you can send a key word query to Amazon and it will return information on all relevant books in XML format. The document contains a list of books, each of which contains child nodes telling you everything from the author of the book to the average rating from Amazon.com reviewers. It's great and a very suitable application for XML and Flash.

Loading XML into Flash
Well that was a long but necessary preamble; now let's get into actually using XML in Flash. First we will need an XML document to work with, so let's start small. Below I've made up a small XML document (download example1) which includes just one node:

[code]<author>Jesse Stratford</ author>
[/code]

I save this in a text file (using a compatible text editor such as Notepad or similar), as author.xml. Next, I fire up Flash MX and create a new document 'author.fla', which I save in the same directory as my new XML file.
Within Flash we need to create a new XML object into which we are going to load our external XML file.

[as]tuteInfo_xml = new XML();
[/as]

Note that I added '_xml' to the end of my XML Object's name so that the ActionScript panel will automatically recognize this Object as being and XML object and provide me with a dropdown of the appropriate methods whenever I refer to it.
With our new object prepared we can load in our XML:

[as]tuteInfo_xml.load('author.xml');
[/as]

When working with XML, Flash provides methods which are automatically invoked when certain evens occur, such as when a document we try to load finishes loading. This means we don't need to constantly check if our data has finished loading, we simply define the actions we wish to take place in a function which is invoked by the load event handler, as follows:

[as]tuteInfo_xml.onLoad = function (success) {
        if (success) {
                trace('Author.xml loaded. Contents are: '+this.toString());
        }
};
[/as]

This code creates a new function which is invoked when the XML document is loaded. The function is automatically passed the success argument, a Boolean value which indicates whether or not the document loaded successfully (this is a built in function of the onLoad event handler in Flash). If the load was successful, I trace a small message for debugging purposes, which outputs the following:
Author.xml loaded. Contents are: <author>Jesse Stratford</author>

Note that it is common practice to insert the onLoad function definition above the load command but it must go after the creation of the new XML object, thus it is most commonly put between the object declaration and the load command.

Before we continue, I should point out that in the above example, the fact that the XML document is just one line with no trailing blank space is important. Most XML documents you will work with will be formatted using new-line characters, tabs, etc. in order to make them more presentable and human-readable, in such cases it is important to tell Flash that your XML document will contain unimportant whitespace, otherwise Flash will not handle it. This is done by setting the ignoreWhite property of your XML object to true, for example:

[as]tuteInfo_xml.ignoreWhite = true;
[/as]

So the entire code snippet for our simple example above is:

[as]tuteInfo_xml = new XML();
tuteInfo_xml.ignoreWhite = true;
tuteInfo_xml.onLoad = function(success) {
        if (success) {
                trace('Author.xml loaded. Contents are: '+this.toString());
        }
};
tuteInfo_xml.load('author.xml');
[/as]

But loading is just the beginning, turn the page to continue!

Page 2 of 3
Data from XML within Flash
The above example was just a trivial intro to loading XML into Flash, now let's look at actually using some information we've loaded. First we'll need an XML document with some more useful information. I had a great idea for a project to work through with you all via this tutorial but now I've forgotten it, so I'm going to go back to the Amazon example I gave above. Here is a snippet from the result of a query on the Amazon Web Services 2 XML server, looking for books with the word "flash" in the title. (Note that the first line has been cut short to fit the window of this tutorial.)

[code]<Details url="http://www.amazon.com/exec/obidos/redirect?tag=webservices-20%26creative=...">
         <Asin>059600396X</Asin>
         <ProductName>ActionScript for Flash MX: The Definitive Guide, 2nd Edition</ProductName>
         <Catalog>Book</Catalog>
         <Authors>
                  <Author>Colin Moock</Author>
         </Authors>
         <ReleaseDate>19 December, 2002</ReleaseDate>
         <Manufacturer>O'Reilly & Associates</Manufacturer>
         <ImageUrlSmall>http://images.amazon.com/images/P/059600396X.01.THUMBZZZ.jpg</ImageUrlSmall>
         <ImageUrlMedium>http://images.amazon.com/images/P/059600396X.01.MZZZZZZZ.jpg</ImageUrlMedium>
         <ImageUrlLarge>http://images.amazon.com/images/P/059600396X.01.LZZZZZZZ.jpg</ImageUrlLarge>
         <ListPrice>$54.95</ListPrice>
         <OurPrice>$38.47</OurPrice>
</Details>[/code]

You'll notice that this document is a lot more complex than any of our previous examples, but don't let that scare you off. Take a moment to read through it and you will see that it is in fact a very nice representation of all the information relevant to a particular book. I've used indentation to indicate the hierarchy of the nodes. Notice that the Details node is the major node, and it contains all the other nodes, such as Asin, ProductName, etc. as its children. Also note that the Authors node, which is a child of the Details node, has its own child node. This is because there can be more than one author who contributed to a book, so had this book had multiple authors, they would each be listed here in a separate Author node, as a child of the Authors node. Thus each Author node is a 'grandchild' of the Details node.

You may wonder why I'm using terms such as child and grandchild. This is the common method for referring to the structure of XML. Moreover, it is the exact terminology Flash uses when manipulating XML documents, so I'm trying to acclimatize you to it.

Imagine that these nodes were laid out in the format of a family tree.


Figure 1: Tree representation of sample XML document

The above diagram clearly shows that each Author node is a child of the Authors node and a grandchild of the Details node, which is the 'root' (top) node of the tree in this example.

Because XML is hierarchical, in order to access information stored deep within an XML document, such as the name of the first contributing author to a book in our example, we must pass first through the root node, then through the appropriate child, to the grandchild and extract the information. This process is often called 'drilling-down' or 'parsing', and can be quite involved with complicated data structures.

Let's take a look at some code. You may wish to download the source file to this example (example2). I've set up an XML document with the exact Amazon XML from above copied into it and named it book.xml. I've created a new FLA named 'drill_down.fla' and into the first frame I've put this code:

[as]// Create new XML Object and set ignoreWhite true
book_xml = new XML();
book_xml.ignoreWhite = true;
// Setup load handler which just invokes another function
// which will do the parsing of our XML
book_xml.onLoad = function(sucess) {
        if (sucess) {
                processBook(book_xml);
        }
};
// Load up the XML file into Flash
book_xml.load('book.xml');
// This is the function that will be called when
// our XML document is loaded succesfully
function processBook(xmlDoc_xml) {
        // xmlDoc_xml is now a reference to the XML
        // object where our information is stored
        for (a in xmlDoc_xml.firstChild.childNodes) {
                trace(a + ' ' + xmlDoc_xml.firstChild.childNodes[a]);
        }
}
[/as]

This is nothing new, it's just like our earlier example of how to load up XML except that the onLoad event handler now invokes another function which we can edit to perform operations on the XML object. At present that function just outputs the contents of the XML node to the Debugging window so we can check everything is running well.

All manipulations of the XML object will now be made within the processBook function, which accepts a reference to an XML object. We're passing in this reference instead of hard coding 'book_xml' into the function so that the function can be reused for another XML object if we wish to load in another XML file and call it something different. Looking back at our simple diagram above we see that the Details node has many children.

Say we are creating an application which needs to display information about a book drawn from an XML file. The first thing we'd want to display is probably the Title of the book, which in this case is given by the ProductName node of our XML ('Product' instead of 'Book' because Amazon sell everything from books to clothes now).


Figure 2: The virtual pointer within Flash

When referencing nodes within an XML document, we have a virtual pointer which keeps track of where we are in the tree structure. To begin with the pointer is pointing at the XML document (not the first node), as shown in panel 1 of Figure 2 above.

In Figure 2 above we can see that the Details node is the first node of the XML document, or the 'first child' of the document. We can move our virtual pointer to the Details node using the following code. This is also illustrated in panel 2 of Figure 2.

[as]trace(xmlDoc_xml.firstChild);
[/as]

The 'first child' of the Details node is the Asin node, so what do you think this code will do? (Here's a hint, it's shown in panel 3 of Figure 2!)

[as]trace(xmlDoc_xml.firstChild.firstChild);
[/as]

If you expected it to trace the Asin node, then you'd be correct. The important thing to note here is that it traces the tags as well as the node's value, which illustrates that the theoretical pointer which keeps track of where we are in an XML document is pointing to the Asin node, not the text within it (panel 3,Figure 2). To access the value of the node (the text within the tags) we need to add an additional call to firstChild, as follows (see panel 4, Figure 2):

[as]trace(xmlDoc_xml.firstChild.firstChild.firstChild);
[/as]

While this outputs the value we're after, we are supposed to use the nodeValue property of the XML object to get at it, so the proper way to get the value of the Asin node is using this code.

[as]trace(xmlDoc_xml.firstChild.firstChild.firstChild.nodeValue);
[/as]

We use nodeValue for an accurate representation of the string value of a node. For example, in strings which include special characters such as ampersands (&) using nodeValue results in the returned string including the ampersand character (rather than the encoded string '&' which is used to represent an ampersand). Thanks to Jeff Schuster for being the only person around to figure that out and explain it to me.

Easy huh? So what if you wanted to access the ProductName node which is the second child of the Details node? This can be done using a similar sort of approach, by reaching the Asin node and then asking for the nextSibling, which moves our theoretical pointer to the next node at the same level in our tree diagram above.
We first use two calls to firstChild to go to the Details node (Figure 3, below, panel 1), then the Asin node (panel 2), then one call to nextSibling which moves us to the ProductName node (panel 3), then one call to firstChild to get inside the ProductName node (panel 4) and finally a call to nodeValue.


Figure 3: Referencing using nextSibling

The code looks like this:

[as]trace(xmlDoc_xml.firstChild.firstChild.nextSibling.firstChild.nodeValue);
[/as]

Low and behold this traces "ActionScript for Flash MX: The Definitive Guide, 2nd Edition" just as it should.

We'll discuss another method over the page...


Page 3 of 3
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:

[as]trace(xmlDoc_xml.firstChild.childNodes);
[/as]

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:

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

(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:

[as]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);
        }
}
[/as]

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:

[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[/code]

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.

[as]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);
                }
        }
}
[/as]

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.

[as]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);
}
[/as]

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

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.

[as]trace(xmlDoc_xml.firstChild.attributes.url);
[/as]

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:
[code]<Asin fake="this isn't a real node"> 059600396X</Asin>[/code]

To access its attribute we would use:

[as]trace(xmlDoc_xml.firstChild.firstChild.attributes.fake);
[/as]

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 [email:jessestratford@actionscript.org] 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.