XML is a standard protocol for transferring, storing, and reading data for several purposes, including application initialization parameters, data sets, and remote procedure calls. Flex applications work with XML by using Flash Player’s native support.
Flash Player 9 supports two mechanisms for working with XML: a legacy
XMLDocument
class
and the new XML
class
that implements the ECMAScript for XML (E4X) standard. All XML examples in this book use E4X unless otherwise
noted.
There are two ways to create XML
objects in ActionScript: using XML
literals or with the XML
constructor.
XML literals are useful when you want to define the XML data directly in
the code and you know the exact XML data you want to use. The following
example defines an XML literal and assigns it to a variable:
var xml:XML = <books> <book> <title>Programming Flex 3</title> <authors> <author first="Chafic" last="Kazoun" /> <author first="Joey" last="Lott" /> </authors> </book> <book> <title>ActionScript 3.0 Cookbook</title> <authors> <author first="Joey" last="Lott" /> <author first="Keith" last="Peters" /> <author first="Darron" last="Schall" /> </authors> </book> </books>;
We’ll assume that this is the XML
object referenced by the remainder of
the XML examples in this chapter.
If you aren’t able to define the XML data directly in
ActionScript, you can load the data as a string and pass it to the
XML
constructor. In the following example, loadedXMLData
is a variable containing XML
data loaded from an external source at runtime:
var xml:XML = new XML(loadedXMLData);
When you use the XML
constructor, any string data you pass to the constructor is parsed into
the XML
object as XML nodes.
By default, Flash Player attempts to interpret all string
data as XML. That means it interprets whitespace (carriage returns,
tabs, etc.) as XML nodes. That can cause unexpected results. Therefore,
if the XML string data you pass to an XML
constructor contains extra whitespace (for
formatting purposes) that you don’t want interpreted as XML nodes, you
should first set the static ignoreWhitespace
property to true
for the XML
class, as shown here:
XML.ignoreWhitespace = true; var xml:XML = new XML(loadedXMLData);
Once you have an XML
object,
you can read from the object. There are two basic ways in which you can
read the data: by traversing the Document Object Model (DOM) or by
accessing the data using E4X syntax. The two techniques are not
exclusive of one another: you can use them in conjunction with one
another.
In each case that outputs an XML node, the following examples
use the toXMLString()
method to
format the XML node as a string.
When viewing the XML data in light of the DOM, treat it simply as a hierarchical structure of data
consisting of parent and child nodes. When looking at the DOM, focus
primarily on the structure rather than the content. You can retrieve all
the content from an XML
object by
treating it in this manner, but you access the data by structure by
stepping into the XML one node at a time. The XML
class defines a host of methods for
retrieving DOM structure information, including the following:
children()
The children()
method
returns an XMLList
object with
all the child nodes of an XML
object. The XMLList
class
implements a very similar interface to that of XML, and all of the
methods discussed in this section apply to both XML
and XMLList
. An XMLList
object is essentially an array
of XML
or XMLList
objects. You can even retrieve
elements from an XMLList
object
using array access notation. For example, the following code
retrieves the book nodes as an XMLList
. It then displays the first
element from that list.
var bookNodes:XMLList = xml.children(); trace(bookNodes[0].toXMLString());
length()
The length()
method
returns the number of elements. For XML
objects, this always returns
1
. For XMLList
objects, it may return more than
1
. The following example
illustrates the children()
and
length()
methods used in
conjunction. This example displays the titles of each of the
books:
var bookNodes:XMLList = xml.children(); for(var i:uint = 0; i < bookNodes.length(); i++) { trace(bookNodes[i].children()[0].toXMLString()); }
parent()
You can retrieve the parent of an XML
or XMLList
object using the parent()
method. For example, the
following displays the first book node by accessing the title node
first, and then it retrieves the parent of that node:
trace(xml.children()[0].children()[0].parent().toXMLString());
attributes()
The attributes()
method
returns an XMLList
object with
all the data from the attributes contained within an XML
object. You can call the name()
method for each attribute in the
XMLList
to retrieve the name of
the attribute as a string. You can then use that value as a
parameter, which you can pass to the attribute()
method of the XML
object to retrieve the value of the
attribute. The following example illustrates how this
works:
var author0:XML = xml.children()[0].children()[1].children()[0]; var attributes:XMLList = author0.attributes(); var attributeName:String; for(var i:uint = 0; i < attributes.length(); i++) { attributeName = attributes[i].name(); trace(attributeName + " " + author0.attribute(attributeName)); }
As you can see, traversing the XML DOM is effective but laborious. Often, it’s far more effective to use E4X syntax, particularly when you already know the structure. E4X syntax allows you to access child nodes by name as properties of parent nodes. For example, the following accesses the first book node:
trace(xml.book[0]);
You can chain together this simple E4X syntax as in the following example, which retrieves the first author node of the first book node:
trace(xml.book[0].authors.author[0].toXMLString());
E4X also allows you to easily access attributes using the @
symbol. The following uses this syntax to
retrieve the value of the first attribute of the author node:
trace(xml.book[0].authors.author[0].@first);
You can also use E4X filters. Filters are enclosed in parentheses
within which you specify conditions. The following example retrieves all
the author nodes in which the last attribute is Kazoun
:
var authors:XMLList = xml.book.authors.author.(@last == "Kazoun"); for(var i:uint = 0; i < authors.length(); i++) { trace(authors[i].parent().parent().toXMLString()); }
You can also write to and edit XML
objects using ActionScript. There are
three things you can do in this category:
Modify existing data.
Add new data.
Remove existing data.
You can modify existing data using the same E4X syntax you use to
read the data on the left side of an assignment statement. For example,
the following changes the title
of
the first book
:
xml.book[0].title = "Programming Flex 3: Edition 1";
The following example changes the name of the second author
of the first
book:
xml.book[0].authors.author[1].@first = "Joseph";
If you want to add new data, you can use the appendChild()
, prependChild()
, insertChildBefore()
, and
insertChildAfter()
methods. Each
method inserts a new XML node into an XML
or XMLList
structure. The appendChild()
and prependChild()
methods each accept one
parameter and insert the node at the end and at the beginning of the
structure, respectively. The following adds a new publisher node to each
book:
xml.book[0].appendChild(<publisher>O'Reilly</publisher>); xml.book[1].appendChild(<publisher>O'Reilly</publisher>);
You can use the insertChildBefore()
and insertChildAfter()
methods to add a new node
before or after an existing node. The methods each require two
parameters: the new node to add, and a reference to the existing node.
The following adds a new publication date node (publicationDate
) between the authors and
publisher nodes:
xml.book[0].insertChildAfter(xml.book[0].authors, <publicationDate>2006</ publicationDate>); xml.book[1].insertChildAfter(xml.book[1].authors, <publicationDate>2006</ publicationDate>);
You can remove elements using the delete
operator. The following example first adds a new middle attribute to
an author node and then removes it:
xml.book[0].authors.author[1] = <author first="Joey" middle="Persnippity" last="Lott" />; trace(xml.book[0].authors); delete xml.book[0].authors.author[1].@middle; trace(xml.book[0].authors);