Debugging Flash


The Flash application includes several useful tools to examine and tweak our work. The Movie Explorer, for example, is a good way to get the big picture of the structure of a project. At the other extreme is the debugger, which displays the minute details of our project. It allows us to directly examine the operation of Flash code even as it is running!

Debugger

We use the debugger to pry apart our XML object (Figure 8.1). While all the data is visible, it is buried in a cascade of empty pointers. By collapsing the list, we can look at the root object:


graphics/08infig02.gif


Figure 8.1. Debugger

graphics/08fig01.gif

The root node is an element node ( nodeType =1) with an empty attribute array, no parent, no siblings, no name , and no value. It has special properties that other elements do not. It has declarations ( xmlDecl and docTypeDecl ), and flags ( loaded and status ).

The childNodes array shows a single undefined node (0) ”not very useful. But by opening the lastChild object, we see


graphics/08fig01a.gif


This daughter node also is a node of the element type with an empty attribute array, no siblings, and no value. But it does have a name: score.


graphics/08fig01b.gif


Take a moment and consider this point: An element node directly contains only the data on the tags themselves , not the data between the tags:

XML
 <?xml version="1.0" encoding="UTF-8"?><score>122</score> 

Although the childNodes array appears empty, it has a lastChild. In that daughter node we can at last find the high score itself. Open it and see the final dead end in the chain of nodes. It has neither children, siblings, nor attributes. It is a leaf node.

Unlike the other two nodes, this is not an Element node (Type 1) but a Type 3 ”a text (CDATA) node. It is, at last, content:

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

It is a pleasure to have a debugger in the Flash authoring environment, and it brings a sense of professionalism that is sorely needed. But the truth is, it is not very useful for students of XML.

Trace

It is a brutal struggle to try to follow the structure of XML in the debugger. It is inside out and follows a perverse logic. Instead, we will rely on trace statements. Trace statements are a crude and dependable way to examine memory. If we add these three lines, we get a clear picture.

ActionScript
 if (this.highscore.loaded) {       trace( highscore.toString());       trace( highscore.firstChild.nodeType);       trace( highscore.firstChild.nodeName);       trace( highscore.firstChild.nodeValue);       score = highscore.;       stop();    } 

We see that the first node is of Element type and has the name score.

Output
 <?xml version="1.0" encoding="UTF-8"?><score>122</score> score 1 null 

We can use trace to check score 's daughter node ”the granddaughter of the root node highscore.

ActionScript
 trace( highscore.firstChild.firstChild.nodeType); trace( highscore.firstChild.firstChild.nodeName); trace( highscore.firstChild.firstChild.nodeValue); 

As we anticipate, it is a nameless text node, containing the actual score as a string.

Output
 3 null 122 

New Code Means New Bugs

Now that we can find the data and the variable name with which it is associated, we can recreate the function of loadVariables() . We can have XML automatically create or update any variables it finds, turning

XML
 <score>122</score> 

into

ActionScript
 score=122 

with a (long) line of code:

ActionScript
 if (this.highscore.loaded) {       eval( highscore.firstChild.nodeName.toString())         = highscore.firstChild.firstChild.nodeValue;       stop();       } 

Try it ”it works nicely !

The eval() operator tells ActionScript to treat the string ...nodeName as the name of a variable ”to create it if necessary ”and to assign to it the value of ...nodeValue . This generically approximates the functionality of loadVariables() ”and it perpetuates the dangerous behavior we discussed moments ago. Variables are manipulated and generated within our namespace without our control.

The eval() operator introduces a new instability as well. It is very position-dependent. Unless the first node has the name score and its first node is the value we want, our XML loader will fail. It is all too easy to create an imperfect XML file. It is especially easy to unwittingly create extra text nodes from tiny bits of whitespace. Sometimes whitespace is inserted for legibility ”by coders used to the transparency of whitespace in Java, C, or HTML. Sometimes inconspicuous whitespace accidentally creeps in. Sometimes it is an artifact of the editor.

Let's take a different approach, one where we test before loading to be certain we have what we want.

