AS Reference  :  Notes Index  :  Resources  :  About/Contact  :  Downloads

Using XML as the data source for the Oahumap application

In this sample, we've taken the example in Easing Slider 4 and changed it to use XML as the data source (instead of hard-coding the information into the fla). We also added one more piece of information to each location: a blurb about that location, including html links, to display in a scrollable textfield.

Because we'll be using an XML file as the data source, we can replace the array we used previously:

var groupinfo:Array = [
   {placename:"Sunset Beach", myphoto:slider_mc.pic0, xloc:178, yloc:85,  xtext:146, ytext:64},
   {placename:"Kailua",       myphoto:slider_mc.pic1, xloc:347, yloc:245, xtext:352, ytext:230},
   {placename:"Hanauma Bay",  myphoto:slider_mc.pic2, xloc:367, yloc:318, xtext:355, ytext:324},
   {placename:"Waikiki",      myphoto:slider_mc.pic3, xloc:282, yloc:306, xtext:249, ytext:309},
   {placename:"Pearl Harbor", myphoto:slider_mc.pic4, xloc:217, yloc:273, xtext:189, ytext:294}
   ];  
  

with a blank groupinfo array that will be populated with data from the XML file. Each of the properties previously in groupinfo can be replicated in the XML file as attributes of a node. We'll structure the XML file to have one main places node, and as many individual place nodes as there are locations to be shown. Here is what that implementation of the XML file would look like:

oahumap.xml, initial version

<?xml version="1.0" encoding="utf-8"?>
<places>
   <place placename="Sunset Beach" xloc="178" yloc="85" xtext="146" ytext="64" />
   <place placename="Kailua" xloc="347" yloc="245" xtext="352" ytext="230" />
   <place placename="Hanauma Bay" xloc="367" yloc="318" xtext="355" ytext="324" />
   <place placename="Waikiki" xloc="282" yloc="306" xtext="249" ytext="309" />
   <place placename="Pearl Harbor" xloc="217" yloc="273" xtext="189" ytext="294" />
</places>
  

You can see the resemblance between the xml file and the original groupinfo array, which perhaps provides a hint about how each node in the XML file might be read and its data saved in an element of groupinfo. What we need to do is store each attribute of the place tags in the corresponding property of a groupinfo array element. Here's the code to create an XML object mapxml and a blank groupinfo array, define a function to read and put data in mapxml into groupinfo, assign that function to the onLoad property of mapxml, and start loading the XML file:

// import the Delegate class to use for assigning the XML onload function
import mx.utils.Delegate;

// create a new XML instance (a variable of type XML)
var mapxml:XML = new XML();

// create a blank groupinfo array to be filled in by onXmlRead
var groupinfo:Array = [];

function onXmlRead(ok:Boolean) {
   if (ok) {
      var places:Array = mapxml.firstChild.childNodes;
      for (var i=0; i < places.length; i++) {
         groupinfo.push({
            placename:places[i].attributes.placename,
            xloc:Number(places[i].attributes.xloc),
            yloc:Number(places[i].attributes.yloc),
            xtext:Number(places[i].attributes.xtext),
            ytext:Number(places[i].attributes.ytext)
         });
	  }
   } else {
      trace('problem reading xml file');
   }
}

function init() {
   mapxml.ignoreWhite = true;
   mapxml.onLoad = Delegate.create(this, onXmlRead);
   mapxml.load("oahumap.xml");
}
init();

When the code above executes, init is called first. The first line tells Flash to ignore carriage returns, tabs and any other whitespace between nodes in the xml file. Then it assigns the onXmlRead function to the onLoad event property of mapxml, retaining the main timeline as the scope for that function. Lastly, a call is made to the web server to download the XML file (or get it from cache if it has been previously downloaded). When the download is complete, onXmlRead will be called.

Within onXmlRead, a variable places is created to refer to the array of childNodes within the main place node in the XML file (the array of childNodes is just the collection of place tags that exist within the main places tag). onXmlRead then loops over that array of childNodes, creating a new element in groupinfo for each place tag and saving each attribute of the place node in the corresponding property of that newly created element of groupinfo. Got that?

Use init to load XML, setup to assign event handlers and other properties

