ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
XML Fingerspelling Quiz
http://www.actionscript.org/resources/articles/957/1/XML-Fingerspelling-Quiz/Page1.html
Michael Toy
I am a Junior at Wheaton College, I have just finished my first class in AS3. I have programmed a number of smaller projects, as well as a substantial bigger American Sign Language fingerspelling parser. I am a computer science major and enjoy learning languages, such as ML, Java, C, and most recently, AS3. 
By Michael Toy
Published on December 14, 2009
 
A quiz program for American Sign Language fingerspelling that loads words from an external XML file.

In this tutorial you will learn how to read from XML files in your Actionscript 3.0 programs, specifically in the context of a quiz program.  XML is a file type that is versatile in its application and implementation.  Basically, an XML file is a tree.  Here is an example. [XML file]  This is a list of strings, a simple document.  Each string is contained in a node of type STRING with an attribute of DATUM, which is the individual string (i.e. godfather – unicycle).

This program tests the users ability to read American Sign Language fingerspelling. There are two modes in this program; the default mode allows a user to input a word and view that word spelled out via fingerspelling. The second mode is a quiz mode that tests a user on how well he or she can read a word fingerspelled.


This first section imports the necessary library functions and then establishes the interface with the Sprites and textfields.

[as]package
{
    import flash.display.*;
    import flash.events.*;
    import flash.media.*;
    import flash.net.*;
    import flash.text.*;
    import flash.ui.*;
    import flash.utils.*;
  
    public class Fingerspeller extends Sprite
    {
        public function Fingerspeller()
        {
            var background:Sprite = new makeRectangle(0x000000, 30, 10, 330, 250);
            addChild(background);
          
            //Speed label
            var speedLabel:TextField = makeLabel(285, 58, 33, 15, 0x333ccc, "Speed");
            addChild(speedLabel);
          
            //Scorekeeper correct & incorrect textboxes
            var numCorrect:TextField = makeLabel(34, 200, 60, 18, 0x333ccc, "Correct: ");
            addChild(numCorrect);
            var numWrong:TextField = makeLabel(34, 220, 60, 18, 0x333ccc, "Incorrect: ");
            addChild(numWrong);
                  
            //Quiz toggle button
            var quiz:TextField = makeLabel(285, 200, 60, 15, 0x333ccc, "Quiz Me");
               quiz.addEventListener(MouseEvent.CLICK, quizListener);
            addChild(quiz);
          
            //Exit Quiz toggle button
            var exitQuiz:TextField = new makeLabel(285, 220, 60, 15, 0x333ccc, "Exit Quiz");
              exitQuiz.addEventListener(MouseEvent.CLICK, exitQuizListener);
            addChild(exitQuiz);
          
            //repeat button
            var repeat:TextField = new makeLabel(285, 180, 60, 15, 0x333ccc, "Repeat");
            repeat.addEventListener(MouseEvent.CLICK, repeatListener);
            addChild(repeat);
          
            //create the display rectangle for images/movies
            var rect:Sprite = makeRectangle(0xff00ff, 100, 50, 175, 131);
            //add the rectangle to the stage
            addChild(rect);
                      
            //rectangle to which buttons are added
            var rect2:Sprite = makeRectangle(0x333ccc, 285, 75, 35, 70);
            //add the rectangle to the stage
            addChild(rect2);
          
            //slow button
            var button1:Sprite = makeRectangle(0x00ffff, 287, 77, 30, 15);
            button1.buttonMode = true;
            button1.addEventListener(MouseEvent.MOUSE_DOWN, slowSpeed);
            addChild(button1);
                      
            //medium speed button
            var button2:Sprite = makeRectangle(0x00ffff, 287, 98, 30, 15);
            button2.buttonMode = true;
            button2.addEventListener(MouseEvent.MOUSE_DOWN, regSpeed);              
            addChild(button2);
                  
            //fast button
            var button3:Sprite = makeRectangle(0x00ffff, 287, 120, 30, 15);
            button3.buttonMode = true;
            button3.addEventListener(MouseEvent.MOUSE_DOWN, fastSpeed);
            addChild(button3);
                      
            //textbox for input
            var myText:TextField = makeLabel(130, 200, 100, 18, 0xff00ff, "");
            myText.border = true;
            myText.borderColor = 0x00ff55;
            myText.type = TextFieldType.INPUT;
            addChild(myText);
            
              //debugging textbox
            var debug:TextField = makeLabel(130, 220, 100, 18, 0xff00ff, "");
               debug.border = true;
            debug.borderColor = 0x00ff55;
            addChild(debug);
            
              //Instructional textbox
            var instruct:TextField = makeLabel(50, 20, 280, 18, 0xff00ff, "");
             instruct.border = true;
            instruct.borderColor = 0x00ff55;
            addChild(instruct);
          
            //textbox to highlight the selected speed button
            var highlight:TextField = makeLabel(0, 0, 30, 15, 0xff00ff, "");
               highlight.border = true;
            highlight.borderColor = 0x00ff55;[/as]

Each of these sections call one of two methods, makeLabel, which creates a new Sprite object, or makeLabel, which creates a new TextField object.  Here is the code for these functions:

[as]//make a rectangular Sprite
            function makeRectangle(color:Number, xPos:int, yPos:int, xSize:int, ySize:int):Sprite
            {
                var toReturn:Sprite = new Sprite();
                toReturn.graphics.lineStyle(1);
                toReturn.graphics.beginFill(color);
                toReturn.graphics.drawRect(xPos, yPos, xSize, ySize);
                return toReturn;
            }
          
            //make a textbox  
            function makeLabel(xPos:int, yPos:int, width:int, height:int, color:Number, text:String):TextField
            {
                var toReturn:TextField = new TextField();
                toReturn.x = xPos;
                toReturn.y = yPos;
                toReturn.width = width;
                toReturn.height = height;
                toReturn.background = true;
                toReturn.backgroundColor = color;
                toReturn.text = text;
                return toReturn;
            }[/as]

This will establish the windows and the interface for the user. The buttons will later have action listeners added to them in later functions.




Load the images of the letters into the program
Next I loaded the images into the program.  This is done by first embedding the images and then calling a function named makeHandshapeArray that then places each letter into the appropriate place in the array of images.

            //the embedding of the files into the code
            var a:Bitmap;
            [ Embed ( source = "a.jpg" ) ] var aClass:Class;
            var b:Bitmap;
            [ Embed ( source = "b.jpg" ) ] var bClass:Class;
            var c:Bitmap;
            [ Embed ( source = "c.jpg" ) ] var cClass:Class;
            var d:Bitmap;
            [ Embed ( source = "d.jpg" ) ] var dClass:Class;
            var e:Bitmap;
            [ Embed ( source = "e.jpg" ) ] var eClass:Class;
            var f:Bitmap;
            [ Embed ( source = "f.jpg" ) ] var fClass:Class;
            var g:Bitmap;
            [ Embed ( source = "g.jpg" ) ] var gClass:Class;
            var h:Bitmap;
            [ Embed ( source = "h.jpg" ) ] var hClass:Class;
            var i:Bitmap;
            [ Embed ( source = "i.jpg" ) ] var iClass:Class;
            var j:Bitmap;
            [ Embed ( source = "j.jpg" ) ] var jClass:Class;
            var k:Bitmap;
            [ Embed ( source = "k.jpg" ) ] var kClass:Class;
            var l:Bitmap;
            [ Embed ( source = "l.jpg" ) ] var lClass:Class;
            var m:Bitmap;
            [ Embed ( source = "m.jpg" ) ] var mClass:Class;
            var n:Bitmap;
            [ Embed ( source = "n.jpg" ) ] var nClass:Class;
            var o:Bitmap;
            [ Embed ( source = "o.jpg" ) ] var oClass:Class;
            var p:Bitmap;
            [ Embed ( source = "p.jpg" ) ] var pClass:Class;
            var q:Bitmap;
            [ Embed ( source = "q.jpg" ) ] var qClass:Class;
            var r:Bitmap;
            [ Embed ( source = "r.jpg" ) ] var rClass:Class;
            var s:Bitmap;
            [ Embed ( source = "s.jpg" ) ] var sClass:Class;
            var t:Bitmap;
            [ Embed ( source = "t.jpg" ) ] var tClass:Class;
            var u:Bitmap;
            [ Embed ( source = "u.jpg" ) ] var uClass:Class;
            var v:Bitmap;
            [ Embed ( source = "v.jpg" ) ] var vClass:Class;
            var w:Bitmap;
            [ Embed ( source = "w.jpg" ) ] var wClass:Class;
            var x:Bitmap;
            [ Embed ( source = "x.jpg" ) ] var xClass:Class;
            var y:Bitmap;
            [ Embed ( source = "y.jpg" ) ] var yClass:Class;
            var z:Bitmap;
            [ Embed ( source = "z.jpg" ) ] var zClass:Class;
            var Default:Bitmap;
            [ Embed ( source = "Default.jpg" ) ] var defaultClass:Class;
    
            //the array to hold the fingershapes
            var array:Array = new Array(27);
          
            //place letters in the array
            makeHandshapes();
              
            /*
            * assign variables their respective image and place in array
            */
            function makeHandshapes():void
            {
                array[1] = new aClass();
                array[2] = new bClass();
                array[3] = new cClass();
                array[4] = new dClass();
                array[5] = new eClass();
                array[6] = new fClass();
                array[7] = new gClass();
                array[8] = new hClass();
                array[9] = new iClass();
                array[10] = new jClass();
                array[11] = new kClass();
                array[12] = new lClass();
                array[13] = new mClass();
                array[14] = new nClass();
                array[15] = new oClass();
                array[16] = new pClass();
                array[17] = new qClass();
                array[18] = new rClass();
                array[19] = new sClass();
                array[20] = new tClass();
                array[21] = new uClass();
                array[22] = new vClass();
                array[23] = new wClass();
                array[24] = new xClass();
                array[25] = new yClass();
                array[26] = new zClass();                      
            }



QuizCounter
Next we declare the variables pertinent to the program.
      
            //the boolean determining the state we are in
            var inQuiz:Boolean = false;
          
            //boolean to tell if you've selected a speed
            var speedSelected:Boolean = false;
                   
            //the position of the word in the array
            var quizIndex:int;
          
            //tracks whether or not we are on a new word, or if the previous word is being repeated
            var newWord:Boolean = new Boolean(false);
          
            //keeps track of score
            var quizCounter:QuizCounter = new QuizCounter(10);

QuizCounter is a class I wrote to keep track of the users score within a quiz.

package
{
    public class QuizCounter
    {
               
        private var correct:int;
        private var incorrect:int;
        private var quizLength:int;
           
        public function QuizCounter(quizLength:int)
        {
            this.quizLength = quizLength;
            reset();
        }
   
        public function reset():void
        {
            correct = 0;
            incorrect = 0;
        }
   
        public function getCorrect():int
        {
            return correct;
        }
           
        public function getIncorrect():int
        {
            return incorrect;   
        }
       
        public function wasCorrect():void
        {
            if(correct+incorrect!=quizLength)
                correct++;
        }
       
        public function wasIncorrect():void
        {
            if(correct+incorrect!=quizLength)
                incorrect++;
        }
        public function getLength():int {return quizLength;}
       
        public function isDone():Boolean
        {
            var toReturn:Boolean = new Boolean(false);
            if(correct+incorrect==quizLength)
                toReturn = true;
            return toReturn;
        }

    }
}

XML
This program reads in a list of words from an XML file, and then parses through them, displaying the appropriate letter and then   XML is a file type that is versatile in its application and implementation.  Basically, an XML file is a tree.  Here is an example.

<?xml version="1.0" encoding="utf-8"?>
<Strings>
    <STRING DATUM = "godfather"/>
    <STRING DATUM = "genius"/>
    <STRING DATUM = "mystery"/>
    <STRING DATUM = "southwest"/>
    <STRING DATUM = "police"/>
    <STRING DATUM = "genuine"/>
    <STRING DATUM = "climber"/>
    <STRING DATUM = "clobber"/>
    <STRING DATUM = "batman"/>
    <STRING DATUM ="unicycle"/>
</Strings>

This is a list of strings, a simple document.  Each string is contained in a node of type STRING with an attribute of DATUM, which is the individual string (i.e. godfather – unicycle).


This next function is an XML parser that will parse through an XML file and place the string datums within an array.  First, import the appropriate library functions needed.  The private variables are the array into which we will place the strings, the XMLList we will get from the XML flie, and my_total, which is the total number of elements in the array.

We have several functions local to the this function; these are used only within the this function and do not need to be accessed by any outside client.  First, declare and initialize the URLLoader.  This will allow us to load an external file into our program.  Next, attach an eventlistener to the loader, listening for its completion.  When the loading is complete, the listener will run the function process XML.  Then load quiz1.xml into the program using the URLLoader and URLRequest.  This will request this file from the source repository and then load it into a data object that is passed on into processXML.

The function processXML converts the data object into an XMLList.
The next function called, callStrings(), iterates through the XMLList and places the DATUM strings into the array, quizArray.
 
          
           //the array to put the quiz words
            var quizArray:Array;
            //load the XML file and place the datums into the above declared array
            makeStringArray();
          

           function makeStringArray():void
           {
                   var my_strings:XMLList;
                var my_total:Number;
              
                   var myXMLLoader:URLLoader = new URLLoader();
                myXMLLoader.addEventListener(Event.COMPLETE, processXML);
                myXMLLoader.load(new URLRequest("christmas.xml"));
              
                    function processXML (e:Event):void{
                     var myXML:XML = new XML(e.target.data);
           
                    my_strings = myXML.STRING;
                    my_total = my_strings.length();
                    quizArray = new Array(my_total);
                    callStrings();
                }
                function callStrings():void{
                    for (var i:Number = 0; i < my_total; i++){
                        var my_string:String = my_strings[i].@DATUM;
                        quizArray[i] = my_strings[i].@DATUM;
                    }
                }
            }


Display the Images
This next portion of the code is the actual display of the word. First, display the default image on the screen.

            //put the default image on the screen
            var currentFrame:DisplayObject;
            currentFrame = new defaultClass();
            currentFrame.x = 100;
            currentFrame.y = 50;
            rect.addChild(currentFrame);
          
            var selected:Sprite = button2;
                                    
            //string we will parse and spell out, initially an empty string
            var displayString:String = "";
          
            //speed for the video
            var speed:int;
          
            instruct.text = "Please select speed.";

These functions are called when one of the speed selector buttons is pressed.  The setSpeed function displays the highlighting textfield over the button and sets the speed that the images will display to the corresponding selection.

            /*
            * Set the speed of the display
            */
            function slowSpeed(e:MouseEvent):void
            {  
                setSpeed(700, 77, "Slow", button1);
            }
            function regSpeed(e:MouseEvent):void
            {
                setSpeed(500, 98, "Med", button2);
            }
            function fastSpeed(e:MouseEvent):void
            {
                setSpeed(200, 120, "Fast", button3);
            }
            /*
             * Set the speed that the parser displays the images
             */
            function setSpeed(newSpeed:int, yPos:int, text:String, selectedButton:Sprite):void
            {
                speed = newSpeed;
                highlight.x = 287;
                highlight.y = yPos;
                highlight.text = text;
                addChild(highlight);
                selected = selectedButton;
                speedSelected = true;
                if(!inQuiz)
                    instruct.text = "Please Input String to Read, then press Return."
                myText.addEventListener(KeyboardEvent.KEY_DOWN, enterPressed);
            }

This next function tests to see what the program should do when the user hits the enter key.  First, it checks to see if the user has inputted a string to be displayed, if so, it then displays that sequence of images.  Otherwise, if the user has selected quizMode, then the program will call the function doWork that will display that string.


            /*
             * Function to determine if the user has pressed enter, thereby indicating that it
             * is time to start the image sequence
             */
            function enterPressed(e:KeyboardEvent):void
            {
                //check to see if enter is pressed and that there is something in the input box.
                if(e.keyCode == Keyboard.ENTER && myText.text != "" && !inQuiz)
                {
                    doWork(myText.text.toLowerCase());
                }
                else if(e.keyCode == Keyboard.ENTER && inQuiz && test())
                {
                    if(myText.text.toLowerCase() == quizArray[quizIndex] && newWord)
                    {
                        debug.text = "Correct!";
                        quizCounter.wasCorrect();
                        numCorrect.text = "Correct: "+quizCounter.getCorrect();
                        newWord = false;
                    }
                    else if(newWord)
                    {
                        debug.text = "Sorry, incorrect.";
                        quizCounter.wasIncorrect();
                        numWrong.text = "Incorrect: "+quizCounter.getIncorrect();
                        newWord = false;
                    }
                    if(quizCounter.getIncorrect()+quizCounter.getCorrect()==quizCounter.getLength())
                    {
                        instruct.text = "Result: "+quizCounter.getCorrect()+"/"+quizCounter.getLength();
                        quizCounter.reset();
                        numWrong.text = "Incorrect:";
                        numCorrect.text = "Correct:";
                    }
                }
            }
            /*
            * Test the text in the input textbox to make sure it contains only proper a-z ascii characters
            */
            function test():Boolean
            {
                var toReturn:Boolean = true;
                for(var i:int = 0; i < myText.text.length; i++)
                {
                    if(myText.text.charCodeAt(i)<96 || myText.text.charCodeAt(i)>122)
                        toReturn = false;
                }
                return toReturn;
            }

This function actually displays the appropriate image in the window of the alphabetical handshape in the window. The way this program works is that one string is set as a display string. The first character of the string is displayed, then knocked off; this process is repeated until the entire string has been displayed.


            /*
            * display the appropriate picture in the main window
            * then remove the first character from the string we are displaying
            */
            function parseInput(e:TimerEvent):void
            {
                rect.removeChild(currentFrame);
                currentFrame = array[displayString.charCodeAt(0)-96];
                currentFrame.x = 100;
                currentFrame.y = 50;
                rect.addChild(currentFrame);
                displayString = displayString.substr(1);
            }
           
            //keeps a copy of the entire word being displayed
            var word:String = "";

This function doWork, takes a string and displays the sequence of images corresponding to the lettering of the word using the timer class within actionscript.

            /*
            * Sets the parser into motion, timed by the timer
            */
            function doWork(input:String):void
            {
                displayString = input;
                word = input;
                if(test())
                {
                    instruct.text = "";
                    var myTimer:Timer = new Timer(speed, displayString.length);
                    myTimer.addEventListener(TimerEvent.TIMER, parseInput);
                    myTimer.start();
                }
                else
                {
                    instruct.text = "Please make sure your input consists only of letters a-z.";
                }
            }
 

Quiz Mode
This function is attached to the quiz button. When clicked, the quiz will be set into motion, a string will be randomly selected from the array (populated by the XML file) and will be displayed.  The next function is a called when the user clicks on the exit quiz button.  This allows the user to return to the default mode of entering his or her own text and seeing the word fingerspelled.  The last function allows the user to see the last word spelled out again, whether in quizMode or not, without affecting the score of the quiz.
         
            /*
            * Randomly select an index in the array and then display the fingerspelling of the word
            */
            function quizListener(e:MouseEvent):void
            {
                if(speedSelected)
                    {
                        myText.text = "";
                        quizIndex = Math.random()*10;
                        inQuiz = true;
                        newWord = true;
                        doWork(quizArray[quizIndex]);
                    }
                else
                    instruct.text = "Please make sure that you have selected a speed.";
            }

            /*
            * Exit quiz mode
            */
            function exitQuizListener(e:MouseEvent):void
            {
                debug.text = "";
                myText.text = "";
                instruct.text = "Please input word to spell."
                inQuiz = false;
                quizCounter.reset();
                numCorrect.text = "Correct: ";
                numWrong.text = "Incorrect: ";
            }
            /*
            * Repeat the last word signed
            */
            function repeatListener(e:MouseEvent):void
            {
                if(word != "")
                    doWork(word);
            }