
Beginning ActionScript 2.0 2006
.pdf
Chapter 22
How It Works
In this example you added a simple way to watch your file load and affect the user interface to give the user information about the state of the file load. The meat and potatoes were really in step 7. Here you used both the getBytesTotal and getBytesLoaded methods. By making them a simple fraction you were able to determine the ratio of bytes loaded.
You might have also noticed how you kept the percent loaded a separate function. This is because there are many objects within Flash that have these two properties. A percentage operation seems simple enough, but during application development, compartmentalizing it into one reusable piece of code helps to speed production. Also this separation hopefully got you to think of ways this entire process could be automated within a class object, so that many different XML files could use the same code to be loaded into an application with an indication of bytes loaded.
The other item introduced into the example is the interval. As covered earlier in this book, the setInterval object is a Number method with global static access. Declaring a number a setInterval, you effectively create a loop that iterates over a specified time. With each loop, in this example, you check the state of your percentage loaded and update the GUI. You can see that you also took care to use the clearInterval method to end the loop after the file had fully loaded. It is important, even on these small scales, to be careful about the loops you have running, what may be looping at the same time, and what effect a runaway loop might have on your movie. Always clean up your code when you are through with any script. To help clean up code, you can use the value of the status property, which you traced when the onLoad event fired. The status will indicate at anytime what the current condition of the data load is.
getBytesTotal Isn’t Working!
How does Flash know how big a file is? Flash needs to know the total bytes of a file to determine the getBytesTotal property. The way in which it does this can affect your code. If the file being loaded resides on the local system, Flash queries the file information kept by the operating system. When Flash is accessing a remote file on an HTTP server, Flash must rely on the server to add the total byte size of the file in the header information. A header is simply a short information block that exists in every file. A header tells an application what the file is and how to handle the bytes within it. Most often, a server automatically adds these headers to a file when they are requested. The header that concerns you is the Content-Length header, which contains the total byte size of the file. An application such as a browser or Flash can know the total size of a file before loading it completely by looking for this header information.
This is all fairly automated, and as long as you’re accessing static files, there’s little issue. There is a case, however, when the header information would be incomplete. Often you’re required to load data files that are sent via CGI or a server-side script engine such as PHP. These requests often return raw data directly back into the response byte stream without headers. The header information is the first place to look when you have a getBytesTotal problem when using server-side script responses. The good news is that the popular server-side scripting engines like Perl and PHP offer methods to manually inject header information into the return byte stream.
548

