Bookmark now!

AddThis Social Bookmark Button

Most popular

The most viewed tutorials in April:

  1. Best dynamic image gallery
  2. Loading external JPG images
  3. Ultimate preloader

Advertisements

Amazing video loops, stunning photo galleries, video and audio players ready to go! Smooth, amazing flipNavigation system!

Making the ultimate dynamic image gallery in Flash 8 — part 9

12.5. Parsing XML: Retrieving gallery data (titles and descriptions) and creating the menu section buttons dynamically

Below is the parseGalleries() function which serves to parse the XML data and store it in various variables. It looks big... scary... doesn't it? :-) No, it is not! It is just a little bit long, but everything inside it is perfectly logical and understandable and I will explain it to you in no time at all! So let's get on with it.

function parseGalleries():Void {
if (imageGallery.firstChild.nodeName == "galleries") {
var rootNode:XMLNode = imageGallery.firstChild;
for (i=0; i<rootNode.childNodes.length; i++) {
if (rootNode.childNodes[i].nodeName == "gallery") {
currentGallery = rootNode.childNodes[i];
imagesInGallery.push(currentGallery.childNodes.length);
galleryNames.push(currentGallery.attributes.title);
galleryIntros.push(currentGallery.attributes.intro);
currentGalleryTitle = rootNode.childNodes[i].attributes.title;
currentGalleryButton = galleryMenu_mc.buttonsHolder_mc.attachMovie("gallery section button", "galleryButton"+i, galleryMenu_mc.buttonsHolder_mc.getNextHighestDepth());
currentGalleryButton._x = 0;
currentGalleryButton._y = galleryBtnVSpace*i;
currentGalleryButton.sectionTitle_txt.text = "0"+(i+1)+" "+currentGalleryTitle.toUpperCase();
for (j=0; j<currentGallery.childNodes.length; j++) {
if (currentGallery.childNodes[j].nodeName == "image") {
currentDescription = currentGallery.childNodes[j].firstChild.toString();
descriptions.push(currentDescription);
}
}
}
}
}
numberOfGalleries = i;
enableButtons(numberOfGalleries);
}

As you probably noticed, there is a semicolon (:) followed by the ActionScript keyword Void in the first line of function's code.

