XML to ActionScript

Actionscript:
  1. // this xml is inline but could easily be in an external file
  2. var script:XML=<code>
  3.  
  4.   <!-- // call some methods of the main timeline graphics property -->
  5.   <call method="graphics.beginFill" args="0xFF0000" />
  6.    
  7.   <call method="graphics.drawRect" args="0, 0">
  8.      <!-- // use this to access properties of the main movie -->
  9.      <!-- // and use them as arguments -->
  10.      <arg reference="stage.stageWidth" />
  11.      <arg reference="stage.stageHeight" />
  12.   </call>
  13.  
  14.   <call method="graphics.endFill" args=""/>
  15.  
  16.   <call method="graphics.beginFill" args="0x0000FF">
  17.      <!-- //regular non-reference arguments can be passed like this -->
  18.      <arg value="0.5" />
  19.   </call>
  20.  
  21.   <call method="graphics.drawCircle" args="100,100,20" />
  22.  
  23.   <call method="customFunction" args="hello">
  24.      <arg reference="root.loaderInfo.bytesTotal" />
  25.   </call>
  26.  
  27. </code>
  28.  
  29. function customFunction(a:String, b:String):void{
  30.     trace("I am a custom function called from xml");
  31.     trace("Here is an argument: " + a);
  32.     trace("Here is another argument, (total bytes of this swf): " + b);
  33. }
  34.  
  35. // parse and run
  36. runCode(script);
  37.  
  38. function runCode(code:XML):void{
  39.     var children:XMLList = code.children();
  40.     for (var i:int = 0; i<children.length(); i++){
  41.         var child:XML = children[i];
  42.         var type:String = child.name();
  43.         if (type == "call"){
  44.             runMethod(child);
  45.         }
  46.     }
  47. }
  48.  
  49. function runMethod(code:XML):void{
  50.     var i:int = 0;
  51.     // get a reference to the function
  52.     var method:Function = dotSyntax(code.@method);
  53.     // call the function if there are no arguments
  54.     if (code.@args.toXMLString().length == 0 && code.arg.length() == 0){
  55.         method();
  56.     }else{
  57.      
  58.      var args:Array = code.@args.split(",");
  59.      var childArgsLength:int = code.arg.length()
  60.      for (i = 0; i<childArgsLength; i++){
  61.           // add another one with dot syntax
  62.           var val:String = code.arg[i].@value;
  63.           if (val){
  64.             args.push(val);
  65.           }
  66.       }
  67.       for (i = 0; i<args.length; i++){
  68.           if (args[i] != ""){
  69.             args[i] = valueType(args[i]);
  70.           }
  71.       }
  72.       for (i = 0; i<code.arg.length(); i++){
  73.          var rs:String = code.arg[i].@reference;
  74.          if (rs){
  75.              var ref:* = dotSyntax(rs);
  76.              args.push(ref);  
  77.          }
  78.       }
  79.       // run the function
  80.       method.apply(null,args);
  81.     }
  82. }
  83.  
  84. // parse dot syntax and return the last property or method
  85. function dotSyntax(str:String):*{
  86.     var path:Array = str.split(".");
  87.     var curr:* = this;
  88.     for (var i:int = 0; i<path.length; i++){
  89.         curr = curr[path[i]]
  90.     }
  91.     return curr;
  92. }
  93.  
  94. function valueType(val:*):* {
  95.     if (isNaN(Number(val))) {
  96.            // remove leading and trailing white
  97.            // remove "" around strings
  98.            val = val.replace(/^s+|s+$/g,"").replace(/^"|"$/g,"");
  99.            //  see if it's a boolean
  100.            if (val == "true"){
  101.                val = true;
  102.            }else if (val == "false"){
  103.                val = false
  104.            }
  105.     } else {
  106.         val = Number(val);
  107.     }
  108.     return val;
  109. }

WARNING: There area few small bugs in this snippet. If you'd like to use this, check out the AsXML mini-library

A few days ago I had the idea to write some code that would parse ActionScript from XML. The features that I realized would be possible are:

1) call methods of the main timeline
2) read and write properties on the main timeline
3) instantiate classes on the main timeline
4) call methods on these classes
5) read and write properties on these classes

So this morning I wrote the first part. This snippet has the ability to read an XML file and call methods accordingly. It also has the ability to read properties of the main timeline and pass them to these methods.

The XML in this snippet draws a box using the stageWidth and stageHeight. It draws a transparent circle and then calls a custom function. The custom function gets passed the root.loaderInfo.bytesTotal property.

I've done something similar a few times where I specifically targeted the Graphics API. This takes that to the next level by potentially working with any ActionScript classes (excluding Vector maybe... need to think about that).

I'll post another version with more features tomorrow. At the very least it will have class instantiation.

This entry was posted in XML, dynamic, external data, string manipulation and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

6 Comments

  1. Chris
    Posted June 19, 2009 at 7:22 pm | Permalink

    Hi,

    Interesting stuff. How do you foresee this being used? I’ve developed a toolkit around a similar idea for designing and populating websites/applications for my own company; it’s similar in spirit to what you’re doing here, and affords integration with content management systems.

    Keep up the good work!

  2. Posted June 19, 2009 at 9:34 pm | Permalink

    Hey Chris,

    Since this snippet only has the ability to run a function it isn’t extremely useful. With all the features implement however (see features listed above) it could be used for a few different things… tomorrow I’m going to post the snippet that implements all these features and I’ll go into more detail… but this could be used as a sort of advanced config file for a medium sized app - it could be used to define levels for a game and (as you mentioned) could be used with some sort of cms… it could also be a good basis for a debugger utility… be sure to check out tomorrows post, I’ll try to go into more detail and may create a few demo files…

  3. Dave
    Posted June 20, 2009 at 10:41 am | Permalink

    I’ve been scouring the interwebs for an xml based map editor for box2d in flash. It seems this may be where you are headed. Thanks for sharing your work with us - I’ve really enjoyed the posts.

  4. Posted June 20, 2009 at 11:40 am | Permalink

    Well the version I posted today will work for that. Could be a bit tedious though - also anything instantiated with this code will be dynamically typed.

    I haven’t looked at it, but I think this thing called Box2DWith does xml based instantiation. Have a look at it here:

    http://personal.boristhebrave.com/project/box2dwith/?q=project/box2dwith

    I created an editor for my QuickBox2D library - in that you can just draw everything and it saves out an ActionScript file - but I won’t be uploading that for awhile as it still has some bugs and needs UI.

  5. Posted August 4, 2009 at 3:44 pm | Permalink

    Good stuff. It seems that a lot of developers are reinventing the wheel.
    Me personally wrote a not-so-small IoC framework based on Spring which actually does something like you did with this code but more advanced.

    Nice blog btw, checked some posts.

  6. Posted August 5, 2009 at 9:15 pm | Permalink

    Thanks Valentin… your IoC thing sounds cool… did you see the slightly more advanced version of this?.. here:

    http://actionsnippet.com/?p=1611

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*