Reading XML
Understanding the Parent-Child Node
Relationship
You access the data within a loaded XML object in Flash by traversing the XML using a DOM (Document Object Model). A DOM is a hierarchy of parent-child relationships. The Flash XML DOM consists of complete XMLNodes, elements, text nodes, attributes, and declarations. The Flash XML DOM is recursive. Every XMLNode is given the same set of properties and methods for navigating up, down, and across the object tree.
Because the method set is recursive and available to every XMLNode within the entire XML object, when you call a navigation method or node property you must specify a starting object. The starting object can exist anywhere in the DOM. Querying navigation methods while navigating the DOM does not modify the XML object in anyway. These methods are simply a convenient way to view your XML document.
The Flash XML DOM is not the same as the JavaScript DOM. Many folks reading this will be familiar with methods such as createAttribute and getElementByID. Flash does not contain these. Although robust, many methods and concepts were left out of the Flash XML DOM. Do not despair, however. Many people have made class additions and libraries for extending the DOM interface. You should go looking for these as well as think about what you might create on your own.
Navigating an Example Node Tree
In the previous Try It Out section you loaded an XML file into a Flash object. However, you didn’t do anything with it. The following exercise is a continuation of that project.
Try It Out |
Load and Extract Values from an XML File |
1.Open xmlLoadSample.fla created in the previous Try It Out. Open the Actions panel, and enter the following into frame 1:
this.createTextField(“XMLProgress”, this.getNextHighestDepth(), 20, 20, 40, 20); this.XMLProgress.border = true;
this.XMLProgress.text = “0%”; getPercentLoaded = function (handle) {
return handle.getBytesLoaded()/handle.getBytesTotal();
};
watchMyXMLLoad = function (handle) { var perc = getPercentLoaded(handle); if (perc>0) {
XMLProgress.text = int(perc*100)+”%”;
}
if (perc == 1) { clearInterval(MyXMLPreloader);
}
};
My_XML = new XML(); My_XML.ignoreWhite = true; My_XML._parent = this;
My_XML.onLoad = function(success:Boolean) {
549

Chapter 22
if (success) { My_XML._parent.init();
} else { trace(“fail”);
}
};
var MyXMLPreloader:Number = setInterval(this, “watchMyXMLLoad”, 10, My_XML); My_XML.load(“myData.xml “);
2.You just added a parent declaration, as well as a call to an init function. Now add the init function just before the My_XML constructor:
init = function () { trace(My_XML.hasChildNodes()); if (My_XML.hasChildNodes()) {
for (var i = 0; i<My_XML.childNodes.length; i++) {
if (My_XML.childNodes[i].nodeName == “channels”) { var channelSet:XMLNode = My_XML.childNodes[i]; var channelObject = this[“channelSet”+i]={};
parseStation(channelObject, channelSet.firstChild,0);
}
}
} else {
trace(“Not a channel list”);
}
delete My_XML;
};
3.Test your code by pressing Ctrl+Enter. Verify that a channels node was found. The list of stations appears in their raw XML format in the output window.
4.Close the SWF and go back to the actions with which you’re working. Now add the following code to create an object and populate it with some station information. Place the code before the init function:
var num:Number = 0;
parseStation = function (channelObject, station, num) {
var stationReference:Object = channelObject[“station”+num]={}; for (var t = 0; t<station.childNodes.length; t++) {
if (station.childNodes[t].nodeName == “Name” && station.childNodes[t].firstChild.nodeType == 3) {
stationReference.stationName = station.childNodes[t].firstChild.nodeValue;
}
if (station.childNodes[t].nodeName == “Desc” &&
station.childNodes[t].firstChild.nodeType == 3) { stationReference.stationDesc =
station.childNodes[t].firstChild.nodeValue;
}
stationReference.ID = station.childNodes[t].parentNode.attributes.identification;
}
if (station.nextSibling != null) { num++
550

Reading XML
parseStation(channelObject,station.nextSibling,num);
}
};
5.Test the code by pressing Ctrl+Enter. In this example code you need to select the show variables option by pressing Ctrl+Alt+v or by selecting Debug List Variables. In the output window you will now see near the top of the list an object called channelSet0. The object has all of your XML data within a similar hierarchy as the XML file. The XML file is deleted, and you can begin to work with the information within your object as if they were any other variable.
How It Works
In this example you use the XML method property set and a few methods to verify and navigate the contents of your XML file. The init function conveniently checks to see whether the XML file is valid. It does this by utilizing the hasChildNodes property to decide whether or not it should proceed. If the function does find child nodes, it goes through them as a list, referring to them with the childNodes property. The childNodes property is an array that references the list of child nodes within a node. The code verifies each node as channels nodes by checking the node name using the nodeName property.
You also check that the node name will have no raw XML, and in fact is actual content data by checking that your nodeValue returns a 3. Had the node contained another element node, the nodeValue would have returned a 1, and you could then make decisions on how to handle such a case.
You can have as many channels nodes as you want for multiple subsets of stations. For each channels node found, the function sends the firstChild within it to the parseStation function. At this point you could double-check the node name of the station to be sure it is a station node, but because you only plan to have stations reside in a channels node, you can skip this check.
The parseStation function is recursive. This means that under the correct conditions the code will call itself within itself, with a new set of parameters. This is effectively like a loop but automates the parsing of each station nicely. Although fast, recursive loops are limited to 256 iterations. If you had more than 256 stations, you’d need to find a different way. However, the recursive example highlights a property called nextSibling. You can see the nextSibling property being fetched in the last line of the parseStation function. This could have easily been previousSibling. Because the init function started the recursion function at the top of your station list, nextSibling works because nextSibling always returns the node below that of the node the nextSibling property is fetched on. If the init function had specified the lastChild rather than the firstChild, the parseStation function would use the previousSibling property, because previousSibling works up the list of nodes rather than down.
The other unique demonstration in the code is the parentNode property access. Although you could have accessed the resulting node in a different way, this shows an example of how you can move up the node tree, rather than use previousSibling, which only moves up the node list. In this case the parentNode is used as a way to target the attribute object of the station itself. You could have easily have called station.attributes.identification to complete the same reference. In this way you can see how malleable the DOM tree toolset is and how the property set of the XML object yields a robust interface for finding information within your XML files.
551

