RETRIEVING DATA FROM AN XML FILE

  
XML support was first added to Flash 5, it is not supported on Flash 4.  This tutorial explains how a Flash movie can retrieve data from an external XML file using Flash MX or later version.  

BACKGROUND

Why would there be a need to read from a file?  Suppose you have a movie that displays a "news of the day."  You could put the content of the news on the swf file, but if you do so, every time the news changes, you'll need to edit the Flash file.  That's very impractical.  So the benefits are: 1) To save time (avoid editing and recompiling of the Flash file); and 2) to separate your application from the data (encapsulation, implementation hiding).  

You can use regular text file to pass external data - see here.  Yet another way to pass external date is to embed the data using the query string or using FlashVars.  

Why use XML? The benefit of using XML is that you can format the data more elegantly; and also, since XML has been widely used nowadays, the exact same XML file could potentially be used for other purpose.  Since XML is very good for representing hierarchical form of data, so you avoid the messy format required by using the other file format.  

The main drawback of using XML is the added complication in the ActionScript coding; and also there's a bug some  Flash 5 players that might not read XML file the way intended (see more on this below).

REQUIREMENTS

To understand this tutorial, it's recommended that you know:

  • How to access variables in Flash via a textbox.
  • Some general Flash Action Scripting knowledge and syntax.
  • Some basic XML knowledge (hierarchical structure, formatting).

This tutorial will be using Flash MX, but is also applicable on Flash MX 2004.  Flash 5 can also be used, but with caution - see note below.  

Note: This tutorial requires Flash 6/MX plug-in/player to be installed to run properly.  Although XML is supported from Flash 5; there's a problem on some older Flash 5 player that causes a movie not to be able to read some XML files correctly.  This problem occurred in Flash player version 5.0.41 and was fixed on version 5.0.42.  If the example above does not run on your machine, you should download the latest flash player from Macromedia.  If you need to support Flash 5 players, then see this link for some workarounds.

SAMPLE XML FILE

The XML file to be used in this tutorial is called "news.xml"  It can be downloaded here: news.xml.  The structure of the XML file is shown below.  Note that we're not using a DTD because Flash will ignore it anyway.

Note that the root element of the XML file is <news>.  A <news> element contains a <header>, a <content>, and an <info> element.  An <info> element itself has a "more_info" attribute, and contains a <comment> and an <author> element.  

Note about XML editing
If you use one of the special character below as a value of an element, you should use the name entities:

Symbol Name Entities
>
&gt;
" &quot;
' &apos;
& &amp;
< &lt;
  
For example, to replace the <header> with "Vacation is Good & Healthy" then do it like this:
<header>Vacation is Good &amp; Healthy</header>
Not like this: 
<header>Vacation is Good & Healthy</header>

CREATING THE SKELETON FLASH MOVIE

Let's start with a sample Flash movie.  This movie will display a "news of the day" movie using data from the above XML file.  Here's what frame 1 looks like:

The movie has 4 textboxes:

  • the one which shows "header"
  • the one which shows "Loading data..."
  • the one which shows "author" 
  • the text "My News Page" is a static textbox (we'll not be doing much with this particular textbox)

Each textbox is a DynamicText, and is associated with a variable name (specified in Var: in the property dialog, like below).

The "header" textbox is associated with Var: header.  This box will hold the news <header>.  Make sure that this button is off so that user can't select (highlight) the text.  It will look weird if you allow user to select the text.

The "Loading data" textbox is associated with Var: content.  This box will hold the news <content>.  

The "author" textbox is associated with Var: author.  This box will hold the name of the news <author>.

We'll ignore the other XML elements such as <date> and  <comment> for now.

LOADING THE XML FILE IN FLASH

Below is the code that loads the XML object

var xmlData=new XML();
xmlData.ignoreWhite=true;
xmlData.load("news.xml");

The first line creates an XML object.  The next line tells Flash to ignore white spaces encountered in between XML elements.  Generally, you'll always want to set this to true, or Flash won't read the XML file correctly.  The last line is the code that actually loads the XML file.   

It is worth noting that when you load external file like this, you should not make the assumption that the file is loaded immediately.  Because Flash does not know how large the file is, it usually runs this kind of process in the background while the movie continues to run.  However, Flash is thoughtful enough to notify us when the file is loaded by what is termed: event handlers.  In the XML case, the event handler is named onLoad (ie: when the file is loaded, Flash will call onLoad).  We will implement onLoad code soon.

Note: for this tutorial, the XML file must be located in the same domain as the swf file.  If you need to access an XML file from a different domain, then you need to enable access across different domain by writing a <cross-domain-policy> in the XML file.  An example is as follows:
<?xml version="1.0"?>
<cross-domain-policy>
  <allow-access-from domain="www.friendofpermadi.com"/>
</cross-domain-policy>

If you need to do the cross-domain-policy, then you can find more info on the Macromedia site.

PARSING THE XML FILE IN FLASH

Now that we know how to load the file, it won't be much of a use without knowing what to do with it.  But before we process the file, we need to know that the file is loaded.  We do that by overriding the onLoad event handler with our own function which will process the XML file. Our handler function is called processXMLData.  So the code becomes:

function processXMLData(success)
{
  if (success)
  {
  }
  else
  {
    content="Today's news is not found";
  }
}

var xmlData=new XML();
xmlData.ignoreWhite=true;
xmlData.onLoad=processXMLData;
xmlData.load("news.xml");
stop();

I also tell Flash to stop the movie because I don't want to continue until processXMLData is called.  (This doesn't mean that you should always stop the movie after loading.  It really depends on your movie.  In my simple example, I do want to stop the movie because the movie can't do anything else until the file is loaded).  

Note that we must put processXMLData before the onLoad=processXMLData portion just to be safe.  We will write the actual code for processXMLData a bit later; currently, it does nothing.  The parameter success is a boolean value that indicates whether the file is successfully loaded or not.  It will be false if the file is not found.  

New, let's see how to access the XML data.  When processXMLData is called, a reference to the XML object is passed.  This reference can be accessed with the keyword "this."  Let's see what it looks like:


You can get this kind of output by running the debugger and putting a breakpoint in processXMLData.

According to the diagram above, "this" has 1 child nodes, which is named "news."  This corresponds to the <news> element in the XML file.   We already know from the XML file that the <news> node should have 3 child nodes (<header>, <content>, and <info>).  Let's extend the tree view and see.  

Sure enough, there they are.   The order is always the same as in the XML file.  So, child[0] is for <header>, childNodes[1] is for <content>, and childNodes[2] is for <info>.  

But why are all the nodeValues null?  This is the way the XML object in Flash works: the nodeValue for an element is stored as a child node. So, the node value for the <header> will be the child node of the "header" node.  We can get the value of the header like this:
newsNode=this.childNodes[0];	   // get news node first
headerNode=newsNode.childNodes[0]; // get header node
header=headerNode.childNode[0].nodeValue   // get value

or alternatively:
header=this.childNodes[0].childNodes[0].childNodes[0].nodeValue;	

Let's see that:

Sure enough.  There it is.  Similarly, the nodeValue of the <content> element will be at: this.childNodes[0].childNodes[1].childNodes[0].nodeValue 

You can also refer chilNodes[0] as firstChild.  So we could have done this:
header=this.firstChild.firstChild.firstChild.nodeValue;	
content=this.firstChild.childNodes[1].firstChild.nodeValue;	

If you've never used XML in Flash before, all this may seem confusing.  I suggest writing some code and try to access some of the elements.  The debugger is very helpful here because you can see the tree view like above.  

Once you get used to the concept, you should be able to reference any element in the XML file without going through this step by step process.  For now, we have enough information to use to code the Flash movie.
function processXMLData(success)
{
  if (success)
  {
    header=this.childNodes[0].childNodes[0].childNodes[0].nodeValue;	
    content=this.firstChild.childNodes[1].firstChild.nodeValue;
  }
  else
  {
    content="Today's news is not found";
  }
}

var xmlData=new XML();
xmlData.ignoreWhite=true;
xmlData.onLoad=processXMLData;
xmlData.load("news.xml");
stop();

The way I'm accessing the nodes on that piece of code doesn't seem very consistent, but that's ok, I'm doing things this way to illustrate a purpose.  

Run the movie, it should be like this:

Cool.  Since we have named the textboxes with the name "header" and "content," they automatically show the value we've just assigned.  So now we only need to add the code to print the <author> node value.

The <author> node is one level deeper than <title> and it is nested below <info> node, so the long code to access the node is:
newsNode=this.firstChild;
infoNode=newsNode.childNodes[2];
authorNode=firstChild.childNodes[1];
author=authorNode.firstChild.nodeValue;	

So let's write that code, and while at it, let's rewrite the way we access the the nodes as well to make the code a bit cleaner:
function processXMLData(success)
{
  if (success)
  {
    var newsNode=this.firstChild;
    var headerNode=newsNode.childNodes[0];
    var contentNode=newsNode.childNodes[1];
    var infoNode=newsNode.childNodes[2];
    var authorNode=infoNode.childNodes[1];
		
    header=headerNode.firstChild.nodeValue;	
    content=contentNode.firstChild.nodeValue;	
    author=authorNode.firstChild.nodeValue;  
  }
  else
  {
    content="Today's news is not found";
  }
}

var xmlData=new XML();
xmlData.ignoreWhite=true;
xmlData.onLoad=processXMLData;
xmlData.load("news.xml");
stop();

Gosh, that code is still quite messy.  Our XML file is quite simple, but what if someone forgot to put the nodes in the right order?  What if someone puts <header> after <content>?  Let's make the code cleaner and be able to handle more nodes.  Also, it will be a nice XML practice.  

Let's write a function to return a node.
function findNode(node, nodeName)
{
  if (node.nodeName==nodeName)
    return node;
  for (var i=0; node.childNodes && i<node.childNodes.length; i++)
  {
    var foundNode=findNode(node.childNodes[i], nodeName);
    if (foundNode!=null)
     return foundNode;
  }
  return null;
}
function getValue(node)
{
  if (node && node.firstChild)
    return node.firstChild.nodeValue;
  return "";
}

The findNode function check if the passed node has the specified nodeName.  If not, the code then loops through the children of the node and check again (call the same function).  Eventually, the named node will either be found or not.  If not, then null will be returned.  (Note: This function would not work correctly if we have multiple nodes with the same name on the XML file.  For that, you'll need to specify an index of which node to return - but this is as far as I'll go for this tutorial.)

The getValue function simply returns the value of a node.  It's a shorthand for typing "firstChild.nodeValue".   That minimizes  the mess that we get every time we just want to get a value of a node.

So let's incorporate these changes:
function processXMLData(success)
{
  if (success)
  {
    var rootNode=this.firstChild;

    var headerNode=findNode(rootNode, "header");
    header=getValue(headerNode);
		
    var contentNode=findNode(rootNode, "content");
    content=getValue(contentNode);
		
    var authorNode=findNode(rootNode, "author");
    author=getValue(authorNode);
  }
  else
  { 
    content="Today's news is not found";
  }
}

function findNode(node, nodeName)
{
  if (node.nodeName==nodeName)
    return node;
  for (var i=0; node.childNodes && i<node.childNodes.length; i++)
  {
    var foundNode=findNode(node.childNodes[i], nodeName);
    if (foundNode!=null)
     return foundNode;
  }
  return null;
}
function getValue(node)
{
  if (node && node.firstChild)
    return node.firstChild.nodeValue;
  return "";
}
var xmlData=new XML();
xmlData.ignoreWhite=true;
xmlData.onLoad=processXMLData;
xmlData.load("news.xml");
stop();

Before we go, let's try to use the "more_info" attribute in the <info> node and print the value.  Add a textbox below "author" and set Var: moreInfo.

You can get the attribute of a node in Flash using 
node.attributes.attributeName
, where attributeName is "more_info" in our example.
function processXMLData(success)
{
  if (success)
  {
    var rootNode=this.firstChild;

    var headerNode=findNode(rootNode, "header");
    header=getValue(headerNode);
		
    var contentNode=findNode(rootNode, "content");
    content=getValue(contentNode);
		
    var authorNode=findNode(rootNode, "author");
    author=getValue(authorNode);
    var infoNode=findNode(rootNode, "info");
    if (infoNode)
    {
      moreInfo=infoNode.attributes.more_info;
    }
  }
  else
  { 
    content="Today's news is not found";
  }
}

// ...
// the rest of the code is unchanged and is not shown here

 

You can download the files here:
FLA file
XMLfile (news.xml)

 Terms of Use

<<
MORE TUTORIALS>>

10/2003
(C) F. Permadi

permadi@permadi.com