function parseGalleries():Void {

This keyword tells Flash that the parseGalleries() function does not return a value. It is good to specify this, although it isn't obligatory. When you have a function that does return a value to the caller, you have to specify this. For example, you may have a function which serves to perform a simple mathematical calculation and so instead of Void, you would write Number after the function's name and the semicolon, because the function would return a numerical value.

Inside the function, almost all of the code (except two lines) is contained within an if conditional statement:

if (imageGallery.firstChild.nodeName == "galleries") {

Notice that I said an if conditional statement, not an if/else one. Why? Because there is no "else" situation here. The if conditional is used here as to say to Flash "When you find the root node with the name galleries, do the following". Also, there is no else, because Flash will find the node named galleries because you created it in the XML file. This is a fail-safe procedure! :-)

Remember, an XML file has only one root node. So when you say imageGallery.firstChild.nodeName, you tell Flash to look up the name of the root node — it is the first child of the XML file (which was converted to XML object when loaded into Flash) itself.

<?xml version="1.0"?>
<galleries>
...
</galleries>

After that, a shortcut variable called rootNode is created that points to this root node:

var rootNode:XMLNode = imageGallery.firstChild;

This is much like the variables that you have created at the very start of your ActionScript code to be able to reference movie clips and buttons in a shorthand and practical manner.

Next, you have a for loop that is used to loop through all the child nodes of the root node.

for (i=0; i<rootNode.childNodes.length; i++) {

To be sure that Flash really loops through all the child nodes of the root node, you set the condition of the loop as follows: i must be less than the total number of child nodes (rootNode.childNodes.length). Why less than and not equal to the number of child nodes? Because the loop starts with i set to zero. Like the position of elements in an array and the position of characters in a string, for example, the XML nodes are also counted starting from zero. It is just how it's done in ActionScript and the majority of programming languages.

What follows is an if conditional statement, again. Exactly like for the root node, you tell Flash here to look for child nodes of the root node that are called gallery.

if (rootNode.childNodes[i].nodeName == "gallery") {

<?xml version="1.0"?>
<galleries>
<gallery title="architecture" intro="These are the photos of various buildings in the cities, towns and villages I visited during my voyages.">
...
</gallery>
<gallery title="essays" intro="A collection of various photos which either do not fit any other category - experiments and such.">
...
</gallery>
</galleries>

The variable i will be replaced by the number of the current loop, of course: 0, 1, 2, 3, etc... so all child nodes will be parsed.

The gallery that is currently being parsed is stored in the currentGallery variable:

currentGallery = rootNode.childNodes[i];

This si done to be able to reference it more easily in the next few lines of code.

Next, the construct currentGallery.childNodes.length is used to pull out the number of images in the current gallery section. This value is in turn stored inside the imagesInGallery array (which you created when you defined all the variables) via the push() method of the Array object.

imagesInGallery.push(currentGallery.childNodes.length);

The imagesInGallery array is very important because the values stored inside it (the number of images in each gallery section) will be used later to tell Flash how many thumbnails should be loaded for a given gallery section.

Next, the value of the title attribute for the current gallery node is extracted and stored inside the galleryNames array via its push() method. This value will be later used to tell Flash what gallery section the user has chosen and also to give Flash the proper path to the section's folder.

galleryNames.push(currentGallery.attributes.title);

Using the same procedure as above, the value of the intro attribute is extracted and stored inside the galleryIntros array. These values will be used to show what's the current gallery section about — this is the description text which will appear in the big dynamic text field once the user clicks on a gallery section button.

galleryIntros.push(currentGallery.attributes.intro);

Next, by using the procedure that you understand well by now, the value of the title attribute of the current gallery section is extracted and stored inside the currentGalleryTitle variable. There is an important distinction here: before, the same attribute's value was extracted and placed inside an array along with its counterparts from other gallery nodes and now it is placed inside a simple, plain variable. This is done because this variable's value will be used very soon.

currentGalleryTitle = rootNode.childNodes[i].attributes.title;

And now, the gallery section button movie clip is being extracted from the Library dynamically and placed inside the gallery menu:

currentGalleryButton = galleryMenu_mc.buttonsHolder_mc.attachMovie("gallery section button", "galleryButton"+i, galleryMenu_mc.buttonsHolder_mc.getNextHighestDepth());

The gallery section button that you have created earlier is being attached inside the gallery menu, more specifically to the buttonsHolder_mc empty movie clip inside it: galleryMenu_mc.buttonsHolder_mc.attachMovie. As you remember, thsi is the empty clip beneath the mask in the gallery menu movie clip. The attachMovie() method has 3 parameters:

  1. The Linkage identifier which is used to pull a movie clip dynamically out of the Library: "gallery section button" in this case.
  2. The new instance name of the newly attached movie clip. This will be different for each gallery section of course, so it has to be created dynamically: "galleryButton"+i. So, as the loop goes on, this instance name will be galleryButton0, galleryButton1, galleryButton2, etc.
  3. The depth level of the attached movie clip. This parameter must also be different for each attached movie clip, because if it stays the same, each subsequent movie clip will replace the previous one, because there cannot be two movie clips present on a same depth level. So, the convenient getNextHighestDepth() method is used to place each movie clip on a separate depth level. Think of the depth levels as invisible layers inside the empty movie clip where you are attaching your buttons.

And the currentGalleryButton variable is used as a shortcut for this newly attached movie clip — the current gallery section button. And now, you see why it is very practical to use such "variable shortcuts" — there are many things that you will now do with the attached movie clip. The first one is positioning:

currentGalleryButton._x = 0;
currentGalleryButton._y = galleryBtnVSpace*i;

The first line above serves to position each gallery section button horizontally, via the movie clip _x property, which defines its horizontal position in relation to the left edge of the stage, expressed in pixels. This value is 0 (zero) for each gallery section button, because they must be aligned flawlessly inside the menu.

The horizontal position of the gallery sections buttons.

On the other side, the vertical position of each section button inside the gallery menu is determined dynamically, because you have to put some space between them: galleryBtnVSpace*i. If you remember, when you defined all the variables, the galleryBtnVSpace was set to the value of 23. Like I said, I chose this value in relation to the height of the buttons, to be able to space them nicely. Since in every loop iteration this value is multiplied by i, the position of buttons will be: 0, 23, 46, 69, etc.

The vertical positions of gallery menu sections buttons.

And now you must define the label for the current gallery section button:

currentGalleryButton.sectionTitle_txt.text = "0"+(i+1)+" "+currentGalleryTitle.toUpperCase();

As you can see above, this label is composed of a few things, all were my choice. I could have just slapped the plain gallery section title over each button, but I wanted to add numbers and also put all the letters into capitals:

And now comes the for loop which passes through each image element inside each gallery node:

for (j=0; j<currentGallery.childNodes.length; j++) {
if (currentGallery.childNodes[j].nodeName == "image") {
currentDescription = currentGallery.childNodes[j].firstChild.toString();
descriptions.push(currentDescription);
}
}

Since this loop is contained within the main loop, you must naturally change the variable: it is j here. The condition for the loop to continue the iterations is that j, which starts at 0, must be lesser than the number of the child nodes of the current gallery node, i.e. the number of image nodes.

Again, you have an if which checks that the name of each node looked at is indeed "image" and not something else. Like before, this is a way of telling Flash to look at precisely these nodes.

<?xml version="1.0"?>
<galleries>
<gallery title="architecture" intro="These are the photos of various buildings in the cities, towns and villages I visited during my voyages.">
<image>Dallas.</image>
<image>Tresnjevka. I love the atmosphere on this one.</image>
<image>Motovun.</image>
<image>New York.</image>
<image>Paris.</image>
</gallery>
<gallery title="essays" intro="A collection of various photos which either do not fit any other category - experiments and such.">
<image>Color mayhem!</image>
<image>The sleeping monster.</image>
<image>Let me out!</image>
<image>A barrel on the side of the trail.</image>
<image>Subterranean passage.</image>
<image>A train in snow.</image>
</gallery>
</galleries>

Then, as each image node is found, its first child's value is converted to a String (text) value.

currentDescription = currentGallery.childNodes[j].firstChild.toString();

For example, the value of the first child node of the fourth image node in the first gallery node above is New York. And since this is an XML node, it has to be converted to a String value, for Flash to be able to display in the dynamic text field later and not to spit out a type mismatch error. Yes, the text between the <image> opening and closing tag is considered the image node's first child.

And the text (which is the description of each particular image) is then stored inside the descriptions array.

descriptions.push(currentDescription);

Finally, after the big for loop has ended after going through all the gallery nodes, the value of i, which matches the number of galleries (sections) is stored inside the numberOfGalleries variable.

numberOfGalleries = i;

This number will be used later to determine the number of gallery section buttons and loop through all of them.

And finally, the enableButtons() function is called and the variable numberOfGalleries is passed to it.

enableButtons(numberOfGalleries);

Whew! That was all about XML parsing and data extraction! Cool! Jump over to the next page to see how the functionality of the gallery menu section buttons is created.