Chapter 22
Using Attributes
The previous examples touched on the use of attributes. Attributes are nothing too complex. Flash treats the attributes within a node as an object appendage. That is, all attributes for a single node are accessed as a named array in the attributes object. Because attributes are an object, you can perform very fast queries to obtain all or some of them. You can use loops or access an attribute directly by name.
Attributes have limitations, however. Attributes cannot contain CDATA tags. Attributes cannot be extended. If you find that an attribute such as color seems simple enough to place within an attribute, perhaps reconsider, because a color may have a secondary property such as gloss or matte. If the color data resides within an attribute, it’s going to be more difficult to extend your XML document to include relational data within the attribute. Migrating attribute data to nodes within an application that is already created can also cause major code reworking. Think carefully about your data and create attributes with values that are as basic and bottom-feeding as possible.
That said, attributes are parsed much, much more quickly than nodes. Using attributes can speed up XML loading on slow platforms such as devices and PDAs. This should be a last-resort effort at speeding up XML loading and parsing.
The ways in which you loop through the DOM with your code or set variables via DOM exploration can often be far more intense than the native parseXML method. Be careful how you loop through your XML. Don’t be tempted to nest for loops within for loops within for loops. Not only is this confusing to code, it can lead to script halts and alerts on the user’s machine.
Using the XML Socket Connection
The XML socket allows Flash to open a persistent line of communication with the server. Using four robust event handlers, Flash can listen for asynchronous data sent from the server without sending explicit requests for the data.
This type of connectivity is useful for Flash clients that must communicate with one another at high speed and present an identical user interface on multiple Web-connected clients. You’ve likely used a socket many times in the form of a chat program or room. Another place where low-latency sockets is used is online gaming.
To use the socket class, you must have a server capable of running a service that allows persistent socket connections. You then must have a server application capable of using the socket and interpreting requests, while sending out well-formed responses and broadcasts. Generally, these types of applications are best built on robust platforms such as Java or Ruby. There are provisions within other languages of course, but the selection of the server technology is important because persistent socket connections heavily tax the server. For example, a socket application with just a few hundred concurrent users may, in fact, need to be farmed out to multiple socket servers using load-balancing techniques.
Creating a stable, consistent, and efficient socket application can be one of the most challenging web applications you can attempt. Approach sockets without humor and do not underestimate the time it will take to develop a full socket application.
552

Reading XML
The XML in the XMLSocket Class
Although the XML socket is best used with XML, and many out-of-the-box socket servers use XML in their responses and broadcasts, XML is not required. You can send ampersand-delimited name/value pairs to be decoded by a LoadVars object. You can send comma-delimited strings to be split manually and used quickly.
So why use XML? Using XML ensures that your application is transparent. By using XML you are allowing for the socket server to be replaced with a new socket server. Maybe you are changing technology from a small PHP socket server to a robust load-balanced Java-based server. Choosing XML means that the client application will need little to no changes because the communications to and from the server are transparent. It doesn’t care who or what sends it information, just that it is in XML format.
Choosing standards can make your initial coding more difficult or lengthy but will make enhancements and modifications to the application much easier in the long run.
Null Bytes
You might have heard the term null byte before. When a transmission is sent over an XML socket, each application needs to understand when a file has finished being sent. Sockets do this by appending a 0 or null byte at the end of the string.
Sometimes the end byte that Flash automatically appends to a socket request is not the end byte the server application is looking for. In these cases, you must manually append it or change the socket application to correctly look for a null byte.
XMLSocket Class Methods and Events
The following table describes the methods of the XMLSocket class:
Method |
Return |
Description |
|
|
|
XMLSocket.close() |
Nothing |
Closes the socket connection by sending a close |
|
|
reponse to the remote socket application and closing |
|
|
the local socket. |
XMLSocket.connect() |
Nothing |
Establishes a socket connection. |
XMLSociet.send() |
Nothing |
Sends an XML object to the server upon a request |
|
|
received as a string object that may, but is not required |
|
|
to be, XML formatted. |
|
|
|
XMLSocket class events are explained in the following table:
553