ActionScript
 if (this.highscore.loaded) {   if(  highscore.firstChild.nodeName.toLowerCase() eq "score"    and highscore.firstChild.firstChild.nodeType==3){          score= highscore.firstChild.firstChild.nodeValue;          }     else{          score= "0000";   // Successful load of bad file.      }    stop();    } 

Debugging with DTD

This approach prevents us from loading any value unless it is tagged as a score. It is still very primitive, especially in terms of error recovery. So first we strengthen the data validation. We are testing to make sure that our XML contains an initial element called score with some content. We can easily build a DTD to validate such XML, which can be a useful tool for the publisher in eliminating bad files from the service.

But a DTD cannot validate the content of this element.

XML
 <score>Unavailable</score> 

This element is perfectly valid to the DTD and may seem appropriate ”even clever ”to the human who wants to publish it. But we know it will fail our display code (which can render only numerals), and it may fail future game logic that compares the player's score against the global high score.

This may seem like a lot of concern for obscure special cases in a marginal detail of an imaginary application ”and of course it is. Later, this kind of concern when applied to very visible details of important web sites will gain you a reputation for professionalism. Expect evenings filled with enjoyable social life rather than caffeine - powered all-nighters staring at a monitor and battling a horde of unanticipated assaults.

Let the DTD validate that the score is a number. To do so, we can move the data from the element's contents

XML
 <score>122</score> 

and make it instead an attribute of an empty element:

XML
 <highscore score="122"/> 

XML Debugger

Let's revisit our XML tracer. Time for an upgrade: We need to make attributes visible. The attributes of each XML node are listed in an associative array. An associative array (also called a hash ) can be thought of as a one-dimensional array that is indexed not by numbers but by keys. Keys are simple unique strings. A traditional one-dimensional array is a list of elements that are addressed by their order in the list, creating pairs of elements and indices. (The latter are calculated on the fly.) An associative array pairs keys and values. The order is unimportant, and even if the keys are numeric (a perfectly valid associative array), holes do no harm.

ActionScript
 if (xml.loaded) {   trace( xml.toString());   l=xml.childNodes.length;   trace( "----------"+ l +" nodes-------------");   for( var i=0; i<l; i++){     t=xml.childNodes[i].nodeType;     trace( "type      "+(t==1? "Element" :                          t==3? "Text" :                                ("unknown: "+Number(t))));     trace( "name      "+xml.childNodes[i].nodeName);     trace( "value     "+xml.childNodes[i].nodeValue);     for (name in xml.childNodes[i].attributes)       trace( "attribute " + name + ":  "                         +  xml.childNodes[i].attributes[name]);       if( ll=xml.childNodes[i].childNodes.length )         trace( " --------"+ ll +" subnodes-------------");       for( var ii=0; ii <ll; ii++){         t=xml.childNodes[i].childNodes[ii].nodeType;         trace( "  type. . .       etc.. 

This listing combines a series of upgrades, mostly to generalize this function and clarify its display. It still needs more ”especially when we move on to recursion in the next chapter. We will continue to develop this as a casual tool for poking into Flash's XML DOM. The following changes are included:

  • All graphics and sounds have been stripped out.

  • The name has been changed to xmltrace to prevent confusion.

  • The first three generations are displayed.

  • Node types are displayed better.

  • The child node tree is indented properly.

In addition to these fairly cosmetic changes, we have added code to scan through the attribute array. ActionScript includes a variation of the for statement that scans arrays:

ActionScript
 for (  var  in  arr  ) 

returns the next key of associative array arr as a string in the variable var. Our code traces both, with this result:

Output
 <?xml version="1.0" encoding="UTF-8"?><highscore score="122" /> ----------2 nodes------------- type      unknown: 0 name value   ................................ type      Element name      highscore value     null attribute score:  122 ................................ 

Making Use of the Insight

Now that we can find the attribute, let's put aside this experimental xmltrace code and return to the functional code for our trivia game. We use the attribute score from the element highscore.

ActionScript
 if (this.highscore.loaded) {  if(  highscore.firstChild.nodeName.toLowerCase() eq "highscore" ){          score =  highscore.firstChild.attribute[ "score" ];        //score = highscore.firstChild.firstChild.nodeValue;          } 

Notice that the new code is far more lucid than the line it replaces ”as well as more stable. But it hurts to throw away code; the temptation to rescue this commented-out line of old ActionScript is immense. We can save it with the time-honored programmer's friend: feature creep. We can show more than simply the score.

ActionScript
 if(  highscore.firstChild.nodeName.toLowerCase() eq "highscore" ){          score =  highscore.firstChild.attribute[ "score" ];          winner = highscore.firstChild.firstChild.nodeValue;          } 

Now we simply change the static text "worldwide high score" to dynamic text that links to the variable winner (Figure 8.2).

Figure 8.2. Adding a Winner Display

graphics/08fig02.jpg

Now if we supply an XML file with the winner's name, it will easily be broadcast to all the players. For very little effort (on the client side anyway) we improve the game value of the highscore feature, mixing bitter jealousy and sweet ambition into a recipe that heretofore included only a bland sense of generalized competition:

XML
 <highscore score="122">CHAMPION:  MARY T. O'BRIEN</highscore> 

When we read this new file, we see


graphics/08fig02a.jpg


This is a great feature to put into our client, but it needs one more touch. We want to be backward-compatible . Our client should be able to read XML generated without a winner's name. (It is already forward-compatible ”this new XML does not break the earlier client that does not read winner's names .)

ActionScript
 if( highscore.firstChild.nodeName.toLowerCase() eq "highscore" ){     score =  highscore.firstChild.attribute[ "score" ];     if (  highscore.firstChild.firstChild.nodeValue )         winner = highscore.firstChild.firstChild.nodeValue;     } 

It will only change the label on the high score box if there is text supplied by the XML.



Flash and XML[c] A Developer[ap]s Guide
Flash and XML[c] A Developer[ap]s Guide
ISBN: 201729202
EAN: N/A
Year: 2005
Pages: 160

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net