The Flash-XML FAQ aims to provide a definitive source for common questions about Flash and its interaction with XML (and XML datasources). If you think of a questions that should be answered in this FAQ, or have an answer or a better answer to a question in this FAQ please email Luke Tupper flash@tupps.com
Copyright Luke Tupper 2001-2002
The latest version of this FAQ is kept at: http://www.tupps.com/flash/faq/xml.html
The latest version of this FAQ is 2.0.4
A change log is kept at: http://www.tupps.com/flash/faq/xml-faq-cl.html
Alternative Formats:
This FAQ is now available in PDF or XML. See the admin pages for more details and copies of the stylesheets.
FAQ Mirrors:
http://www.huikuri.com/flash/xml/
http://www.flashdeveloper.nl/g_flash_xml_faq.html
http://home.earthlink.net/~ymcvicar/tutorials/faqs/flashxml/
FAQ Translations
http://faces.bascule.co.jp/flashxmlfaq.php
Email Luke flash@tupps.com if you are willing to be included in the official mirrors list.
1 |
Before You Begin |
XML is the extensible markup language. XML uses tags very similar to HTML, instead of describing the structure of the page the tags, XML uses the tags to describe the data. This allows a structured data format, that can be extended without breaking previous implementations. A good starting point for learning XML is:
http://www.w3schools.com/xml/xml_whatis.asp
XML is becoming a standard way for people to export and import data from different systems. Its simplified mark up language make it easy for different systems to read data in, without knowing the exact structure of the data. If the XML data description has been properly created it is possible to add additional information to your XML data files without affecting system that are already using the information.
If you load XML data into flash, an object model will be created that will allow you to easily manipulate and extract the data. The same object model is available to create XML data, and export it to an extenal system.
For retrieving information external to the flash file loadvariables might work when loading simple or small amounts of information. Once you have to retreive information where the amount of information changes, or is being created by an external source, you should use XML
2 |
Connectivity |
When run from a web server Flash has a security implementation which only allows you to send and retreive information to the server that delivered the flash file. If you try to read information from another system (such as moreove.com) you will find that the XML files will work fine on your local machine, but will fail when you move them onto your web server.
In nearly all browsers this is the server which the HTML file contains your flash file. However at least IE4.5 for the Mac, will only allow you to send and retrieve information to the server that contains the flash file. For this reason it is recommended that you place you flash file and HTML file on the same server.
Your ability to use external XML sources will depend on the amount of access you have to your web server. Before using these routines make sure you have permission to access this external information.
The following routines will extract the information from an external web server and retransmit it from your own machine, avoiding the security problems outlined in 2a. If you know how to perform these routines using a different server based language please submit them to: flash@tupps.com
<% url="http://p.moreover.com/cgi-local/page?c=Web%20developer%20news&o=xml" Response.ContentType="text/xml" Response.Redirect url %>
<cflocation url="http://p.moreover.com/cgi-local/page?c=Web%20developer%20news&o=xml"/>
<?php // get a web page into a string echo join ('', file ('http://p.moreover.com/cgi-local/page?c=Developer%20news&o=xml')); ?>
3 |
Manipulating XML |
When flash loads XML data by default any carriage returns and linefeeds are displayed as empty XML nodes. The exact reason that Macromedia did this is unclear however, when writing code to manipulate XML information it is important to make sure you always check the node XML object to make sure it is not a blank node. Do this by checking the node name to make sure you have correct node, this will also ensure that if extra data is added to the XML your movie will still work.
With versions of the flash player after version 5.0.41 there is the command xml.removeWhitespace however unless you are working in a controlled environment where you can rensure that the flash player is the latest this will be of no use.
First thing the whitespace command only works for people with the latest versions of flash, so if they have an earlier version then it will not work. A better option is to get the whitespace stripped out using this code:
http://www.moock.org/asdg/codedepot/
Go to the very last script on the page and you should find a fla file with whitespace stripping code. This will work with any flash player.
If your XML is extremely large it may take flash a long time to process your XML. If this takes longer than 15 seconds, the flash player will throw an error. You cannot change this error, or its timeout. Your options will be to reduce the size of your XML file or load and parse it in several chunks. It has been found that attributes are a lot quicker to access and parse than child nodes.
4 |
Back End Integration |
Any backend scripting language should be able to create XML files. As long as you can output properly formatted XML from your scripting language flash will be able to load the information. Flash does not require that the file have a .xml extension.
In fact web pages that conform to the XHTML spec can be read and parsed by flash.
The first thing to do is make sure the XML is being outputted correctly. The easiest way to do this is to use a web browser to read in the information. Internet Explorer is a good test as it will render the XML in a tree structure as well as color the nodes and attributes.
You should not have to have a php script that parses the data back together if you set the content type of the xml to "text/xml". This was a bug in version 5,0,30,0 (the initial released version with the dev studio). See link: http://www.macromedia.com/support/flash/ts/documents/xml_content_type.htm It always sends a content type of "application/x-www-form-urlencoded". But in version 5,0,42,0 (only through the webbrowser) of the player you have a new XML member called contentType that I can set the type to "text/xml". Now, when I do this $HTTP_RAW_POST_DATA will be set with my XML and not chopped into nasty key value pairs.
And the second minor tidbit, for PHP developers: In version 4.0.7 there will be a config directive to force $HTTP_RAW_POST_DATA to stay set no matter what. For those of you interested, here's my code (and it seems to work for me - heavily borrowed from macromedia example):
on (release) { // A. Construct a XML document with a LOGIN element loginXML = new XML(); loginElement = loginXML.createElement("LOGIN"); loginElement.attributes.username = "MyDog"; loginElement.attributes.password = "barkbark"; loginXML.appendChild(loginElement); // this only works in version 5,0,42,0 or greater (test in web browser) loginXML.contentType = "text/xml"; // B. Construct a XML object to hold the server's reply loginReplyXML = new XML(); loginReplyXML.onLoad = onLoginReply; // C. Send the LOGIN element to the server, //place the reply in loginReplyXML loginXML.sendAndLoad("xmlreader.php", loginReplyXML); }
<? // make sure you have the proper permissions to write to this file $filename = "xmloutput.txt"; $fp = fopen( $filename,"w+"); fwrite ( $fp, "$HTTP_RAW_POST_DATA" ); fclose( $fp ); print '<?xml version="1.0"?><result>LOGIN OK</result>'; ?>
and I end up with an xmloutput.txt file with this in it:
<login password="barkbark" username="MyDog" />
Another options is:
Anyway the kludge is to do some parsing in PHP before invoking the XML engine. The faulty content-type is causing PHP to parse the data as if it were url encoded ('attribute1=value1&attribute2=value2...') and place it in $HTTP_POST_VARS instead of $HTTP_RAW_POST_DATA where the XML engine expects it. It's trivial to set things right once you know what's gone wrong:
$s = ''; while(list($key, $val) = each($HTTP_POST_VARS)) { $s .= $key . '=' . $val; } $s = str_replace('_', ' ', stripslashes($s)); $HTTP_RAW_POST_DATA = $s;
Then just proceed as normal, invoking your XML parser of choice...
The ASP should use the Microsoft XML Parser to read the XML elements and traverse the tree.
To get the XML in, try assigning the whole post data to a variable.
Dim strXML Dim objXML strXML = Request.Form Set objXML = Server.CreateObject("Microsoft.XMLDOM") ' Do manipulation here Set objXML = Nothing ' Free it after use
This example script takes 2 parameters in the URL and saves the data into a xml file on the server.
############## ### Start Script ############## ######################################################################################### ### This file takes 2 name/value pairs in either GET or POST form. ### The names are 'name' and 'xml'. 'Name' contains the full name of the file you want to create... ### ... and 'xml' contains the data you want to write. It doesn't have to be in XML format, ### and the file doesn't have to end in ".xml"... so you could essentially write your own server-side scripts ### from within Flash - in the form of text, and then send it to the server, and call it later.... anyway.. ######################################################################################### #!/usr/local/bin/perl print "Content-type: text/html\n\n"; if($ENV{'REQUEST_METHOD'} eq "GET"){ $my_data = $ENV{'QUERY_STRING'}; } else { $data_length = $ENV{'CONTENT_LENGTH'}; $bytes_read = read(STDIN, $my_data, $data_length); } # Let's load it into something we can use @name_value_array = split(/&/, $my_data); # Here's where we do the actual work. We're going to cycle # through @name_value_array to decode the name=value pairs foreach $name_value_pair (@name_value_array) { # Split the name=value pair in your HTML form data ($name, $value) = split(/=/, $name_value_pair); # Now, replace '+' with ' ' $name =~ tr/+/ /; $value =~ tr/+/ /; # Next, we'll translate any hex values back into characters $name =~ s/%(..)/pack("C",hex($1))/eg; $value =~ s/%(..)/pack("C",hex($1))/eg; # Finally, we'll load the variables into an associative array # so we can use it when we need it. if($form_data{$name}) { $form_data{$name} .= "$value"; } else { $form_data{$name} = $value; } } # Now print out the data to verify that it's correct. #foreach $form_data_key (keys(%form_data)) { # print "$form_data_key = $form_data{$form_data_key}<br>"; #} #At this point, our name=value pairs have been decoded into their original form. Now we can put them into a hash that our script can use. #Since $name corresponds with a specific form element, we'll use that as the index. That way, if we want to access the value in, say, a #textbox, we can do that with #$first_name = $form_data{'first_name'}; # File manipulation $fileNameToOpen = $form_data{'name'}; open myHandle, ">$fileNameToOpen"; $XMLtoWrite = $form_data{'xml'}; print myHandle $XMLtoWrite; close myHandle; print "Here's the XML: ".$XMLtoWrite; ############## ### End Script ##############
The random number solution is simply trick the browser/proxy server into thinking it is getting a new file, because the URL has changed.For example if I am loading:
http://www.tupps.com/flash/news.xml
And this file is changing the browser will see the request for the URL and know that it is the same one and will not make an update.If I change the URL to be:
http://www.tupps.com/flash/news.xml?random=12845743890527
Where the last number is random. For the web server it will simply ignore this random=12923434 number, as it is just a file. However the browser and proxy servers are unable to determine that this is the same as the file before and will be forced to reload the file, as they are not able to determine that the files are the same. If you make the 'random' number based on date and time you can guarentee that the random numbers will not be repeated.
5 |
Scripting |
The xml.onload property which you can set with the name of a function. Once the XML file has been loaded and parsed by the flash player your function will then be called. Your function should take a single parameter which flash will pass to you specifing whether the XML file was successfully loaded. Check this before trying to access your XM Ldata.
Node values are the values between tags in XML. Eg the node value in the following XML for the my-xml tag:
<my-xml>Flash is great</my-xml>
is "Flash is great"
Once you have parsed through your tree and found node you want to access you can use the .nodeValue property to retreive the text of that node. Eg:
trace(myXML.firstChild.nodeValue)
Using the nodeValue function is not really necessary (although it is good form) you can simply use:
trace(myXML.firstChild)
The same results will be returned as the first statement. You can use these methods for setting the node values as well.
Attributes assigned inside a XML tag. For example the attributes of the tag my-xml:
<my-xml quotefrom="Luke Tupper" display="All">Flash is great</my-xml>
are QuoteFrom and Display.
Attributes are accessed in Flash using the attributes tag in two ways:
trace(myXML.firstChild.attributes.QuoteFrom
or
trace(myXML.firstChild.attributes["QuoteFrom"]
The attributes node can be used for assigning attributes to XML as well as accessing attributes. Adding a new attribute is done as such:
myXML.firstChild.attributes.NewAttribute = "New Value"
This will result in xml looking like:
<myxml quotefrom="Luke Tupper" display="All" newattribute="New Value">....
If you're going to place HTML markup inside of an XML document - and you do NOT want it to be treated as XML. use CDATA tags. CDATA stands for Character data - or non-parseable data. In other words CDATA tags will contain characters that are left alone, characters that are skipped over by any XML parsing engine.
Flash can retrieve the information inside of CDATA tags just fine - and then you could deal with it however you wanted.
sample XML:
<top><![CDATA[<b>Hello!</b>]]></top>
ActionScript:
myXML = new XML; myXML.onLoad=handleLoad; myXML.load("xml.xml"); function handleLoad(status){ status ? trace(_root.myXML.firstChild.firstChild.nodeValue): trace("plop"); // Traces:: <b>Hello!</b> }
Asking Flash for anything other than the nodeValue of a CDATA section will return the 'escaped' value, or
ActionScript:
myXML = new XML; myXML.onLoad=handleLoad; myXML.load("xml.xml"); function handleLoad(status){ status ? trace(_root.myXML.firstChild.firstChild.nodeValue) : trace("plop"); //Traces:: <b>Hello!</b> }
Well either option is applicable. Both will deliver you the data that you require. Vaykent has done some tests recently and found XML with attributes load a lot quicker than XML with a large number of nodes. (Note this information is current for Flash 5.
Flash 5 is quite slow when loading XML. This has been fixed in Flash MX. If you are using Flash 5 the smart guys at figleaf have a better way: XMLNitro 1.3 beta
http://chattyfig.figleaf.com/~bhall/code/xmlnitro.asThis routine replaces the standard XML routines and gets a 75~130% increase in speed. And se the diskussion around it....
http://www.were-here.com/forums/showthread.php?threadid=78637
6 |
Flash/XML Socket Servers |
A socket connection is different in one fundamental way from normal data-pushing in flash. Under normal circumstances, the Flash client must always ask for data from the server. But when you create a socket connection in Flash, the client 'listens' to the server, and the server can push information to the flash client. This is great if you want to create a news system that alerts people when new news items are available.
This is the key to multi-user environments, where the server acts as an intermediary between multiple Flash clients. It involves taking data such as instant messages from one client and then sending it to another client. Napster, RealAudio, Telnet, these all use sockets to communicate with the server, the same way that we want Flash too.
XML data that is brought into Flash through sockets is exactly the same as normal XML objects. The only difference is the process involved in getting data into Flash.
You need a XML server that is capable of accepting socket connections. If the flash movie is delivered from the a web server, the XML socket server must be running on the same server, or from the same subdomain. (eg a flash movie on www.flash.com can read a file from xml.flash.com)
An XML socket server is a piece of software that resides on the server and 'listens' on a 'port' for XML information from a client. When it receives information from a client it looks at the XML tags, and then performs some sort of action, such as broadcasting the information to other clients. XML socket servers can do many different tasks, some of them work with databases, others simply 'echo' information. An XML socket server can be written in Java, Python, C++ etc, and incorporate any number of features.
Right now the actual functionality of most Socket Servers for Flash revolve around chat. FlashNexus also allows for creation of custom tags in addition to it's normal <chat> tags. Fortress allows the creation of Java and Javascript plugin functionality making it probably the most robust XML socket server. Most are still in the 1.0 phase, and provide basic functionality and nominal security. None have real database functionality so that integrating your chat application or game with other parts of your site might pose a problem.
If you would like to learn more about how XML sockets work, download and look at MoockComm. If you are looking for a chat or simple game server then FlashNexus is a wonderful app. If you want Java use Drserver. If you need to integrate your Flash app with an existing database, such as a mySQL server, need security and enterprise class stability then your only option currently is Fortress.
There are many different flavors of servers in many different languages and each one has its strengths and weaknesses.
Freeware. Source code available.
Perl code snippets and .fla client.
Perl code for generic flash chat client. By Vaykent, sample below:
Perl code sample:
use IO::Socket; use IO::Select; $manager = new IO::Socket::INET ( Listen => 1, LocalPort => 2229); $selectObj = new IO::Select($manager); $/ = "\0"; while(@readySockets = $selectObj -> can_read){ foreach (@readySockets){ if($_ == $manager){ $newConnection = $manager -> accept; $selectObj -> add($newConnection); } else{ my $sysreadReturn = sysread($_, $infoRead, 2048); if($sysreadReturn == 0){ $syswriteToClient = syswrite($_, '', 2048); if($syswriteToClient==undef){ $selectObj -> remove($_); } } else{ foreach $eachClient ($selectObj->handles){ $syswriteToEachClient = syswrite($eachClient, $infoRead, 2048); } } } } }
Ruby code for generic flash chat client. By Vaykent (again), sample below:
Ruby code sample:
require "socket" # Set EOL for Flash $/="\0" # Establish the main listening socket on the localhost on port 4444 mainSocket = TCPserver.open('localhost', '4444') # Get the addre # Establish the main listening socket on the localhost on port 4444 mainSocket = TCPserver.open('localhost', '4444') # Get the address array from the connection # .. and Toss out the connection type (It's usually something like "AF_NET"... useless to us) addr = mainSocket.addr addr.shift # Display connection information print "server is on...\nIP:\t#{addr[2]}\nPort:\t#{addr[0]}\nComputer Name:\t#{addr[1]}\n" # Establish array container for threads allThreads=Array.new(); totalAccepted=0; #Loop endlessly loop { # Accept connections on the main listening socket ns = mainSocket.accept totalAccepted+=1 print totalAccepted # Get the address information from the connection # (same as above [line 9] - but for the other side of the connection) peerName=ns.peeraddr print(peerName, " is accepted\n") # Add this connection to the list allThreads << ns # Start the thread to handle the connection # Threads aren't the greatest in ruby.. so this'll have to change # - probably to spawning a new process... Thread.start do # Threads have access to all variables (global, local, blah) when they are started. # If we didn't create a local variable to hold the connection.... s = ns # save to dynamic variable # Save our name to a local variable ourName=allThreads[allThreads.length-1] puts ourName # Read from the connetion while s.gets # Display what we've recieved in the console rawDisplay=$_.dump print "incoming - #{rawDisplay}\n" # Uncomment this line to write to all clients connected. allThreads.each { |aThread| aThread.write($_) # Uncomment this line to write to all clients connected EXCEPT the sender. # allThreads.each { |aThread| # if aThread!=ourName # aThread.write($_) # end # } # Uncomment this line to echo back what it heard, ONLY to the client who said it. # s.write($_) end # The connection was terminated. This thread will end as well... print(s, " is gone\n") s.close end }
Freeware. Source code available.
A great start at coding a chat server in Java. Not a servlet, but a multi-threaded Server object. I've had a couple errors and the fla isn't very robust but overall well-thought out and nearly there.
Freeware. Source code available.
Alpha software currently at 0.1pre2. Written in Python.
Commercial Server Software.
Windows and Linux server software. 5-user demo available or $95.00 64-user full version. Provides chat, multiuser handling, whiteboards etc. Comes with examples.
Freeware. Source code available.
Colin Moock's simple chat client. Written as an illustration of coding in Flash with XML. Best beginner app to understand the intricacies of XML in Flash (I also recommend FlashNexus's chat client).
Commercial Server Software
Unity is a socket server specifically designed for Flash. While it comes with some out of the box solutions for setting up chat ect, you can build your own solutions using Java.
Freeware. Source code available.
Windows based server software built specifically for chat. Well-built freeware with MS Access database functionality and the ability to build custom tags. Allows execution of SQL statements from flash.
Commercial Server Software.
Flash-XML based message board and avatar chat. Allows a custom front and back end. Requires Linux 5.0 or newer(whatever that means) ,Perl 5.004 or newer, Apache 1.2 or newer. Evaluation copy available. Not available at last check 9/12/2002
Commercial Server Software.
The flash XML enterprise, mission-critical solution. Licensed-only on a per-server per user basis. The client is rather impressive, has everything you'd expect, plus top-class support and security. From the website: "activities taking place in any given room can be customized with simple plugins written in Java[tm] or JavaScript." Also available are Fortress Hosting Solutions at http://www.mediatemple.net . Evaluation copy available.
Linux, FreeBSD, Unix, and Win32 with cygwin.
Jabber server supports flash5 xmlsocket connections directly. This means is that flash clients canconnect to the Jabber server as a normal Jabber client, and speak the normal Jabber XML protocol. One (not updated recently) such example ishttp://www.flabber.org/ and Disney is also starting to roll out some flash games on their site that use this. It also has support for 'Transports' which allow you to extend the capabilities of the server to include AIM, IRC, Yahoo, and MSN protocols, allowing your flash clients to communicate to anyone on these networks.
Freeware. Java.
Basic XML socket server and demo client. Comes with java source if you'd like to explore it. Yet another useful tidbit from Fig Leaf Software.
7 |
XML Socket Programming |
Unfortunately the learning curve for using Flash and sockets is rather steep. It requires advanced knowledge of object-oriented concepts in ActionScript, and intermediate knowledge of web servers at the very least. You are better off with knowing a programming language or some server side scripting in order to make things really work. If you are looking for an easy flash chat app then steal some code from flashKit. XML socket servers offer advanced functionality for advanced flash apps.
Socket servers must open a connection with a client using a port. Ports are numbered 0 to 65535. Flash requires the port number must be greater than 1024. Flash also requires that the server's domain be the same as that of the site, same as a normal data connection from Flash. Standard issues with XML, such as being unable to use XML objects anywhere but the _root, still exist with XML socket data, the only difference between XMLSocket data and XML data is the way that it is retrieved.
XMLSocket.onClose (page 422 of the ActionScript Reference Guide) allows you to set a callback function when the connection is closed by the server.In all the socket is pretty simple, with the following commands:
connect, onConnect (Callback) close, onClose (Callback) onXML (Callback receiving a completed XML file) send (send an XML document).
The same issues exist that will if you want to let real audio or any other protocol through. The firewall has to be set up to allow the connections to be created on the appriorate port. It's sort of common courtesy for certain ports to be certain kinds of data, such as HTML data runs over port 80, and Telnet on 22, FTP on 21, Napster on 6969. Most Firewall and Proxy software are constantly updated for these programs to allow data through these common ports, but block any data on others. So if you use a port that's not commonly used then it might be blocked on computers behind a firewall, and flash will simply not be able to communicate unless the client's network administrator specifically enables that port. If you decide to use a commonly used port, such as say Napster's 6969 and your clients are running Napster, then Flash will receive Napster's data and vice versa, completely kludging things up.
Your XML server must terminate each XML messages with a null (ASCII 0) otherwise your flash application will hold open a connection until the session is closed. If you are having problems have a look at some of the prebuilt flash servers that are known to be working and test with those, before using your own server. Then you can concentrate on problems in your flash code or your socket server.
8 |
Resources |
http://www.w3schools.com/dom/dom_parser.asp
http://www.flash5actionscript.com/
http://www.moock.org/webdesign/flash/
http://flash-creations.com/notes/dynamic_xml.php
9 |
Thanks and Acknowledgements |
Founding Author: Luke Tupper flash@tupps.com
Author: VAYKENT
Flash-Sockets Author: Chris Hill chill@collective3.com
Thanks to everyone who has helped in defining this FAQ either via email or on the FlashKit Forum.
Naveen Rao
ironmallet
Jpsy
Muzak Muzakmuzak@pandora.be
Jeremie jeremie@jabber.org
Japanese Translation: Jun Kitazawa jun@bascule.co.jp
The following books were used in the creation of this FAQ:
Flash 5 Magic, New Riders, ISBN 0-7357-1023-6
ActionScript The Definitive Guide, O'Reilly, ISBN 1-56592-852-0