Chapter 22
|
Event |
|
Type |
Description |
|
|
|
|
|
|
|
|
XMLSocket.onClose |
Function |
Fires when the socket has closed. This event does not |
||
|
|
|
|
require a close message from the server, and it will fire if |
|
|
|
|
|
the socket connection is simply broken. |
|
|
XMLSocket.onConnect |
Function |
Fires when the socket has a received an initial response |
||
|
|
|
|
establishing the socket connection. |
|
|
XMLSocket.onData |
Function |
Fires when anything is received by the server. |
||
|
XMLSocket.onXML |
Function |
Fires when a well-formed XML document has been sent |
||
|
|
|
|
by the server. |
|
|
|
||||
Try It Out |
Create an Initial Socket Connection |
|
This Try It Out assumes you’ve written or have found a socket server such as Moock’s Unity server. It uses AOL’s instant messaging socket login negotiator at login.oscar.aol.com. This is a socket server that then sends an AIM client to a specific socket server for chat relays.
1.Open a new Flash document and save it in your work folder.
2.Click the first frame in the timeline, open the Actions panel, and type the following ActionScript code:
var My_Socket:XMLSocket = new XMLSocket() My_Socket.onConnect = function (success) {
if (success) {
trace (“Connected to remote socket”)
}else {
trace (“Socket failed”);
}
}
My_Socket.connect(“login.oscar.aol.com”,5190);
3.Press Ctrl+Enter to test the code. If oscar is running on AOL at the specified port, and you have an Internet connection, you should see that the socket connection has been established.
How It Works
In this exercise, you defined an onConnect event to fire when the remote server successfully connected to the local socket. If this was a basic XML socket server, you could then begin to send request packets to the server.
At the time of this writing, an excellent free socket server that runs on both Mac and Win from the command line is available at www.oregano-server.org/. It is released under GNU. Because it runs on Mac and Win, it is perfect for testing out the XML Socket object.
Once you have a socket server available for access, you can begin to try simple communications with the server. The next Try It Out is a simplified example that illustrates the basic construction of a simple communication. The socket server you choose to use, or write, will likely use its own request commands and XML formats. You should read the documentation for your server thoroughly and use this example as a rough guide.
554

Reading XML
Try It Out |
Create a Socket Request and Receive an Answer |
This Try It Out assumes you’ve written or have found a socket server such as Moock’s Unity server. It does not refer to any specific socket server, but cites a hypothetical URL that assumes a working response. Again try the server available at www.oregano-server.org/ if you do not have a socket server and you are simply learning the basic events of the XMLSocket class.
1.Open a new Flash Document and save it in your work folder.
2.Click the first frame in the timeline, open the Actions panel, and type the following ActionScript code:
var userID:Number = userInputField.text; var My_Socket:XMLSocket = new XMLSocket(); My_Socket.onXML = function (xmlObject) {
trace(xmlObject.firstChild.attributes.name);
trace(xmlObject.firstChild.attributes.phoneNum);
}
var message:XML = new XML();
var info:XMLNode = message.createElement(“getInfo”);
info.attributes.userID = usernID; message.appendChild(info); My_Socket.onConnect = function (success) {
if (success) { this.send(my_xml);
} else {
trace (“Socket failed”);
}
}
My_Socket.connect(“foo.com”,2222);
3.Test your code by pressing Ctrl+Enter.
How It Works
As long as your server is set up to accept and respond properly to a request formatted as
<getInfo userID=”9999”/>
you should see the trace values of the returned XML file if the response from the server is a well-formed XML document and punctuated the transmission with a zero end byte character. An example of an XML response for this request could be as follows:
<reponse name=”John Smith” phoneNum=”555-5555”/>
In this way you can see that the XMLSocket utilizes XML and XML objects to organize and communicate data efficiently.
555

