Notes on Flash and XML

Flash can be used to create a movie that reads in XML data during runtime. These are notes on a sample application (see xmlfamily.fla) in which an XML file containing information (picture, name, speed) is read into arrays that then are used to display moving images. The movement is accomplished using frame actions in another frame.

An XML file suitable for this application is:

<?xml version="1.0" encoding="UTF-8" ?>

- scenes

- scene

nameWinter Piano Party: Esther and Aviva</name

pictureavivagrandma.jpg</picture

speed6</speed

</scene

- scene

nameUday with Amy and her sisters</name

picturesisters.jpg</picture

speed10</speed

</scene

- scene

namePiano and flutes</name

picturepianoandflutes.jpg</picture

speed8</speed

</scene

- scene

nameJeanine at Storm King</name

picturehat.jpg</picture

speed4</speed

</scene

- scene

nameDaniel</name

picturedaniel1.jpg</picture

speed3</speed

</scene

</scenes

Note that the XML file contains the names of image files. These files need to be jpg files present on the server in the same folder as the application swf file. They are loaded into the Flash application using loadPicture. A movie clip instance named place is used in loadPicture as a 'seed'. It is off-stage.

The ActionScript refers to the XML tree using built-in methods. The code checks the name of the node and then extracts the contents. That is, the XML file could contain other elements, which would be ignored. It is easy to be confused about the node versus the firstChild versus the nodeValue. If the node N is <picture>flutes.jpg</picture>, then

N.nodename ßà "picture"

N.firstChild.nodeValue ßà "flutes.jpg"

Reading in and parsing, that is, reading in the XML file, which can be a text file, and then constructing an XML tree, is not a quick operation. This is way there are provisions to do it asynchronously, that is, go on and do other things while this is being done. However, for this example, the code specifies .async = false.

ActionScript in Frame 1:

resultsXML=new XML(); / set resultsXML to be an XML object
resultsXML.onLoad=transXML; / Specify that after the XML file is read in and parsed, the function transXML is to be invoked.
resultsXML.async = false; / Wait for loading.
display1="getting data"; / Set a dynamic text field
var speeds = new Array(); / Set up empty array
var names = new Array(); / Set up empty array
var stuff= new Array(); / Set up empty array
var rightbound = 1000; / Specify right boundary
var leftbound = -200; / Specify left boundary. Images will move off the screen
resultsXML.load("scenesnoref.xml"); / Load in the XML file named scenesnoref.xml
function transXML() { / This is the definition of the function to be called when the file is read in.
if (this.loaded) { / If there was an error in the loading, the transXML function would still be called, so check if the loading was okay
display1 = "XML data is loaded."; / This outputs this message if things are okay. A robust application would have an else clause!
}
keyTag = new XML(); / Set up a new XML object
matchList = new Array(); / Set up an empty array. It will hold all the child nodes of the document node (in this case, all scenes)
keyTag=this.lastChild; / This is the document node
matchList= keyTag.childNodes; / This is the childNodes (all scene nodes)
matchdata = new Array(); / Used and re-used for each scene
ccount = 0; / Keep count
nump = -1; / Used to keep track of levels
display = ""; / erase display text field
for (m = 0; m<=matchList.length; m +=1) { / Loop through all the child nodes
if (matchList[m].nodeName=="scene") { / If the node is a scene node….
ccount++; / Increment ccount
matchdata = matchList[m].childNodes; / Put the child nodes for the scene node into matchdata
for (i=0; i<=matchdata.length; i++) { / Loop through matchdata. (Note: we know for this XML file, that matchdata will have length 3, but can be more general)
if (matchdata[i].nodeName=="picture") { / If this is the picture element
nump++; / increment nump keeping track of levels
newp = "place"+nump; / Create a name
duplicateMovieClip(place,newp,nump); / Create a movieclip using the instance named place
setProperty(newp,_y,10+60*(nump)); / Position it using nump in the formula for _y
setProperty(newp,_x,200*(nump-1)); / …. and _x
loadMovie(matchdata[i].firstchild.nodeValue,newp); / loadMovie, using the contents of this element—the name of a jpg file
stuff.Push(_root[newp]); / Add (push) this newly created instance to the stuff array
} / Ends clause for picture element
if (matchdata[i].nodeName=="speed") { / If this is a speed element
speeds.Push(Number(matchdata[i].firstchild.nodeValue)); / Add (push) this value onto the speeds array
} / End if speed
if (matchdata[i].nodeName=="name"){ / If this is a name element
names.Push(matchdata[i].firstchild.nodeValue); / Add (push) this value onto the names array.
} / End if name
} //closes going through child nodes of a player node / End loop through matchdata
display = display+" "+names[names.length-1]+"\n"; / Add to display text field
} //closes if scene node / Close if scene node
} //closes going through child nodes of topmost node / Close looping through all scene nodes
display1="1 2 3 4 5 "; / Set text field
} //closes transXML / Close definition of transXML function

After the action of frame1, the application does not refer to the XML file. The second frame has no action script, but is labeled "loop". The action in the third frame is to move each of the instances referenced in the stuff array using the corresponding value in the speed array. When an instance exceeds the right or left bounds, the speed value is changed so the instance will start moving in the opposite direction.

for (i=0; i<stuff.length; i++) { / Loop through stuff array
stuff[i]._x = stuff[i]._x+speeds[i]; / Move ith instance horizontally using the corresponding value in the speeds array
if (stuff[i]._x>rightbound) { / Check if past the right boundary
speeds[i]=-speeds[i]; / … if so negate speed
}
if (stuff[i]._x<leftbound) { / Check if past the left boundary
speeds[i]=-speeds[i]; / … if so negate speed
}
} / End looping
gotoAndPlay("loop"); / Go to frame labeled loop.