Notice, if you haven't already, that the init function is completely different from the one in the previous example because now the thing that we need to do first of all on start up is to read the XML file and put its contents into a format (the groupinfo array) useable by our program. Only when that is complete can we do the things we did previously in init: assign event handlers and attach the dot movieclips and fill in their textfields. Because the XML file is now providing the information about where to attach each dot and each dot label, and what placename to use in the dot label, we can't set up that information til the data is ready to use. The place where that happens (the data being ready to use) is inside function onXmlRead, so that's where we'll add a line to call function setup, which will now contain everything that used to be in function init:

function onXmlRead(ok:Boolean) {
   if (ok) {
      var places:Array = mapxml.firstChild.childNodes;
      for (var i=0; i < places.length; i++) {
         groupinfo.push({
			placename:places[i].attributes.placename,
            xloc:Number(places[i].attributes.xloc),
            yloc:Number(places[i].attributes.yloc),
            xtext:Number(places[i].attributes.xtext),
            ytext:Number(places[i].attributes.ytext)
         });
	  }
	  setup();   // call the setup function to assign event handlers and build the map
   } else {
      trace('problem reading xml file');
   }
}

There's one more change that needs to be made to the code from our previous example. The associated picture movieclip information is no longer stored in the groupinfo array (or in the XML file). Because the naming scheme of the pictures (pic0-picn) follows a pattern that can easily be applied in a loop, there is no reason to store that information separately. We can just create the correspondence directly in the setup loop:

for (var i:Number=0; i < groupinfo.length; i++) {
   ctrl = this.attachMovie("dot", "p"+i, i, {
      _x:groupinfo[i].xloc,
      _y:groupinfo[i].yloc,
      placename:groupinfo[i].placename,
      myphoto:slider_mc["pic"+i]
    });
    // etc
}

The myphoto property is now assigned based on the corresponding photo having the same index in its name in the control (instead of from a property of the groupinfo array). Those are all the changes necessary to make the previous example work from an XML file instead of a hardcoded array.

Including html-formatted text in XML

One more change was made to this fla from the previous example to show an example of including scrollable html-formatted text read from the XML file. As mentioned on the XML page, any text in an XML file which needs to contain tags that are to be read in as is (eg, HTML-formatted text) instead of as subnodes of the node they appear under should be surrounded by special CDATA formatting. Specifically, the text should be preceded by <![CDATA[ and followed by ]]>. As an example, the Sunset Beach place tag now looks like this in the XML file:

<place placename="Sunset Beach"xloc="225" yloc="86" xtext="192" ytext="64">
<![CDATA[On the North Shore of Oahu, <a href="http://surfing.about.com/cs/epicsurfspots/a/072303sunset.htm" target="_blank">Sunset Beach</a>
 is known for big wave surfing during the winter season and home to the Duke Kahanamoku Classic surfing competition and 
 the O'Neill World Cup of Surfing competition and occasionally the site of the Quiksilver In Memory of Eddie Aikau big wave
  competition.]]></place>

The CDATA itself is not read as part of the tag -- it simply serves to indicate that the subsequent text should be read as a big text string (until the "]]>" is encountered). So the onXmlRead function now looks like:

function onXmlRead(ok:Boolean) {
   if (ok) {
      var places:Array = mapxml.firstChild.childNodes;
      for (var i=0; i < places.length; i++) {
         groupinfo.push({
            placename:places[i].attributes.placename,
            xloc:Number(places[i].attributes.xloc),
            yloc:Number(places[i].attributes.yloc),
            xtext:Number(places[i].attributes.xtext),
            ytext:Number(places[i].attributes.ytext),
            descrip:places[i].firstChild.nodeValue
         });
	  }
	  setup();
   } else {
      trace('problem reading xml file');
   }
}

Notice that the description text is read as the firstChild of the place tag (node), and its .nodeValue property is used to access it (in much the same way that a textfield's .text property is used to access the textfield's content).

I hope you can guess what the next step is, based on the steps we've followed previously: the descrip property of the groupinfo array has to be assigned to a property of the button, so it will be available for use in the rollover, rollout, and onrelease functions.

