For simplicity, we’ll create element nodes, text nodes, and attributes in one example, and build an XML instance as if we were writ-ing it over time.. Line 2, therefore, creates an eleme
Trang 1Writing XML Writing XML
You’ve already seen how to write XML when creating an instance of the XML
class, but you may also have to write to the instance over time For example,
you may need to add to XML based on user input or as data changes The
majority of techniques for adding content to XML mirror the process of
read-ing the data, except this time you’re assignread-ing information to a node rather
than retrieving it
In this section, you’ll re-create the data used throughout the “Reading XML”
section of this chapter For simplicity, we’ll create element nodes, text nodes,
and attributes in one example, and build an XML instance as if we were
writ-ing it over time In a real scenario you would not assemble XML in multiple
steps in the same script However, assuming the premise that we’re writing
the object in stages will allow us to demonstrate the most common XML
writing methods
Because we’re intentionally writing the XML out of order to demonstrate
methods like insertChildBefore() that will alter the order of nodes, we’ll
show the progress of the XML as we go The code that follows can be found
in the write_xml.fla source file For clarity, only the last trace() statement is
used in the source file, to show the final XML content, but you can
uncom-ment any trace along the way to see interim results
To begin, we must have an XML instance and a root node, so line 1 creates both
Note that, when adding element nodes without content, you must specify a
self-closing tag so the XML remains well formed As soon as you add content
to a self-closing node, ActionScript will replace it with balanced open and
closing tags For example, we’re initially adding <book /> as the root node
but, after adding the next element node, the root node will become <book>
</book>
Line 2 demonstrates the simplest technique for creating both an element
node and a text node When assigning a value to a node, if the node does not
already exist, it will be created If you assign another element node to the new
node, a nested element will be created If you assign a String to the new node,
a text node will be created Line 2, therefore, creates an element node called
<title> and a text node that contains “Learning ActionScript 3.0.” The result
appears in lines 5 through 7
1 var las3Data:XML = <book />
2 las3Data.title = "Learning ActionScript 3.0" ;
4 /*
5 <book>
6 <title>Learning ActionScript 3.0</title>
7 </book>
8 */
We started with the <title> node intentionally to demonstrate the next
method The prependChild() method will add a node to the beginning of
Trang 2Writing XML
the XML object specified In this case, line 9 creates the <publisher> ele-ment node and positions it before the <title> node so it’s the first node of
las3Data Line 10 demonstrates the creation of an attribute node adding the
name attribute to the publisher element node just created The cumulative result appears in lines 13 through 16
9 las3Data.prependChild(<publisher />);
10 las3Data.publisher.@name = "O'Reilly" ;
12 /*
13 <book>
14 <publisher name="O'Reilly"/>
15 <title>Learning ActionScript 3.0</title>
16 </book>
17 */
The opposite of prependChild(), appendChild() adds a node to the end of
an XML object Therefore, line 18 adds the <authors> node after the <title>
node Up to this point, we’ve only added objects to the XML instance, which
is equivalent to the root node However, you can also use appendChild() to add a child to another node Line 19 adds the first <author> node as a child
of <authors> Lines 20 and 21 again demonstrate the simultaneous creation
of element and text nodes, adding <firstname> and <lastname> nodes and assign a String to each The cumulative result appears in lines 24 through 33
18 las3Data.appendChild(<authors />);
19 las3Data.authors.appendChild(<author />);
20 las3Data.authors.author.firstname = "Zevan" ;
21 las3Data.authors.author.lastname = "Rosser" ;
23 /*
24 <book>
25 <publisher name="O'Reilly"/>
26 <title>Learning ActionScript 3.0</title>
27 <authors>
28 <author>
29 <firstname>Zevan</firstname>
30 <lastname>Rosser</lastname>
31 </author>
32 </authors>
33 </book>
34 */
Line 35 demonstrates the insertChildAfter() method, the first of a pair that allows you to provide an existing node as a reference point for where the new node should be added The first argument of the method is the existing node, and the second argument is the node you want to create In this case, the
<subject> node is being inserted after the <title> node Line 36 adds a text node to <subject>, and the cumulative result is seen in lines 39 through 49
35 las3Data.insertChildAfter(las3Data.title, <subject />);
36 las3Data.subject = "ActionScript" ;
38 /*
39 <book>
40 <publisher name="O'Reilly"/>
N OT E
It’s not possible, using this method, to
add more than one node with the same
name to an XMLList For example,
we have to add another author to the
<authors> node, but if we repeat lines
19 through 21, we’ll receive this error:
Error #1089: Assignment to lists
with more than one item is
not supported.
Instead, we must copy the first author
node and change its contents We’ll show
you how to do that in just a moment.
Trang 3Deleting XML
41 <title>Learning ActionScript 3.0</title>
42 <subject>ActionScript</subject>
43 <authors>
44 <author>
45 <firstname>Zevan</firstname>
46 <lastname>Rosser</lastname>
47 </author>
48 </authors>
49 </book>
50 */
The next block of code demonstrates insertChildBefore(), the other method
that uses an existing node as a reference However, it also demonstrates how
to copy a node and change its values Line 51 uses the copy() method to
copy the previously created <author> node, and lines 52 and 53 change the
text nodes in <firstname> and <lastname> After the edits, the new node is
inserted before the existing <author> node to match the order of the original
data we’re trying to recreate Using the copy() method is a real timesaver
when tags with many children must be reproduced over and over again with
few changes
The final result is shown in lines 57 through 71, and matches the original
las3Data object to achieve our goal.
52 firstAuthor[0].firstname = "Rich" ;
53 firstAuthor[0].lastname = "Shupe" ;
54 las3Data.authors.insertChildBefore(las3Data.authors.author,
firstAuthor);
56 /*
57 <book>
58 <publisher name="O'Reilly"/>
59 <title>Learning ActionScript 3.0</title>
60 <subject>ActionScript</subject>
61 <authors>
62 <author>
63 <firstname>Rich</firstname>
64 <lastname>Shupe</lastname>
65 </author>
66 <author>
67 <firstname>Zevan</firstname>
68 <lastname>Rosser</lastname>
69 </author>
70 </authors>
71 </book>
72 */
Deleting XML
We’ve placed deleting XML elements in a separate section because you may
delete elements when reading or writing XML When parsing XML, you’re
likely to ignore small sections of unwanted content, but deleting large
seg-ments of unneeded material can sometimes simplify your task When writing
Trang 4Loading External XML Documents
XML, you may find the need to delete an element added in error or that is
no longer needed
To delete something, simply use the delete operator on the desired item Here are a few examples showing how to delete attributes, element nodes, and text nodes from a simplified version of our ongoing las3Data example This
code can be seen in the delete_xml.fla source file Line 7 deletes an attribute,
line 8 deletes an element node and all its children (which deletes the text node therein), and line 9 deletes only a text node, leaving the parent element node intact The final result is seen in lines 12 through 15
1 var las3Data:XML = <book>
2 <publisher name="O'Reilly" />
3 <title>Learning ActionScript 3.0</title>
4 <subject>ActionScript</subject>
5 </book>;
6
11 /*
12 <book>
13 <publisher/>
14 <title/>
15 </book>
16 */
Note that the delete operator won’t work with text(), elements(), attri-butes(), children(), or descendents() to delete all of the nodes returned
by these methods Rather, you must specify which item within the XMLList
returned that you want to delete This can be counterintuitive if you just want
to delete a single text node, as in line 9
Loading External XML Documents
Often when you work with XML, you’re using data that’s being retrieved from
an external source Even when you need only a local data source, however, it’s almost always easier to work with an external XML document because it’s easier to edit the XML as you project evolves
We’ll use the LoadURL class developed in Chapter 13 to load data for our XML navigation system at the end of this chapter, but right now we’d like to stress the basic syntax of loading XML The code in this section can be found in the load_xml.fla source file.
Before we get started with the syntax, let’s create a very simple XML docu-ment called toLoad.xml It contains the mandatory root node, one element
node called <stuff>, and one text node with the string, “XML loaded!”
<main>
<stuff>XML loaded!</stuff>
</main>
Trang 5Loading External XML Documents
With that in hand, let’s start our script by creating a text field to display our
results (lines 1 through 5) This is a handy alternative to tracing loaded
con-tent because it’s easier to test in a browser Next, create a URLRequest instance
for the XML file (line 7), and a URLLoader instance to load the document (line
9) Then create two event listeners to react to a possible I/O error (lines 10 and
11), and the completion of the loading process (lines 12 and 13) The onIOError()
function in lines 16 through 18 places any error text (if an I/O error occurs)
into a text field, and we’ll discuss the onComplete() function after the first
code block Next, the XML document is loaded in line 14
2 txtFld.width = 500;
3 txtFld.height = 350;
4 txtFld.multiline = txtFld.wordWrap = true;
6
7 var req:URLRequest = new URLRequest( "toLoad.xml" );
8
10 urlLoader.addEventListener(IOErrorEvent.IO_ERROR,
11 onIOError, false, 0, true);
12 urlLoader.addEventListener(Event.COMPLETE,
13 onComplete, false, 0, true);
14 urlLoader.load(req);
15
17 txtFld.text = "XML load error.\n" + evt.text;
18 }
The onComplete() function (lines 19 through 28) is triggered when the XML
file has completely loaded The function first removes the listeners because
the XML document was both found and loaded It then uses a try catch
block to create an XML instance from the loaded data, and places the <stuff>
node into a text field If unsuccessful, an error message is placed into the
same field, often allowing you to locate something that may cause the XML
to be malformed
20 urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
21 urlLoader.removeEventListener(Event.COMPLETE, onComplete);
23 var loadedXML:XML = new XML(evt.target.data);
24 txtFld.text = loadedXML.stuff;
25 } catch (err:Error) {
26 txtFld.text = "XML parse error:\n" + err.message;
27 }
28 }
Before we demonstrate populating menus with XML in our navigation
sys-tem project, let’s look at sending data to a server and loading the result
Trang 6Sending to and Loading from a Server
Sending to and Loading from a Server
Another frequent use of XML data is for transmission to and from a server XML is often the data format used by news feeds (RSS, ATOM), Web services, and database output While some of these uses require only loading informa-tion, other tasks, including application logins, game high score submission, and so on, also require sending data In this chapter, we’ll cover the basic send and load method of communicating with a server
Send and Load
The send-and-load approach is a form of traditional server communication,
be it a browser retrieving an HTML file or a user submitting data via a form Essentially, the client sends data to the server and waits for a response The server processes the incoming information, formulates a reply, and sends information back to the client
For simplicity, this example sends a short XML object to a PHP script, which then writes data to a text file on the server and sends back a short reply Writing a text file on the server may not be the most common use of XML submissions, but it’s basic enough to illustrate in this context This example uses two files: send_load_xml.fla and save_xml.php Let’s look at the FLA file
first
The client source
This example is nearly identical to the load_xml.fla source file discussed in
the preceding “Loading External XML Documents” section All we need to
do is substitute the following eight lines of code for line 7 of that example These lines both create XML to send, and customize the URLRequest instance
to send data, as well as load it
Lines 7 through 9 create the XML object to send to the server Like ActionScript, our PHP script does not require the XML declaration tag in line 7 but, for maximum flexibility, it’s not a bad idea to prepend this to any XML you send
to a server You may find that it’s required in a future configuration of your project and, since it makes no difference in ActionScript, there’s no good rea-son not to include it
Lines 11 through 14 create a URLRequest instance for submitting the data Note that you’ll need to put the correct path to your server in line 11 As discussed
in Chapter 13, line 12 assigns the outgoing XML to the data property of the request, and lines 13 and 14 specify “text/xml” as the contentType, and POST
as the method, of the request object, respectively
7 var str: String = "<?xml version='1.0' encoding='utf-8'?>" ;
8 str += "<value>Sent from ActionScript</value>" ;
9 var xmlToSend: XML = new XML (str);
10
Trang 7An XML-Based Navigation System
11 var req: URLRequest = new URLRequest ( "save_xml.php" );
12 req data = xmlToSend;
13 req contentType = "text/xml" ;
14 req method = URLRequestMethod.POST ;
The server source
The next code block is the server-side PHP script This is the server
destina-tion of your simple XML data and, as specified in line 11 of the Acdestina-tionScript
code, should be called save_xml.php The script first checks to be sure POST
data has been received (line 3), and then populates the $data variable with
that data (line 4) In lines 6 through 8, it creates and opens for writing a
file called data.txt, writes the data to the file, and then closes the open file
instance Lastly, it checks to make sure the file was written successfully and
sends a simple XML object back to ActionScript
If successful, you’ll see the message “File saved.” in the text field If not, you’ll
see “Server unable to create file.” There may be a permissions issue on the
server preventing write access to the directory in which the PHP script has
been placed, for example, or another error preventing file creation
1 <?php
2
3 if (isset($GLOBALS["HTTP_RAW_POST_DATA"])){
4 $data = $GLOBALS["HTTP_RAW_POST_DATA"];
5
6 $file = fopen("data.txt", "wb");
7 fwrite($file, $data);
8 fclose($file);
9
10 if (!$file) {
11 echo("<stuff>Server unable to create file.</stuff>");
12 } else {
13 echo("<stuff>File saved.</stuff>");
14 }
15 }
16
17 ?>
An XML-Based Navigation System
If you haven’t done so already, you may want to read the last exercise in
Chapter 6, before continuing with this project Chapter 6 discusses
object-oriented programming and uses a simplified version of this exercise without
XML, populating the menus with an array By comparing this exercise with
the more basic version in Chapter 6, you can see how incorporating XML
changes the system The result of this exercise will be a five-button
naviga-tion bar with submenus, the labels and partial funcnaviga-tionality of which are
populated through XML
Pu sh You rself!
Trang 8An XML-Based Navigation System
The Directory Structure and Source Files
Before looking at the ActionScript for this exercise, we need to explain a couple of quick things about the project’s directory structure and source files We’ve tried to use several of the key topics that we’ve learned throughout the book to approximate an average use of an XML-driven menu system Highlights include: object-oriented design, embedded fonts, text formatting, TweenLite animations, loading external assets, drawing with vectors, filter effects, and, of course, parsing XML
The project directory, nav_bar_xml, includes the primary FLA file, LAS3Lab.fla,
and document class, LAS3Main.as The exercise also uses classes from the
learningactionscript3 package (in the com directory) that we’ve been building
throughout the book:
com.learningactionscript3.loading.LoadURL
Created in Chapter 13, this class can load text from a URL, and includes error checking, making it convenient for loading XML
com.learningactionscript3.ui.NavigationBarXML
This class is the backbone of the system and is a new version of the
NavigationBar class used in Chapter 6 It replaces that chapter’s array data with XML, adds submenus, and puts the whole system to work by adding
a loader that the menu items can target for loading SWFs and images
import com.learningactionscript3.ui.MenuButtonMain
This simple class essentially provides a text field and text formatting for the MenuButtonMain movie clip in the LAS3Main.fla library.
import com.learningactionscript3.ui.MenuButtonSub
This class dynamically creates submenu buttons that will be clicked to load visual content at runtime
In addition, the exercise uses classes that are developed by others and are not part of any default ActionScript 3.0 distribution, including a few classes from TweenLite (the ActionScript tweening platform discussed in Chapter 7), and
a modified version of Adobe’s SafeLoader class (the class designed to load SWFs that contain TLF instances without error, discussed in Chapter 13) The last parts of the exercise directory are the XML data and content for load-ing The XML file that populates the menus is called nav.xml and is found
inside a directory called data, and the content ready for loading, and specified
in paths in the XML data, is found inside the projects directory
N OT E
The navigation menu system in this
chapter is an enhancement of the
ver-sion in Chapter 6 We elected, however,
not to replace the older classes to allow
you to compare the classes and see the
evolution of the code Instead, we placed
the new and revised classes in the com.
learningactionscript3.ui package.
Trang 9An XML-Based Navigation System
The Library of the FLA
The main FLA file requires three symbols in its library:
ArialBold
ArialRegular
These are embedded font symbols containing bold and plain versions of
the Arial font with linkage class names of ArialBold and ArialRegular,
respectively Although embedded fonts in a SWF ensure that viewers
don’t need to have the fonts installed in their computer, this is not true of
editing an FLA If you prefer, you can substitute your own fonts and then
either use the same linkage class names or update the code accordingly
MenuButtonMain
This is a movie clip that looks like a tab-shaped button The class of the
same name provides the text field and text formatting needed to display
the tab’s text label
The XML and Classes
Now we’ll being looking at the code behind the project We’ll start by
show-ing you an excerpt of the XML data file, and then discuss each of the classes
that you’ll write We’ll also explain the usage of related, third-party classes
XML
You can look at the XML document any time, but the following excerpt is
representative of the data:
<nav>
<menus>
<button label="MOTION">
<project label="flocking" path="projects/motion/worm.swf">
Flocking with Zeno's paradox
</project>
<project label="point at" path="projects/motion/point.swf">
Pointing at the mouse position
</project>
</button>
</menus>
</nav>
The root node, <nav>, has a child node, <menus>, which contains the data for
all menus Each menu is delineated by a <button> node, which corresponds
to the main menu button This node has a label attribute, which holds the
text used for the main menu button text label
Within each <button> node are multiple child nodes called <project> (two
are shown in the excerpt for brevity) Collectively, these make up the submenu
for each menu Each <project> node corresponds with one button in the
submenu, and has an attribute called label This is used to populate the text
Trang 10An XML-Based Navigation System
label of the submenu button It also has a path attribute, used to load the cor-responding content, and a text node, which we’ll use in Chapter 15 to display
a brief blurb about the loaded asset
LAS3Main (document class)
The document class is pretty straightforward It loads the XML data, creates
a SafeLoader for loading content and a mask for masking the content to an area below the menus, and initializes the menus
Lines 1 through 10 declare the package and import required classes, including
SafeLoader, and two custom classes, CustomURLLoader and NavigationBarXML Line 12 declares the class, including extending MovieClip so it can easily be used as a document class Finally, lines 14 through 16 create three private properties for the CustomURLLoder, XML, and SafeLoader instances, respectively
2
3 import flash.display.Graphics;
4 import flash.display.MovieClip;
5 import flash.events.Event;
6 import flash.filters.DropShadowFilter;
7 import flash.net.URLRequest;
8 import fl.display.SafeLoader;
9 import com.learningactionscript3.loading.CustomURLLoader;
10 import com.learningactionscript3.ui.NavigationBarXML;
11
12 public class LAS3Main extends MovieClip {
13
14 private var _menuLdr:CustomURLLoader;
15 private var _xml:XML;
16 private var _loader:SafeLoader;
The class constructor occupies lines 18 through 22 and creates an instance of the CustomURLLoader class to load the external data Discussed in Chapter 13, this class does all the loading work for us and dispatches an Event.COMPLETE
event when the loading is finished Line 20 adds an event listener to trap this event and call onLoadXML()
Once the XML is loaded, the onLoadXML() method uses a try catch block
to attempt to parse the XML It retrieves the data from the data property of the CustomURLLoader instance and tries to instantiate an XML object using that data (line 26) If successful, it calls the initLoader() and initMenus() meth-ods (lines 27 and 28, respectively) If the data can’t be parsed as XML, it traces
an error (lines 30 and 31)
17 //constructor and xml load
18 public function LAS3Main() {
19 _menuLdr = new LoadURL( "data/nav.xml" );
20 _menuLdr.addEventListener(Event.COMPLETE, onLoadXML,
21 false, 0, true);
22 }
23
24 private function onLoadXML(evt:Event):void {
25 try {