Chapter 22
sendAndLoad
The sendAndLoad() method works the same in both the LoadVars object and the XML object. In fact, you can mix the two objects by specifying the object to send data from and the object to load data to. Each end of this transaction does not have to be the same type of object. One object initiates the transaction by attaching a string version of itself to the URL via POST or GET. The URL specified is the first of three parameters required by sendAndLoad. The server response to the URL call is then directed back to the object specified as the second parameter. The last parameter of the sendAndLoad method is the POST or GET declaration. These are specified as String literals.
You can, in fact, use the same object to send and load the data.
One of the more popular trends on the Web these days is API exposure. This means that companies like Google, Yahoo, PayPal, Flickr, and more are offering their services at an application level so you can include their data seamlessly within your own application. Obtain a developer key from any of these APIs and use sendAndLoad to send RESTful calls.
For the purposes of showing how one object initiates the transaction, while another object waits for the transaction, you can just use a web page URL.
Try It Out |
Using sendAndLoad |
1.Open a new Flash document and save it in your work folder.
2.Click the first frame in the timeline, open the Actions panel, and type the following ActionScript code:
resultObject:LoadVars = new LoadVars(); resultObject.onData = function(str) {
trace(str);
};
My_Data:LoadVars = new LoadVars(); My_Data.hl = “en”;
My_Data.q = “Flash”;
My_Data.sendAndLoad(“http://www.google.com/search”, resultObject, “GET”);
3.Test the code by pressing Ctrl+Enter. The output window shows you the file that has just been loaded into the resultObject. You can change the q variable declaration to change the results from the remote server.
4.This is interesting, but just do one more thing to make use of the data that is loading into the resultObject. Add the following function before the resultObject LoadVars constructor:
findAHrefLinks = function (page) { var linkList:Object = {};
var ahrefs:Array = page.split(“<a”); ahrefs.shift();
for (var i = 0; i<ahrefs.length; i++) { trace(ahrefs[i]);
ahrefs[i] = ahrefs[i].split(“a>”)[0];
}
for (var i = 0; i<ahrefs.length; i++) {
var thisLink:Object = linkList[“link”+i]={}; var linkText:String = ahrefs[i].split(“>”)[1];
556

Reading XML
linkText = linkText.substring(0, linkText.lastIndexOf(“<”)); thisLink.linkText = linkText;
var attributes = ahrefs[i].split(“>”)[0].split(‘“‘).join(“”).split(“‘“).join(“”);
thisLink.url = attributes.split(“href=”)[1]; if (thisLink.url.indexOf(“ “)>1) {
thisLink.url = thisLink.url.substring(0, thisLink.url.indexOf(“ “));
}
}
return linkList;
};
5.Add a function call to the existing resultObject.onData event handler. The onData event handler should now look like this:
resultObject.onData = function(str) { linkList = findAHrefLinks(str);
trace(“done”);
};
6.Test the code by pressing Ctrl+Enter. Wait for the word “done” to appear within the output window. At that point the response has loaded fully into the resultObject.
7.With the SWF open, view the variables out function created by pressing Ctrl+Alt+v or by selecting Debug List Variables. You should see a very long list of very usable HTTP links.
How It Works
As you can see, the actual activity of using sendAndLoad is very much like the load method you’ve already used several times in this chapter. It’s almost as if you’re calling the load method on the target object (resultObject), while making a request and posting variables from the initial object (My_Data). In this way sendAndLoad does not provide Flash with any new or groundbreaking functionality, but instead packages up what could be a complex activity into a single, encapsulated code block.
The example also utilized a specific parsing function to show how varying interception objects can be used to encapsulate specific parsing functionality while keeping the data fetch, the sendAndLoad method identical regardless of final data usage.
This example shows you the power of adding variables to a Flash object and sending those variables to a server to manipulate the data the server sends back, as well as the different ways you can use the many methods provided by the LoadVars and XML objects in conjunction to write simple code that accomplishes useful transactions.
Using HTTP GET and POST
If you’ve followed the previous examples in this chapter you’ve seen how to request and send data to a remote server. Two terms that keep popping up are POST and GET. Many readers are familiar with these terms already and have used them in HTML forms.
557