function setup() {
   var ctrl:MovieClip; 
   for (var i:Number=0; i < groupinfo.length; i++) {
      ctrl = this.attachMovie("dot", "p"+i, i, {
         _x:groupinfo[i].xloc,
         _y:groupinfo[i].yloc,
         placename:groupinfo[i].placename,
         myphoto:slider_mc["pic"+i],
         descrip:groupinfo[i].descrip
       });
   // etc
}

Now it's available as a property of the button, so when the button is clicked, that property can be used to set the content of textfield descrip on stage. We'll display it at the same time we display the new caption -- once the tween is complete (ie, in the showName function):

function showName() {
   caption.text = this.placename; 
   descrip.text = this.descrip;
   descrip.scroll = 1;	
   up._visible = down._visible = true;   
}

We also set the textfield's scroll property to 1 in case it was scrolled down on a previous click and unhid the up and down scroll buttons (hidden in init and doClick). The only thing left to add to the code is the text formatting, which we can do with either css styling (using the StyleSheet class) or the TextFormat class, both of which are shown on the Easing Slider 4 page. Since we already have a StyleSheet set up, we'll just add formatting for a tags (including hover) and use that for links in the the descrip field. Here's the change to the StyleSheet and its assignment to descrip:

var mapcss = new TextField.StyleSheet();
mapcss.setStyle(".caption", {fontFamily: "Verdana", fontSize: "10px", color:"#000000"});
mapcss.setStyle("a", {color: '#0000cc',  textDecoration:'underline'})
mapcss.setStyle("a:hover", {color:"#006600", textDecoration:'underline'}) 
...
function init() {
   descrip.styleSheet = mapcss;	
   mapxml.ignoreWhite = true;
   mapxml.onLoad = Delegate.create(this, onXmlRead);
   mapxml.load("oahumap.xml");
}

And the functions and assignments to handle single-click scrolling:

function scrollTextUp() {
   if (descrip.scroll > 0) {
      descrip.scroll--;
   }
}

function scrollTextDown() {
   if (descrip.scroll < descrip.maxscroll) {
      descrip.scroll++;
   }
}

function setup() {	
   ...
   // set up the textfield button handlers for continuous scroll when pressed
   up.onRelease = scrollTextUp;      
   down.onRelease = scrollTextDown;
}

For other scrolling options (click-and-hold buttons, eased scrollbar) and/or how to format text without css, see the scroll text page. The complete code for the example above may be found in oahumap_slider5.as and oahumap_slider5.fla, available via the link at right. The final example in this series will show how to create the slider and load the jpgs in it dynamically.

Intro
Flash: What & How
Example Sites
Create
Draw, Edit Shapes
Gradients
More Drawing Tips
Import
A Sample
Animate
Frames, Keyframes
Motion Tweens
More Motion Tweens
Shape Tweens
Masks
Control
Stop/Replay
Movieclips Intro
Movieclip Reference
Site Structure 1
Slideshow Movieclip
Contact Form
Scroll Resume
Preloader
Site Structure 2
Publish
Display Options
Player Detection
Optimize
AS 2.0 Basics
Intro to Syntax
Playhead Commands
Playhead Cmds 2
Coded Tween
onEnterFrame
Intro to Classes
Declare/Assign
Comments, Trace
Simple Data Types
Arrays & Objects
Code Blocks
Operators
Beyond Buttons
Code Structure
Toggle Controls
Group of Buttons
Drag and Hit
Distort Magnifier
Scroll Text
Bee Game
Dart Shooter
Sound Control
Easing Slider
Easing Slider 2
Components Intro
Timers & Delays
Dynamic Content
Intro
Drawing API
Create Text
Attach Movieclips
Easing Slider 3
Easing Slider 4
Load jpg/swf
Sliding Viewer
Preload swf
XML
Easing Slider 5
Server Comm
LoadVars (w/ PHP)
AS - PHP Lookup
Text File
Database 1:LoadVars
Database 2:Remoting
Read from directory
AS 2.0 Classes
Intro
Math
Key
Date
Color
EventDispatcher
New Samples
Pie Chart
Event-model Emailer
Tween Sequence
Fuse Sequence
SVG in Flash
Bitmap Topo
SWF as Data Holder
Two-level Menu
Yahoo! Flash Maps
Class-based Game
ASTB Samples
Disclaimer
3D Outlines
Bounce Collide
Address Book
Save Drawings
Home  :  Notes Index  :  Resources  :  About/Contact  :  Downloads