A lot of the XML parsing information on the internet related to Flash deals with looping over the childNodes array to extract data from an XML file. While this approach works, its lacking in two areas: speed and readability. I'm going to show you something that isn't new, but rather, seemingly under-utilized.
First, XML parsing is the act of extracting data from an XML document and creating an internal representation of that data. Typically, we'll want to load in a XML file and populate an array of objects that corresponds to the data that we can easily use in our Flash movie.
The reason behind parsing the XML document into an object or an array of objects is multi-part. We can save memory space as the XML object in Flash is a little bulky, and we can speed up the data access when trying to use the data loaded from the XML file. Additionally, its a little more convenient to say something like "playlist_array[1].artist" rather than having to find that information in the XML document.
For starters, let's take a look at an example XML file that might be used in a Flash based MP3 player.....
Here is my file, playlist.xml:
<?xml version="1.0"?> <playlist> <track> <artist><![CDATA[Some Band #1]]></artist> <name><![CDATA[Some band's song]]></name> <location><![CDATA[some_band_1.mp3]]></location> </track> <track> <artist><![CDATA[Some Band #2]]></artist> <name><![CDATA[Some band #2's song]]></name> <location><![CDATA[some_band_2.mp3]]></location> </track> </playlist>
In the XML file I'm declaring a playlist with 2 tracks. Each track contains an artist name, the song name, and the location of the mp3 file that we can load in dynamically. Here's the code that is typically used in tutorials for XML parsing:
playlist_arr = new Array();
playlist_xml = new XML();
playlist_xml.ignoreWhite = true;
playlist_xml.onLoad = function(success) {
if (success) {
var startTime = getTimer();
var tracks_xml = playlist_xml.firstChild;
for (var i = 0; i < tracks_xml.childNodes.length; i++) {
var trackData = new Object();
for (var j = 0; j < tracks_xml.childNodes[i].childNodes.length; j++) {
trackData[tracks_xml.childNodes[i].childNodes[j].nodeName] = tracks_xml.childNodes[i].childNodes[j].firstChild.nodeValue;
}
playlist_arr.push(trackData);
}
trace("Total parse time: " + (getTimer()-startTime));
} else {
trace("Error loading playlist.");
}
// clean up after ourselves
delete playlist_xml;
}
playlist_xml.load("playlist.xml");
What the above code does is parse the XML file and build an array of objects. It's a little bulky and probably hard to understand if you've never dealt with XML data before. After the parsing is complete, to access the location of the mp3 file of the first track I would use "playlist_arr[0].location" and it would return the proper location. Pretty sweet that it at least works, but we can do better...
While this is all well and good, on my computer it takes 5 milliseconds to complete the parse. That's not too bad, but remember that's only to parse the information for 2 tracks.
Here's a better way of doing the exact same thing without relying on the childNodes array:
playlist_arr = new Array();
playlist_xml = new XML();
playlist_xml.ignoreWhite = true;
playlist_xml.onLoad = function(success) {
if (success) {
var startTime = getTimer();
var track_xml = playlist_xml.firstChild.firstChild;
while (track_xml != null) {
// add the track data to our playlist!
playlist_arr.push(getTrackData(track_xml));
track_xml = track_xml.nextSibling;
}
trace("Total parse time: " + (getTimer()-startTime));
} else {
trace("Error loading playlist.");
}
delete playlist_xml;
}
function getTrackData(track_xml) {
var trackData = new Object();
var data_xml = new XML();
data_xml = track_xml.firstChild;
while (data_xml != null) {
trackData[data_xml.nodeName] = data_xml.firstChild.nodeValue;
data_xml = data_xml.nextSibling;
}
return trackData;
}
playlist_xml.load("playlist.xml");
Same results, but a little bit faster, and a little bit easier to read. It took only 2 milliseconds on my computer to parse the track information for those 2 tracks into the playlist array.
While 5 milliseconds and 2 milliseconds isn't that much of a difference... if I bump the playlist up to 20 tracks the first approach takes 113 milliseconds to parse while the second approach takes only 20. Quite a difference now, don't you think?
I'm letting the code speak for itself in this example. The main thing to get out of it is what's in the xml onLoad function. Notice that I made things even more readable in the second approach by creating the getTrackData function. It takes in a track xml node and returns an object representative of that track.
Instead of looping over every element in the childNodes array, I'm using two XML properties in Flash -- firstChild and nextSibling. Before we start looping, we kick off the whole thing by assigning the firstChild to an XML variable (track_xml in the example). Then, our loop is easy: while there are siblings, extract the information. At the end of the loop, when we're done getting the information, we update the XML variable to be the nextSibling. The loop ends when nextSibling returns null, meaning there is no more information to process.
Now you can see a different way of parsing XML objects. Rather than relying on childNodes, take advantage of nextSibling to increase the speed and readability of your XML parsing. Many of you are already doing this, but I wanted to highlight an XML parsing technique that not everyone knows about.

11 Comments
Darron, this looks very promising. Can you apply this change to the XFTree component? It would certainly help alot I think. I am loading in file directories that contain alot of nesting. I would love to shave some load time off.
Posted by: Scott Blanchard | November 25, 2003 6:32 PM
I played for a while with a alternative solution to XML parsing on a XML data file "playlist.xml" extended to 108 records.
Timings I had received for the total time spent on XML parsing:
"ChildNodes" array case - 63 ms
"nextSibling" array case - 56 ms
While there is a 10-15% gain of loading time, the advantange of the second case is not so evident.
Test files were compiled by Macromedia Flash 2004 Pro.
Posted by: JabbyPanda | December 10, 2003 8:23 AM
sir, i your example was great and i have don that,but actually i wanted to put the information contained in nodes i.e the both under tag in a dyanamic text box which will be genearated dynamically i suppose.
like if i have 20 s then retrieve information for that is the artist, name ,location for each of the 20 track and put in seperate text boxes(dyanamic text boxes) and then aligned then acoording the gui of the form.
i think i would have to run a loop for genarating text boxes so the information which is recieved from the child nodes is displayed.
i can send u the fla file and sample xml which i have done. i have retrieved values for the products in a variable maybe if u have look at it then u can get a beeter idea what i want.
please sir do help me ,
regards prikshit
Posted by: prikshit | December 12, 2003 7:11 AM
While your method works well, i found that the XML file I loaded took 13ms.
By doing changing the loop I had better results like this:
------------------------------------------------
playlist_xml.onLoad = function(success) {
if (success) {
var startTime = getTimer();
var track_xml = playlist_xml.firstChild.firstChild;
// mini0n's mod
this.createEmptyMovieClip("xmlLoader",12);
xmlLoader.onEnterFrame = function()
{
if (track_xml != null)
{
playlist_arr.push(getTrackData(track_xml));
track_xml = track_xml.nextSibling;
// delete the onEnterframe NO (endless) LOOPS!
delete xmlLoader.onEnterFrame;
}
}
/***********************
while (track_xml != null) {
// add the track data to our playlist!
playlist_arr.push(getTrackData(track_xml));
track_xml = track_xml.nextSibling;
}
****************************/
trace("Loaded: " + playlist_xml.getBytesLoaded() + " Bytes Total: " + playlist_xml.getBytesTotal());
trace("Total parse time: " + (getTimer()-startTime));
} else {
trace("Error loading playlist.");
}
delete playlist_xml;
}
Posted by: Mini0n | April 5, 2004 4:38 PM
Would you be willing to help me out with a problem I have with an xml menu? It should not take an expert like you longer than say about 15 minutes via Instant Messaging. If you are up for that, feel free to contact me via e-mail. Awesome! Thanks!
Posted by: jjmancini | May 17, 2004 10:22 PM
played for a while with a alternative solution to XML parsing on a XML data file "playlist.xml" extended to 108 records.
Timings I had received for the total time spent on XML parsing:
"ChildNodes" array case - 63 ms
"nextSibling" array case - 56 ms
While there is a 10-15% gain of loading time, the advantange of the second case is not so evident.
Test files were compiled by Macromedia Flash 2004 Pro.
Posted by: Stephen | September 13, 2004 9:18 PM
i did not get it i will like to put songs that are in my computer to my url but i do not have the code
Posted by: john | May 30, 2005 8:41 PM
For myself, after cutting and pasting your data and code, playlist_arr contains no objects. playlist_arr never seems to
in scope even though it is the first var declared. I've read
much about this XML.onLoad scoping problem but I've never
seen it actually work.
I ran your examples on Flash2004MX Pro (7.2)
Posted by: Todd | September 8, 2005 7:25 AM
I would like to add the function of deleting current play list and loading another playlist for mp3 player- xml. via ( artist name) button on stage flash mx 2004.
Do I need to add more action script or what!!??
Please help if you can.
David
Posted by: David | September 13, 2005 3:19 AM
And... what's about XPATH?
That's a marvellous free solution and lets me to use some kind of queries to get the info
http://www.xfactorstudio.com/Actionscript/AS2/XPath/Default.aspx
Posted by: Julian | November 2, 2005 11:04 AM
Just a note, this weblog entry was originally written in 2003, making it over 3 years old at this point, and not very relevant in today's technology landscape.
With ActionScript 3, obviously the preferred approach is to just use E4X notation on an XML instance.
Posted by: darron | December 27, 2006 12:49 PM