INFO 424 SCHEDULE

Olympic medals, Phase 9 - XML

<countries>
   <country id=''>
      <year id=''>
         <totalMedals></totalMedals>
         <goldMedals></goldMedals>
         <silverMedals></silverMedals>
         <bronzeMedals></bronzeMedals>
      </year>
   </country>
</countries>

Phase 9:
Store the data in an XML file

Now that we've got the basic functionality down, we'll go back and make modifications so the application will scale (i.e. so we can add more countries without making it more complex), and so it will be flexible (i.e. so we could use the application for different data or change the existing data without needing to rewrite the application).

BE AWARE:This phase covers several important and potentially frustrating concepts (loading XML files, pulling data from XML files, parsing text). Some of you will have encountered these concepts before, but if you haven't, they can be hard to learn - be patient with yourself (and with my efforts to explain it). Spend the time you need to understand it.

Right now the data is embedded in the Flash file. If we put the data in it's own file and just point to it from the .fla file, it opens the possibility of swapping out the data for different data.

Step 1: Put the data in its own file

There are a number of ways to represent data. One common one is with XML. That's what we'll use. (Some of you have taken an XML class, but I realize that many of you may not have - it shouldn't be too hard for you to follow along. XML can get complex, but the basics are very simple).

WHAT IS XML:

WHAT DOES XML LOOK LIKE?

Very much like HTML, but with HTML, you have tags that have been defined (e.g. <strong>, <p>, <div>). With XML, you make up tags for your particular purpose (you'll see samples soon).

So here's our raw data:

Japan:

  1964 2008
total 29 25
gold 16 9
silver 5 6
bronze 8 10

Canada:

  1964 2008
total 4 18
gold 1 3
silver 2 9
bronze 1 6

We can represent it as a hierarchy like this (it could be represented in different ways, this is just one idea)

data hierarchy

Here are the basic rules for writing XML:

XML BASICS:

  1. Must have a root element that starts and ends the XML (in the sample above, the root elements was <myTopLevelTag>:

  2. <rootElement>
    ...
    </ rootElement>

  3. Each element can have sub-elements which can be repeated:

  4. <rootElement>
       <subelement>
         contents of sub element 1
       </subelement>

       <subelement>

         contents of sub element 2
       </subelement>
    </rootElement>

  5. Each element can have 1 or more attributes which appear inside of the brackets with the element name:

  6. ...
    <subelement attribute1 = "attribute 1">
       contents of sub element 1
    </subelement1>
    ...

Here is the structure based on the hierarchy I showed above - no data, just the tags and attributes names:

<countries>
   <country id=''>
      <year id=''>
         <totalMedals></totalMedals>
         <goldMedals></goldMedals>
         <silverMedals></silverMedals>
         <bronzeMedals></bronzeMedals>
      </year>
   </country>
</countries>

Time for you to create an XML file:

a. An XML file is a plain text file so...open a text editor (Notepad, for example).

b. Paste the above XML into your text file.

c. Fill in the id attribute for the first country like this:

<country id='Japan'>

d. Fill in the id attribute for the first year like this:

<year id='1964'>

e. Fill in the first data value like this:

<totalMedals>29</totalMedals>

f. Fill in the rest (you'll need to repeat the <year> element to be able to fill in the "2008" data for Japan and you'll need to repeat the whole <country> element to fill in the data for Canada.

When you're done, but sure yours looks like mine:

<countries>
   <country id='Japan'>
      <year id='2008'>
         <totalMedals>25</totalMedals>
         <goldMedals>9</goldMedals>
         <silverMedals>6</silverMedals>
         <bronzeMedals>10</bronzeMedals>
      </year>
      <year id='1964'>
         <totalMedals>29</totalMedals>
         <goldMedals>16</goldMedals>
         <silverMedals>5</silverMedals>
         <bronzeMedals>8</bronzeMedals>
      </year>
   </country>
   <country id='Canada'>
      <year id='2008'>
         <totalMedals>18</totalMedals>
         <goldMedals>3</goldMedals>
         <silverMedals>9</silverMedals>
         <bronzeMedals>6</bronzeMedals>
      </year>
      <year id='1964'>
         <totalMedals>4</totalMedals>
         <goldMedals>1</goldMedals>
         <silverMedals>2</silverMedals>
         <bronzeMedals>1</bronzeMedals>
      </year>
   </country>
</countries>

NOTE: As with HTML, the white space in the file is optional. It's just there to make the file easier for humans to read; you could string it all together on a single line and the computer would be able to read it just fine.

g. Add this "XML declaration" at the beginning of the file:

<?xml version="1.0"?>

Your code will work without this, but it's good practice to include it.

h. Test your xml file by opening it in FireFox or Chrome (it won't look the same in safari). If it's correct, you'll see something that looks like this:

i. Save this file as "medalXML.xml" in the same folder where your Flash file is stored.

Step 2: Learn how to refer to XML elements

a .Download the code module introToXML.fla.

b. Open the file in Flash. You'll see this on the stage:

appearance of intro to XML module

b. Test it/run it and you'll see this:

run intro to XML

c. Open the Actions pane to see the code.

Take note of the 2 different ways to refer to an element or attribute in the XML (one is based on the attribute's properties, the other is based on its position).

Here are some references that will come in handy in the future when you're trying to figure this out (yes, they're kind of confusing. For now, just look at them to know they exist):

d. Now comment out the two lines that retrieve the data based on its properties by putting "//" in front of each, and un-comment the two lines that retrieve the data based on its position by removing the "//".

e. Test it again, you should get the same result.

f. Figure out how to use either method to refer to the second book. When you've succeeded, you'll see this when you test the move:

retrieving element 2

Step 3: Create an XML variable in your code

a. Open "Medals_8_text.fla" and save it as "Medals_9_XML.fla".

b. Open the code panel. After the other var statements, create an XML variable called "medalXML" (follow the example in the code module to do this). Paste in the XML from your XML file (you may be wondering why you're pasting the XML into the .fla file when the point is to have it in a separate file. That will come later, but I'm doing it this way to start simple).

c. Test your app. You won't see anything different, but you shouldn't get any error messages.

Step 4: Pull a piece of data from the XML object

The next step will be to pull the data from the XML object to put it into the info box.

Look at this example code which shows the XML object followed by a line that refers to one element:

var myXML:XML =
<metadatas>
   <item id='Book 1'>
      <bookTitle>War and Peace</bookTitle>
      <bookAuthor>Leo Tolstoy</bookAuthor>
   </item>
   <item id='Book 2'>
      <bookTitle>Harry Potter</bookTitle>
      <bookAuthor>JK Rowling</bookAuthor>
   </item>
</metadatas>;

myXML.item.(@id=='Book 1').bookTitle;

Here is the anatomy of that last line:

The line reads like this: Go to myXML. Go down one level (from the root) to an element called "item." Find the "item" element which has "Book 1" as the "id" attribute. Find the "bookTitle" element for that "item" element.

a. Go back to Medals_9_XML.fla.

We're going to start by grabbing one piece of data from the XML file. Your code currently has the following line which inserts the number "9" into the infobox (as you can see in the image below):

infoBox.NoGold_txt.text = "9";

25 in info box

You will want to replace this hard-coded "9" with a number pulled from the XML data. The next 4 instructions show you how to build up to this slowly in a way that makes it clear what is happening:

b. Insert a trace statement at the beginning of the "showInfoBox" function that retrieves the entire XML element:

trace(medalXML);

c. Run the movie and hover over a circle. Then look to see what you get in the output panel (the beginning should look like this):

output panel with XML

d. Now limit the retrieval to just the first element (NOTE: you don't have to specify the root element, that's assumed).

trace(medalXML.country);

e. Again, run the movie to see what you get in the output panel.

f. Keep adding to your phrase, following the model below until you just retrieve the number "9" (the number of gold medals Japan won in 2008):

Here's what mine looks like (click to reveal it):

trace(medalXML.country.(@id=='Japan').year.(@id=='2008').goldMedals);

f. Once you're sure the reference is correct, replace the "9" in this line:

infoBox.NoGold_txt.text = "9";

..with the reference that is currently in your trace statement, and test it to be sure you still see 9 in the info window when you hover over Japan while the slider is at 2008.

Step 3: Make the reference more generic

Now you've successfully retrieved data from the XML object. You could replace all of the numbers with similar references, but the code is pretty clunky. We want to make the reference generic by replacing the hard-coded values like "2008" and "Japan" with variables.

a. Create a variable called "currentYear" (put it with the other variable statements). Make it a String variable and make it equal to "2008" since that's the starting value when the application starts up.

b. Go to the beginning of the "changeDate" function and add the following code to update "currentYear" whenever the slider is moved (as you write the code, ask yourself what it's doing):

if (e.target.value == 0){
   currentYear = "1964";
}else{
   currentYear = "2008";
}

Now you can always know what year it is by checking the currentYear variable.

Next you want to put the name of the current country in a variable.

b. Create a variable called "countryName." Make it a String variable.

To figure out which country you've hovered over, you can take advantage of the fact that the name of the object being hovered over contains the name of the country (e.g. "JapanCircle_btn" ) . All you need to do is chop off the last 10 characters and you will have the name of the country.

Parsing text

"parsing" refers to using code to process text to get at a piece that you want. If you haven't already learned about text parsing, pay attention here. In my experience, this is a useful skill to have (I've used it in many situations over the years, most having nothing to do with visualizations). You'll get a very brief introduction below. There are a handful of parsing functions that you'll find in any programming language. They help you do things like find a letter that is "x" characters from the right end of the string, or find the character string "xyz" within a larger string).

To chop off the extra characters at the end of the object name, use the substr method (short for "substring"). It goes like this:

<string>.substr(<position of first character to include>,<length of the string you want>)

so if I had a variable called myText and I populated it with the string "Hi there" like this:

var myText = "Hi there";

and then wrote this trace statement:

trace(myText.substr(3,3));

the output would be:

the

because I start at position 3 (see the diagram below) and include 3 characters

character positions

c. Replace the trace statement that you currently have at the beginning of the showInfoBox function with this one:

trace(theEvent.target.name);

d. Test it. You should see "JapanCircle_btn" or "CanadaCircle_btn" depending upon which circle you hovered over.

e. Now use the substring method in your trace statement:

trace(theEvent.target.name.substr(0,4));

Test it. The first letter is in position "0" so you should see "Japa" or "Cana."

Since you don't know in advance how long a country's name is, you don't know what number to insert instead of 4. But you do know that it's always 10 characters before the final character (since the name always ends with the 10 characters "Circle_btn"). You can find out how long the entire string is using the .length method).

f. Write a second line:

trace(theEvent.target.name.length);

Now you should see either "Japa" "15" or "Cana" "16." When you hover over a circle.

Now that you know how many characters are in the entire string, you can subtract 10 to get the position of the last character in the country name.

g. Remove the second trace line and modify the first so the statement in parentheses reads:

theEvent.target.name.substr(0,(theEvent.target.name.length-10));

Be sure you understand what this line is doing. Now when you hover over a circle, you should see "Japan" or "Canada," which is what you want.

h. Write a line just after the trace line to assign the country name to that variable you created called "countryName":

countryName = theEvent.target.name.substr(0,(theEvent.target.name.length-10));

i. Now use that variable to put the correct country name in the info box (replacing the existing line with this one):

infoBox.countryName_txt.text = countryName;

Now the pieces are in place to pull out the correct value from the XML file for each of the text boxes in the info box (i.e. the text boxes for the country name, the total number of medals, the number of gold medals, etc.)

j. Comment out the entire contents of the "showInfoBox" function, except for two lines:

  1. The line you wrote that defines the "countryName" variable
  2. ...and the line that makes the info box visible

(You don't have to put "//" in front of every line, instead, you can put "/*" in front of the first line and "*/" after the last line:

/* all of these
lines will be commented
out */

k. Now add this line which fills in the value for the total number of medals:

infoBox.NoOfMedals_txt.text = medalXML.country.(@id==countryName).year.(@id==currentYear).totalMedals + " medals";

Make sure you understand exactly what this line is doing before moving on. NOTE: I've added "+ " medals" at the end because in my info box I want to put that text after the number so that it looks like this:

infobox with text

instead of this:

25 in info box

l. Now add the lines that fill in the values for the gold, silver and bronze medals and the line that fills in the value for the country name. (It will be just like the line you just inserted, but simpler because you don't need to add that extra text at the end).

m. Test this. When you're comfortable that it works, delete the commented code.

Now all of the data is being retrieved from the xml object.

Step 4: Put the data in a separate XML file

The final step is to put the XML in a separate file and load that XML file into Flash.

a. Download the loadXMLfile.fla module and it's accompanying XML file . Open the Flash file and run it.

It should look just the same as the previous module:

run intro to XML

But when you open the Actions pane, you'll see some differences.

Here's what the code is doing (look at the code and compare it to this explanation):

1. First, the XML object is created (shown as an empty box, ready to be filled with XML data), then the two functions are defined (but not run), then the first function is called:

xml load, step 1

2. When the the 'loadXMLFile' function is run (shown as an opened box below), the URLLoader requests the XML file ("Please give me..."), and is given a listener to allow it to hear the Complete event:

XML load 2

3. When the file has been loaded, the Complete event is broadcast ("XML load finished"), and an event object is created (represented by the green shape in the picture below). The loader hears the Complete event (because it has a listener for this event) and calls the loadedCompleteHandler function:

xml load 3

4. In the loadedCompleteHandler function, the event is named "e" (notice that the green event object is now labeled "e" in the picture below). The function gets the data associated with that event (the XML data shown by the black rectangle) and it is put into the myXML xml object (the box). Then data from this XML object is pulled out to populate the text boxes in the display:

 

XML load step 4

 

Now you'll do the same in your Medals_9_XML.fla file:

b. Add a function called "loadXMLFile" (just like in loadXMLfile.fla).

c. In this function, create a URLLoader called "loader" (just like in loadXMLfile.fla). Have it look for medalXML.xml.

d. Add an event listener to this loader. Have it listen for Event.COMPLETE and have it trigger a function named loadCompletedHandler (just like in loadXMLfile.fla).

e. Write the function called loadCompletedHandler which receives an event labeled e (just like in loadXMLfile.fla).

f. Have that function assign the data from the XML file (which is the event's target), to the medalXML variable (just like in loadXMLfile.fla - except the name of the XML variable is different).

g. Write the line that calls the loadXMLFile to make the load happen. Put it anywhere in the file, but not inside a function - it needs to run when the file first loads:

loadXMLFile();

h. Comment out the part of your code where you previously populated medalXML (remember you can use /* and */ to comment out several lines at once).

i. But you still want the medalXML variable so write a new line that instantiates that variable:

var medalXML:XML;

j. Test your application - it should act just as it did before - the info box should pop up when you hover over a circle and the data in that info box should be correct. But now it's coming from medal.XML.xml rather than from within the Flash file.

If you get this error:

it probably means that something's wrong with your XML file or you haven't stored it in the same location as your fla file.

Please zip your flash and xml file and submit it

FINAL PRODUCT: Medals_9_XML.zip

SUMMARY

creating an XML file

create a structure that fits the data and follows the rules for XML, then fill it in with data

referring to data in an XML file

shown in the code module "introToXML.fla"

use the @ symbol to access attributes

parsing text

pulling out text from a larger string (in this case using the substr method).

loading an xml file

demonstrated in the 'loadXML.fla' code module

essential elements are the loader object and the complete event

using trace statements to develop & debug your code

you used trace statements to see what was happening when you referenced parts of an XML object and to see if you were parsing text correctly