| 
  Introduction to XML in Flash by senocular
 
 Example: Flash MX 2004 Classes DirectoryThis example will list out the contents of the 
                                  Classes folder in the Flash MX 2004 install 
                                  directory. Can you guess the format of this 
                                  information? Do I even need to ask? Yup, XML. 
                                  The XML contains the full contents of the Classes 
                                  folder, each file and folder and each file and 
                                  folder within those folders and so on until 
                                  there's no more files or folders left to file 
                                  or fold. A recursive function (which even includes 
                                  a loop on top of everything else) is then used 
                                  to list out the contents of each folder and 
                                  is re-called on if any item is itself a folder 
                                  thereby listing its contents. And this happens 
                                  until there is nothing left to file or fold!
 As an added bonus to this example, we'll make 
                                  the folders expandable and collapsible. This 
                                  way you're not forced to look at all of the 
                                  files at once; you can be selective. And we 
                                  all know selection is a good thing. When all 
                                  done and through, you get the following end 
                                  result:.  
                                   [ 
                                  flash mx 2004 classes directory ]   
                                  
                                     
                                      |  | Note: Class Listing Lag |   
                                      | 
                                          
                                             
                                              | Given 
                                                  the sheer number of icons attached 
                                                  for this example, there will 
                                                  be a little bit of lag when 
                                                  the XML is loaded and the directory 
                                                  listing is created. As a precaution, 
                                                  should you ever decide to create 
                                                  something similar, you may wish 
                                                  to start with all directories 
                                                  closed loading in the icons 
                                                  only when that directory is 
                                                  opened. For simplicity's sake, 
                                                  here, it was just easier to 
                                                  add them all at once. |  |    XML StructureThere technically isn't much to the XML that 
                                  makes up this example. You're dealing with files 
                                  and directories, each with a name and type where 
                                  type determines icon. That's basically two different 
                                  kinds of elements with two different kinds of 
                                  data. The most important aspect of the XML is 
                                  the structure. Folders contain files and other 
                                  folders so folder elements will have file and 
                                  folder element children. Directories within 
                                  other directories can too have their own files 
                                  and directories and so on and so forth. So what 
                                  you get is a lot of nested directories. Here's 
                                  the XML:
 mx04_classes.xml It should look a little something like the 
                                  following (the entire file is not shown here): 
                                  <?xml version="1.0"?><directory 
                                    name="Classes" 
                                    type="directory">
                                    <file name="Accessibility.as" 
                                      type="actionscript" 
                                      /><file name="Array.as" 
                                      type="actionscript" 
                                      /><file name="AsBroadcaster.as" 
                                      type="actionscript" 
                                      /> . . . Starting from the classes directory in a Flash 
                                  MX 2004 install, you get a listing of all the 
                                  files and directories that are within complete 
                                  with name and type. To generate this list, I used this simple PHP 
                                  script: 
                                  <?phpfunction ExportDirectoryXML($base, 
                                    $indent){
                                    if ($dir 
                                      = @opendir($base)){
                                      while 
                                        ($file 
                                        = readdir($dir)){
                                        if ($file{0} 
                                          != "."){
                                          if 
                                            (is_dir($base 
                                            . "/" 
                                            . $file)){
                                            echo 
                                              "$indent<directory 
                                              name=\"$file\" type=\"directory\">\n";ExportDirectoryXML($base 
                                              . "/" 
                                              . $file, 
                                              $indent."\t");echo 
                                              "$indent</directory>\n"; }else 
                                            echo 
                                            "$indent<file 
                                            name=\"$file\" type=\"actionscript\" 
                                            />\n"; } }closedir($dir); } } $directory 
                                    = "[DIRECTORY 
                                    PATH GOES HERE]"; echo "<html><body><pre>\n";ExportDirectoryXML($directory, 
                                    "");echo "\n</pre></body></html>";?> This generated the directory structure in markup 
                                  which I then saved it to a XML file. It's that 
                                  file which is loaded by the Flash movie (the 
                                  movie loads a files separate from the script 
                                  though such a script could be used to load XML 
                                  like this dynamically from a server). If you'll 
                                  notice, it uses a recursive function as well. Preparing the Flash FileThis Flash file is really no more complicated 
                                  than the others before it, at least not in setting 
                                  up. Scripting is a little more involved. Otherwise, 
                                  in terms of screen elements, you're not dealing 
                                  with much more than about 3 different elements: 
                                  a movie clip for containing the full file listing, 
                                  an attached clip to represent a directory item 
                                  (a file or directory), and a scrollbar.
 The other two parts are the directory items 
                                  and the movie clip to contain them. The movie 
                                  clip used to contain them is just an empty clip 
                                  called listing_mc. Nothing much in terms of 
                                  preparation goes into that. However, to keep 
                                  it masked, it is placed under a graphic that 
                                  hides content scrolling inside. listing_mc itself 
                                  isn't masked masked, it's just being 
                                  hidden by being beneath this graphic. 
 [ 
                                  listing_mc beneath movie graphic interface ] Next it's just a matter of making the movie 
                                  clip that is to be attached and representative 
                                  as a directory item. This will be used for both 
                                  files and directories when added to the listing_mc. 
                                  This movie clip has three parts: an icon, a 
                                  text field for a name, and an underlying button 
                                  used to select it. This example uses the button 
                                  to open and close directories only, but ideally 
                                  it would add interaction to the files as well. 
 [ 
                                  item mc for each directory item ] Take note that the registration point for this 
                                  movie clip is in the upper left. This will be 
                                  important later on when positioning each item 
                                  in the display. This will be linked as "directory_item" 
                                  in the library so that it can be attached dynamically 
                                  when needed. Since this is used for all directory items, 
                                  files (of any kind) and directories, it will 
                                  need to facilitate the needs and differences 
                                  of each. The text field is no problem since, 
                                  as dynamic text, it can be changed easily at 
                                  any time. The icon, however, is a little more 
                                  difficult. The icon is actually another movie 
                                  clip with its own collection of frames inside. 
                                  These frames contain each of the icon graphics 
                                  needed for the file listing, the first frame 
                                  being a directory. For this example, there's 
                                  only one other file type so frame 2 is an ActionScript 
                                  file icon. Each frame also has a frame label 
                                  named after its icon type. This allows navigation 
                                  to any particular icon much more straight forward 
                                  using a name rather than a number. This name, 
                                  conveniently, should reflect the string used 
                                  to identify type in the XML document. 
 [ 
                                  label frames for each icon based on type in 
                                  xml ]   Now, whenever one of these clips is attached 
                                  as a directory item, it can be given a name 
                                  and have its icon switched to whatever type 
                                  is necessary. ActionScriptFor the most part with this example, 
                                  you get another squirrel finder script-wise. 
                                  This too revolves around generating a list of 
                                  movie clips or buttons based on XML. However, 
                                  here, recursive functions are going to be used 
                                  to allow directory listings to be created for 
                                  each other directory within another directory 
                                  listing. So it's like taking the squirrel finder 
                                  and change some of its buttons to be other instances 
                                  of a squirrel finders.
 The most difficult aspect of the file listing 
                                  is arranging the items in the view. Because 
                                  of the ability to open and close directories, 
                                  it means that whole groups of items will have 
                                  to move either up or down in response to more 
                                  items being displayed from the opening or closing 
                                  of directories. Instead of attaching items using 
                                  a variable to control spacing, a new technique 
                                  is used. This technique positions based on bounding 
                                  area moving lower items to the bottom of the 
                                  items above them. This way, should any items 
                                  be added or removed, basically, you just move 
                                  the item directly below that change where all 
                                  items below it can just reposition themselves 
                                  based on where they should be in respect to 
                                  the the position of item above them. We'll get to that script in a second, but first 
                                  lets look at the definition of the XML instance. 
                                  var directory_xml 
                                    = new 
                                    XML();directory_xml.ignoreWhite 
                                    = true;directory_xml.onLoad 
                                    = function(success){
                                    if (success){
                                      GenerateFileListing(this, 
                                        listing_mc);scrollbar.setTarget(listing_mc, 
                                        view_mc._y, 
                                        view_mc._height); }else 
                                      trace("Error 
                                      loading XML file"); } directory_xml.load("mx04_classes.xml"); The directory_xml variable represents the XML 
                                  instance. It loads "mx04_classes.xml" 
                                  using load and has an onLoad which, upon success, 
                                  runs a function called GenerateFileListing passing 
                                  in itself and the listing_mc (and of course 
                                  there's that scrollbar action in there too). 
                                 
                                  GenerateFileListing(this, 
                                    listing_mc); As you might imagine, GenerateFileListing creates 
                                  a listing of files based on xml (this) in a 
                                  movie clip (listing_mc). Here is what GenerateFileListing 
                                  looks like: 
                                  function GenerateFileListing(directory_node, 
                                    target_mc){
                                    var directory_mc 
                                      = target_mc.createEmptyMovieClip("directory_mc", 
                                      1);SetAtBottomOfParent(directory_mc);directory_mc._x 
                                      += item_indent;directory_mc.depth 
                                      = 0; var contents 
                                      = directory_node.childNodes;var item_mc, 
                                      last_item_mc;for (var 
                                      i=0; 
                                      i<contents.length; 
                                      i++) 
                                      { 
                                      item_mc 
                                        = directory_mc.attachMovie ("directory_item","item"+directory_mc.depth, 
                                        directory_mc.depth);directory_mc.depth++; item_mc.name_txt.text 
                                        = contents[i].attributes.name;item_mc.icon_mc.gotoAndStop(contents[i].attributes.type); if (last_item_mc 
                                        == undefined) 
                                        directory_mc.firstChild 
                                        = item_mc;else item_mc.previousSibling 
                                        = last_item_mc;last_item_mc.nextSibling 
                                        = item_mc;last_item_mc 
                                        = item_mc; if (contents[i].attributes.type 
                                        == "directory"){
                                        item_mc.select_btn.onPress 
                                          = Fold;GenerateFileListing(contents[i], 
                                          item_mc); } ArrangeContents(directory_mc); } }   The basic break down is as follows: 
                                  create and position an empty movie 
                                    clip to hold the directory's contentsloop through the children of the 
                                    node passed (representing the directory) 
                                    attach an item movie clip for 
                                      each child in that nodeassign name and other properties 
                                      and change icon based on item typeif type is a directory, call 
                                      the function again passing in the node representing 
                                      the item and the clip created for itposition the item Due to the fact that movie clips are being 
                                  used as directories (and files) and since movie 
                                  clips can contain other movie clips within them, 
                                  it seems perfect sense to maintain a directory's 
                                  own contents by keeping them within that directory's 
                                  movie clip as child movie clips. However, given 
                                  that the option of hiding those child movie 
                                  clips exists, it would be further beneficial 
                                  to keep all of those child movie clips within 
                                  one single movie clip (as a child of the directory). 
                                  That would allow us an easy way to get rid of 
                                  every single one of those movie clips at any 
                                  given time simply by removing hiding or that 
                                  single movie clip in which they all exist. This is the initial command of GenerateFileListing, 
                                  creating that empty movie clip for directory 
                                  contents to exist.  
                                  var directory_mc 
                                    = target_mc.createEmptyMovieClip("directory_mc", 
                                    1);SetAtBottomOfParent(directory_mc);directory_mc._x 
                                    += item_indent;directory_mc.depth 
                                    = 0; It does this within the passed target_mc which, 
                                  initially, is the listing_mc on the main timeline. 
                                  Other commands such as SetAtBottomOfParent and 
                                  the assignment of _x (based on item_indent, 
                                  a variable defined earlier on the main timeline) 
                                  manage its position while a depth variable is 
                                  set to manage the depths of clips being attached 
                                  within. So right away, when the XML first loads, before 
                                  listing_mc gets any item movie clips attached 
                                  to it, it gets an empty clip which is to be 
                                  treated as a content holder for a collection 
                                  of directories and files within a directory. 
                                  This means listing_mc itself only gets one movie 
                                  clip added to it. All contents within listing_mc 
                                  end up going in that movie clip. Also, every 
                                  directory item thereafter will too get its own 
                                  empty movie clip when a recursive call to GenerateFileListing 
                                  is made to generate its file contents. What 
                                  you end up getting is something along the lines 
                                  of this in terms of movie clip structure: 
 [ 
                                  movie clips in movie clips for directory structure 
                                  ] Now, if you'll imagine removing or hiding any 
                                  one of those movie clips holding one of those 
                                  directory's contents, you can see how the effects 
                                  would be similar to closing that directory in 
                                  a directory view which is exactly what we're 
                                  after.  All that remains is getting the contents in 
                                  each directory as needed, and that's what the 
                                  following loop lets us do. 
                                  var contents 
                                    = directory_node.childNodes;var item_mc, 
                                    last_item_mc;for (var 
                                    i=0; 
                                    i<contents.length; 
                                    i++) 
                                    {
                                    // ... } First the child nodes are put into a friendly 
                                  variable named contents. These are the nodes 
                                  within the current directory node initially 
                                  passed into GenerateFileListing. A few other 
                                  variables being used within the loop are also 
                                  declared here for safe keeping. Then the for 
                                  loop is used to cycle through each. In the loop, each item, directory or file, 
                                  is immediately created within the directory_mc 
                                  movie clip (the empty one created to hold all 
                                  contents of a directory). 
                                  item_mc = 
                                    directory_mc.attachMovie("directory_item", "item"+directory_mc.depth, 
                                    directory_mc.depth);directory_mc.depth++; Then, the text and icon are set for that item. 
                                  item_mc.name_txt.text 
                                    = contents[i].attributes.name;item_mc.icon_mc.gotoAndStop(contents[i].attributes.type); This is pretty straight-forward. Simply take 
                                  the text from attributes the current node of 
                                  the loop. The text comes from the name attribute 
                                  and is placed into the name_txt text field while 
                                  the icon_mc is told to go to and stop on the 
                                  frame label specified by the type attribute. 
                                  Directly after this, however, are some assignments 
                                  that are less obvious. 
                                  if (last_item_mc 
                                    == undefined) 
                                    directory_mc.firstChild 
                                    = item_mc;else item_mc.previousSibling 
                                    = last_item_mc;last_item_mc.nextSibling 
                                    = item_mc;last_item_mc 
                                    = item_mc; What we have here is actually the borrowing 
                                  of naming conventions used by XML to help handle 
                                  the movie clip positioning of child movie clips 
                                  within a directory. Since item movie clips have 
                                  to be aware of their preceding item in order 
                                  to position themselves to it, a reference to 
                                  that item is added within the movie clip. This 
                                  is defined as previousSibling and handled through 
                                  the last_item_mc variable defined prior to the 
                                  loop which following this assignment becomes 
                                  the current item. Similarly, nextSibling is 
                                  used to be able to start at the top of a list 
                                  of directory items and work our way down in 
                                  order to perform the positioning of each in 
                                  the correct order. This will work much in the 
                                  same way the alternative approach to the squirrel 
                                  finder example did. The directory_mc too gets 
                                  a reference to a movie clip, the first in the 
                                  list (when last_item_mc is undefined, it means 
                                  the current item is the first) in order to be 
                                  able to start a chain of positioning beginning 
                                  with it's first item listed. Putting this into 
                                  motion is handled by four other functions that 
                                  are used for directory opening and closing. Next in the loop is the recursive call, or 
                                  at least the check to see if a recursive call 
                                  to GenerateFileListing is needed. When it is 
                                  needed is when the type of the current item 
                                  is of type "directory." 
                                  if (contents[i].attributes.type 
                                    == "directory"){
                                    item_mc.select_btn.onPress 
                                      = Fold;GenerateFileListing(contents[i], 
                                      item_mc); } If so, a button action is added (using Fold, 
                                  covered shortly) and the call is made. This 
                                  particular call to GenerateFileListing uses 
                                  the current node in the loop and the current 
                                  item movie clip. Each exists within the previous 
                                  arguments passed in to GenerateFileListing during 
                                  the current call. So here, and in many cases, 
                                  the nesting of the function calls reflects the 
                                  nesting of the objects in which it affects. 
 [ 
                                  generatefilelisting called for each directory 
                                  ] After each child is created, and if a directory 
                                  all its children or contents are created, then 
                                  it is positioned with a final 
                                  ArrangeContents(directory_mc);   And that brings us to those functions used 
                                  to handle item position and directory opening 
                                  and closing. They are as follows: 
                                  function SetAtBottomOfParent(below_mc){
                                    if (below_mc._parent._height) 
                                      {
                                      below_mc._y 
                                        = below_mc._parent.getBounds(below_mc._parent).yMax; } }function SetBelow(below_mc, 
                                    top_mc){
                                    if (top_mc 
                                      != undefined) 
                                      {
                                      below_mc._y 
                                        = top_mc.getBounds(top_mc._parent).yMax; } }function ArrangeContents(directory_mc){
                                    var item 
                                      = directory_mc.firstChild;if (item 
                                      != undefined){
                                      while 
                                        (item 
                                        = item.nextSibling){
                                        SetBelow(item, 
                                          item.previousSibling); }var parent_container 
                                        = directory_mc._parent._parent;if (parent_container 
                                        != undefined) 
                                        ArrangeContents(parent_container); } }function Fold(){
                                    if (this._parent.directory_mc._visible){
                                      this._parent.directory_mc._visible 
                                        = false;this._parent.directory_mc._yscale 
                                        = 0; }else{
                                      this._parent.directory_mc._visible 
                                        = true;this._parent.directory_mc._yscale 
                                        = 100; }ArrangeContents(this._parent._parent);scrollbar.contentChanged(); } The first two functions, SetAtBottomOfParent 
                                  and SetBelow are used to position the individual 
                                  empty directory movie clips and attached item 
                                  clips (respectively). 
                                  function SetAtBottomOfParent(below_mc){
                                    if (below_mc._parent._height) 
                                      {
                                      below_mc._y 
                                        = below_mc._parent.getBounds(below_mc._parent).yMax; } }function SetBelow(below_mc, 
                                    top_mc){
                                    if (top_mc 
                                      != undefined) 
                                      {
                                      below_mc._y 
                                        = top_mc.getBounds(top_mc._parent).yMax; } } Each function vertically positions a passed 
                                  clip, below_mc, to be either below its _parent 
                                  or another movie clip through the use of the 
                                  getBounds method. As you might be able to imagine, 
                                  SetBelow will be useful with a directory item 
                                  and its previousSibling property. And what do 
                                  you know, the next function, ArrangeContents, 
                                  does exactly that: 
                                  function ArrangeContents(directory_mc){
                                    var item 
                                      = directory_mc.firstChild;if (item 
                                      != undefined){
                                      while 
                                        (item 
                                        = item.nextSibling){
                                        SetBelow(item, 
                                          item.previousSibling); }var parent_container 
                                        = directory_mc._parent._parent;if (parent_container 
                                        != undefined) 
                                        ArrangeContents(parent_container); } } ArrangeContents gets passed to it a directory 
                                  container movie clip. If it has a firstChild, 
                                  it would mean there are movie clips within it. 
                                  This would have been assigned in the for loop 
                                  attaching the clips. Then positioning would 
                                  be performed, otherwise the function just ends. To position items, a while loop is used to 
                                  cycle through each sibling of the movie clips 
                                  starting with the first in the directory_mc. 
                                  SetBelow is then used to position that sibling 
                                  below the sibling before it. Now, the thing to remember is that if you reposition 
                                  the contents of a directory, other directories, 
                                  such as the one containing the directory in 
                                  question, will have to react and reposition 
                                  their content as to prevent gaps in the directory 
                                  layout. ArrangeContents handles this by calling 
                                  itself (recursively) on the directory_mc's _parent._parent 
                                  if it exists, ultimately correcting all movie 
                                  clip positions that the initial change could 
                                  have effected. (_parent._parent is used since 
                                  _parent reflects the attached item clip used 
                                  for the directory and we want the directory 
                                  clip in which it exists or its _parent clip). That brings us to the remaining Fold function 
                                  which is assigned as an onPress event for directories. 
                                  function Fold(){
                                    if (this._parent.directory_mc._visible){
                                      this._parent.directory_mc._visible 
                                        = false;this._parent.directory_mc._yscale 
                                        = 0; }else{
                                      this._parent.directory_mc._visible 
                                        = true;this._parent.directory_mc._yscale 
                                        = 100; }ArrangeContents(this._parent._parent);scrollbar.contentChanged(); } This shows or hides directory contents. Because 
                                  this is assigned to a button within an attached 
                                  item movie clip, _parent is used to access the 
                                  directory_mc within that item. Then the directory 
                                  is hidden and set to have a _yscale 
                                  of 0. The inclusion of the _yscale is necessary 
                                  because, despite the fact that this movie clip 
                                  may be invisible, its height would still register 
                                  as part of its parent's height. This means that 
                                  hiding the clip alone will not be enough for 
                                  ArrangeContents to recognize there being a gap. 
                                  The clip would actually have to be literally 
                                  folded up. When that happens, ArrangeContents 
                                  is called and all movie clips get to react to 
                                  the new change in position, whether it was movie 
                                  clips being shown or being hidden. 
   |