Understanding AS3 and XML
- May 21, 2009 by Emanuele Feronato
- Filed under Actionscript 3, Flash | 5 Comments
When you are about to design a Flash application using dynamic content, such as an image gallery or a tile based game, XML is one of the best ways to handle external content because it’s very easy to create, understand, read, and update.
AS3 now uses a system called ECMAScript for XML (E4X) that will do most of the dirty job, allowing us to focus on the application we are goingo to write.
From Wikipedia: ECMAScript for XML (E4X) is a programming language extension that adds native XML support to ECMAScript (which includes ActionScript, DMDScript, JavaScript, JScript). The goal is to provide an alternative to DOM interfaces that uses a simpler syntax for accessing XML documents. It also offers a new way of making XML visible. Before the release of E4X, XML was always accessed at an object level. E4X instead treats XML as a primitive (like characters, integers, and booleans). This implies faster access, better support, and acceptance as a building block (data structure) of a program.
So let’s start playing with it, and let me show you the one of the worst XML you can find… a collection of Sokoban levels (guess why?)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | <?xml version="1.0" encoding="ISO-8859-1"?> <SokobanLevels xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="SokobanLev.xsd"> <Title>Fly</Title> <Description>Simple Microban-style levels.</Description> <Email>bsimpson_910@hotmail.com</Email> <LevelCollection Copyright="Tim LeFevre" MaxWidth="15" MaxHeight="11"> <Level Id="The Fly_1" Width="11" Height="11"> <L> ####</L> <L> # #</L> <L> ## ####</L> <L>###.$.$. #</L> <L># $.$.$ ##</L> <L># .$@$. #</L> <L>## $.$.$ #</L> <L> # .$.$.###</L> <L> #### ##</L> <L> # #</L> <L> ####</L> </Level> <Level Id="The Fly_2" Width="13" Height="11"> <L> ####</L> <L> # #</L> <L> ### ####</L> <L>### .$.$. #</L> <L># $.$.$ ###</L> <L># .$#$. #</L> <L>### $.$.$ #</L> <L> # .$.$. ###</L> <L> #### ###</L> <L> # @#</L> <L> ####</L> </Level> <Level Id="The Fly_3" Width="15" Height="11" Copyright="1106 1087 Jordi Doménech"> <L> ####</L> <L> ## ##</L> <L> # ###</L> <L>#####$.$.$ ###</L> <L># $.#.#.$ ##</L> <L># $.@.$ #</L> <L>## $.#.#.$ #</L> <L> ### $.$.$#####</L> <L> ### #</L> <L> ## ##</L> <L> ####</L> </Level> </LevelCollection> </SokobanLevels> |
This is one of the worst XML you can find because it has an unknown number of nodes (I don’t know how many levels has a level collection) and some nodes with multiple attributes.
But you’ll see parsing it with AS3 will be very easy anyway.
Let’s see how to read the xml file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package { import flash.display.Sprite; import flash.events.Event; import flash.net.URLRequest; import flash.net.URLLoader; public class sokoxml extends Sprite { public function sokoxml() { var loader:URLLoader=new URLLoader; var req:URLRequest=new URLRequest("sokobanxml.xml"); loader.addEventListener(Event.COMPLETE,on_xml_completed); loader.load(req); } public function on_xml_completed(event:Event):void { var xml_to_parse:XML=new XML(event.target.data); trace(xml_to_parse) } } } |
This would outputs the entire XML file in the same way it was created. Let’ see how does it work:
Lines 8-9: Setting the XML file to load
Line 10: Adding a listener to check if the XML has been completely loaded
Line 11: Loading the file
Line 14: Transforming the file in a XML variable. Not it’s ready to be parsed
The first things we want to look for in an XML file are elements. The elements method lists the elements of an XML object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package { import flash.display.Sprite; import flash.events.Event; import flash.net.URLRequest; import flash.net.URLLoader; public class sokoxml extends Sprite { public function sokoxml() { var loader:URLLoader=new URLLoader ; var req:URLRequest=new URLRequest("sokobanxml.xml"); loader.addEventListener(Event.COMPLETE,on_xml_completed); loader.load(req); } public function on_xml_completed(event:Event):void { var xml_to_parse:XML=new XML(event.target.data); for each (var item:XML in xml_to_parse.elements()) { trace(item.name()+": "+item+"\n--------------"); } } } } |
With the for each loop we can parse all elements even if we do not know how many of them we have in our XML file. The output is pretty similar to the original file because elements method does not care if an element has children.
Title: Fly -------------- Description: Simple Microban-style levels. -------------- Email: bsimpson_910@hotmail.com -------------- LevelCollection: <LevelCollection Copyright="Tim LeFevre" MaxWidth="15" MaxHeight="11" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Level Id="The Fly_1" Width="11" Height="11"> <L>####</L> <L># #</L> <L>## ####</L> <L>###.$.$. #</L> <L># $.$.$ ##</L> <L># .$@$. #</L> <L>## $.$.$ #</L> <L># .$.$.###</L> <L>#### ##</L> <L># #</L> <L>####</L> </Level> <Level Id="The Fly_2" Width="13" Height="11"> <L>####</L> <L># #</L> <L>### ####</L> <L>### .$.$. #</L> <L># $.$.$ ###</L> <L># .$#$. #</L> <L>### $.$.$ #</L> <L># .$.$. ###</L> <L>#### ###</L> <L># @#</L> <L>####</L> </Level> <Level Id="The Fly_3" Width="15" Height="11" Copyright="1106 1087 Jordi Doménech"> <L>####</L> <L>## ##</L> <L># ###</L> <L>#####$.$.$ ###</L> <L># $.#.#.$ ##</L> <L># $.@.$ #</L> <L>## $.#.#.$ #</L> <L>### $.$.$#####</L> <L>### #</L> <L>## ##</L> <L>####</L> </Level> </LevelCollection> --------------
So the first thing to do is to create a recursive function, because we don’t know if a child of an element has its own children, that can have children, and so on. That’s why I am approaching this problem with recursive functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package { import flash.display.Sprite; import flash.events.Event; import flash.net.URLRequest; import flash.net.URLLoader; public class sokoxml extends Sprite { public function sokoxml() { var loader:URLLoader=new URLLoader ; var req:URLRequest=new URLRequest("sokobanxml.xml"); loader.addEventListener(Event.COMPLETE,on_xml_completed); loader.load(req); } public function on_xml_completed(event:Event):void { var xml_to_parse:XML=new XML(event.target.data); for each (var item:XML in xml_to_parse.elements()) { recursive(item); } } public function recursive(xml:XML) { trace("NAME: "+xml.name()); trace("VALUE: "+xml.children()); trace("-----------------"); } } } |
As you can see, the result does not change…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | NAME: Title VALUE: Fly ----------------- NAME: Description VALUE: Simple Microban-style levels. ----------------- NAME: Email VALUE: bsimpson_910@hotmail.com ----------------- NAME: LevelCollection VALUE: <Level Id="The Fly_1" Width="11" Height="11" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <L>####</L> <L># #</L> <L>## ####</L> <L>###.$.$. #</L> <L># $.$.$ ##</L> <L># .$@$. #</L> <L>## $.$.$ #</L> <L># .$.$.###</L> <L>#### ##</L> <L># #</L> <L>####</L> </Level> <Level Id="The Fly_2" Width="13" Height="11" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <L>####</L> <L># #</L> <L>### ####</L> <L>### .$.$. #</L> <L># $.$.$ ###</L> <L># .$#$. #</L> <L>### $.$.$ #</L> <L># .$.$. ###</L> <L>#### ###</L> <L># @#</L> <L>####</L> </Level> <Level Id="The Fly_3" Width="15" Height="11" Copyright="1106 1087 Jordi Doménech" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <L>####</L> <L>## ##</L> <L># ###</L> <L>#####$.$.$ ###</L> <L># $.#.#.$ ##</L> <L># $.@.$ #</L> <L>## $.#.#.$ #</L> <L>### $.$.$#####</L> <L>### #</L> <L>## ##</L> <L>####</L> </Level> ----------------- |
Now it’s time to scan each element and see if it has children. The children method lists the children of the XML object in the sequence in which they appear. So, now for each element I am scanning for children, and for each child (if any), for children of that child, and so on.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package { import flash.display.Sprite; import flash.events.Event; import flash.net.URLRequest; import flash.net.URLLoader; public class sokoxml extends Sprite { public function sokoxml() { var loader:URLLoader=new URLLoader ; var req:URLRequest=new URLRequest("sokobanxml.xml"); loader.addEventListener(Event.COMPLETE,on_xml_completed); loader.load(req); } public function on_xml_completed(event:Event):void { var xml_to_parse:XML=new XML(event.target.data); for each (var item:XML in xml_to_parse.elements()) { recursive(item); } } public function recursive(xml:XML) { trace("NAME: "+xml.name()); if (xml.children()==xml) { trace("VALUE: "+xml.children()); trace("-----------------"); } else { trace("This node has children:"); for each (var item:XML in xml.children()) { recursive(item); } } } } } |
Now the XML has been completely parsed, I can see if a node has children and list them properly
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | NAME: Title VALUE: Fly ----------------- NAME: Description VALUE: Simple Microban-style levels. ----------------- NAME: Email VALUE: bsimpson_910@hotmail.com ----------------- NAME: LevelCollection This node has children: NAME: Level This node has children: NAME: L VALUE: #### ----------------- NAME: L VALUE: # # ----------------- NAME: L VALUE: ## #### ----------------- NAME: L VALUE: ###.$.$. # ----------------- NAME: L VALUE: # $.$.$ ## ----------------- NAME: L VALUE: # .$@$. # ----------------- NAME: L VALUE: ## $.$.$ # ----------------- NAME: L VALUE: # .$.$.### ----------------- NAME: L VALUE: #### ## ----------------- NAME: L VALUE: # # ----------------- NAME: L VALUE: #### ----------------- NAME: Level This node has children: NAME: L VALUE: #### ----------------- NAME: L VALUE: # # ----------------- NAME: L VALUE: ### #### ----------------- NAME: L VALUE: ### .$.$. # ----------------- NAME: L VALUE: # $.$.$ ### ----------------- NAME: L VALUE: # .$#$. # ----------------- NAME: L VALUE: ### $.$.$ # ----------------- NAME: L VALUE: # .$.$. ### ----------------- NAME: L VALUE: #### ### ----------------- NAME: L VALUE: # @# ----------------- NAME: L VALUE: #### ----------------- NAME: Level This node has children: NAME: L VALUE: #### ----------------- NAME: L VALUE: ## ## ----------------- NAME: L VALUE: # ### ----------------- NAME: L VALUE: #####$.$.$ ### ----------------- NAME: L VALUE: # $.#.#.$ ## ----------------- NAME: L VALUE: # $.@.$ # ----------------- NAME: L VALUE: ## $.#.#.$ # ----------------- NAME: L VALUE: ### $.$.$##### ----------------- NAME: L VALUE: ### # ----------------- NAME: L VALUE: ## ## ----------------- NAME: L VALUE: #### ----------------- |
The last thing I have to do is checking for attributes. An element can have one or more attributes, or can have no attributes. Also, I don’t know their names and values. That’s when attribute method comes and saves me. attribute returns a list of attribute values for the given XML object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package { import flash.display.Sprite; import flash.events.Event; import flash.net.URLRequest; import flash.net.URLLoader; public class sokoxml extends Sprite { public function sokoxml() { var loader:URLLoader=new URLLoader ; var req:URLRequest=new URLRequest("sokobanxml.xml"); loader.addEventListener(Event.COMPLETE,on_xml_completed); loader.load(req); } public function on_xml_completed(event:Event):void { var xml_to_parse:XML=new XML(event.target.data); for each (var item:XML in xml_to_parse.elements()) { recursive(item); } } public function recursive(xml:XML) { trace("NAME: "+xml.name()); for each (var att:XML in xml.attributes()) { trace("Attribute: "+att.name()+" = "+att); } if (xml.children()==xml) { trace("VALUE: "+xml.children()); trace("-----------------"); } else { trace("This node has children:"); for each (var item:XML in xml.children()) { recursive(item); } } } } } |
And finally the XML has been fully parsed, attributes included
NAME: Title VALUE: Fly ----------------- NAME: Description VALUE: Simple Microban-style levels. ----------------- NAME: Email VALUE: bsimpson_910@hotmail.com ----------------- NAME: LevelCollection Attribute: Copyright = Tim LeFevre Attribute: MaxWidth = 15 Attribute: MaxHeight = 11 This node has children: NAME: Level Attribute: Id = The Fly_1 Attribute: Width = 11 Attribute: Height = 11 This node has children: NAME: L VALUE: #### ----------------- NAME: L VALUE: # # ----------------- NAME: L VALUE: ## #### ----------------- NAME: L VALUE: ###.$.$. # ----------------- NAME: L VALUE: # $.$.$ ## ----------------- NAME: L VALUE: # .$@$. # ----------------- NAME: L VALUE: ## $.$.$ # ----------------- NAME: L VALUE: # .$.$.### ----------------- NAME: L VALUE: #### ## ----------------- NAME: L VALUE: # # ----------------- NAME: L VALUE: #### ----------------- NAME: Level Attribute: Id = The Fly_2 Attribute: Width = 13 Attribute: Height = 11 This node has children: NAME: L VALUE: #### ----------------- NAME: L VALUE: # # ----------------- NAME: L VALUE: ### #### ----------------- NAME: L VALUE: ### .$.$. # ----------------- NAME: L VALUE: # $.$.$ ### ----------------- NAME: L VALUE: # .$#$. # ----------------- NAME: L VALUE: ### $.$.$ # ----------------- NAME: L VALUE: # .$.$. ### ----------------- NAME: L VALUE: #### ### ----------------- NAME: L VALUE: # @# ----------------- NAME: L VALUE: #### ----------------- NAME: Level Attribute: Id = The Fly_3 Attribute: Width = 15 Attribute: Height = 11 Attribute: Copyright = 1106 1087 Jordi Doménech This node has children: NAME: L VALUE: #### ----------------- NAME: L VALUE: ## ## ----------------- NAME: L VALUE: # ### ----------------- NAME: L VALUE: #####$.$.$ ### ----------------- NAME: L VALUE: # $.#.#.$ ## ----------------- NAME: L VALUE: # $.@.$ # ----------------- NAME: L VALUE: ## $.#.#.$ # ----------------- NAME: L VALUE: ### $.$.$##### ----------------- NAME: L VALUE: ### # ----------------- NAME: L VALUE: ## ## ----------------- NAME: L VALUE: #### -----------------
This was the hardest situation, when you don’t exactly know the structure of your XML tree.
But a good PROgrammer always knows the structure of the data he’s playing with, so next time we’ll see how to parse this sokoban level in order to draw it on the screen.
They can be easily customized to meet the unique requirements of your project.
5 Responses
Leave a Reply
- Una guida completa al gioco del poker online e una selezione dei migliori casino online.
- casino online
- migliori casino online
- BlackJack online
- casinò online
- Giochi casino

(11 votes, average: 4.73 out of 5)



Good post Emanuele! I think this is a very interesting post.
You can use XML as a var inside the flash movie too so you don’t have to load externally.
Maybe some default levels are in game and extra levels loaded from server so users can contribute with levels to the game and the game can be played still if the “XML server” is down.
But of course, loading things at runtime is a bad practice if you cannot store more than 1 file on a server (I use Flex and the Embed metatag)
[...] Understanding AS3 and XML [...]
[...] one of those bookmarks, hopefully it will help some of you Learn To Use XML With Actionscript 3.0. view article Bookmark this [...]
Great! I have searched for this about a good time…
I’m working with result from API yahoo and it code is terrible! Your exemple done, but for some reason the tags are changing between name and values…
Do you imagine what’s happening?
If you want and can I would send data to you see.
Thanks.