h2j9k's first completed project! version 0.1 of the AS3 XMLSerialiser is available for download, attached to this page.
Why make an AS3 XML Serialiser?
What is so magic about a piece of code that turns stuff into XML and back? Hasn't that been rather done? Isn't quite easy anyway in AS3?
It is manifestly bad design to write unnecessary and difficult to maintain code. But this is exactly what XML serialisation tends to contain - manual calls to each accessor. Similarly when deserialising, loops over many cryptically defined properties and attributes are common. This tedious boilerplate, which isn't DRY, and requires changing every time you consolidate your data structures, needn't be such a risky section of your code.
Why not use a reusable static class that handles any object, even with dynamic properties attached, and can restore it's state (assuming it has read-write access to all its data in public members of course). Structuring an application around a design pattern with a single interface to serialisation (which, under the MIT license, you can customise if you don't like my schema...) is much neater and much easier to modify in future, when you need to extend your application (in our fast paced world of "release driven development").
I realise that this approach could also be taken in any language that supports reflection. I can think of uses for compatible versions in Java, C#, Ruby and Javascript, especially if they followed the same schema (woo interoperability), although I am not certain that the endevour is necessarily possible... watch this space for further updates.
EDIT - Apparently Java and C# have quite good XML Serialisers (spelt wrong, of course) built into their standard libraries (although I still disapprove of having all these [XmlRootNode] declarations all over the place to maintain, it is still better than a massive ToXML that just calls a thousand getters, and FromXML which does the reverse). Am still interested in doing something like this for ruby, a bit like ActiveRecord's render :format => :xml perhaps.
Implementation
The implementation uses some plain old AS3 tricks like class "reflection" (aka flash.utils.describeType), running a for..in on dynamic objects, and the easy as pie XML.@attributename syntax for storing and retrieving metadata on nodes. Skip to the end for a download link, if you want to know more.
Demonstration
Have a look at the following test method and the code output. It is set up in the bundle as a document class which runs this code as part of the constructor. The methods to watch out for are:
h2j9k.XMLSerialiser.serialiseThat(objectToSerialise:Object, rootName:String):XML
h2j9k.XMLSerialiser.deserialiseThat(xmlToDeserialise:XML):Object
You will need a cast on the way out, and you need to specify the name of the root node (since it is impossible to detect the instance name of the variable you are passing in, in the problem domain). Here they are in action:
// Initialise a dummy object:
var ddh:DummyDataHolder = new DummyDataHolder();
ddh.ONE = 1;
ddh.TWO = 2;
ddh.three = 3;
ddh.FIVE = 5;
ddh.HELLO_WORLD = "Hello, world!";
ddh.setFour();
ddh.FOO = new Object();
ddh.FOO.understand = "cake";
ddh.artichoke = "cauliflower cheese is awesome";
// Call the actual methods:
var ddhAsXML:XML = serialiseThat(ddh, "Arbitrary");
var ddh2:DummyDataHolder = deserialiseThat(ddhAsXML) as DummyDataHolder;
// Trace the results:
trace("ddh before serialisation:");
ddh.traceMe();
trace("ddh as XML:");
trace(ddhAsXML.toXMLString());
trace("ddh after serialisation:");
ddh2.traceMe();
trace("test of dynamic vars, FOO.understand:");
trace(ddh2.FOO.understand);
trace("and ddh2.artichoke");
trace(ddh2.artichoke);
and the result:
ddh before serialisation:
ONE: 1
TWO: 2
three: 3
four: 4
FIVE: 5
HELLO_WORLD: Hello, world!
FOO: [object Object]
ddh as XML:
<Arbitrary type="h2j9k::DummyDataHolder">
<FIVE type="int">5</FIVE>
<FOO type="Object">
<understand type="String">cake</understand>
</FOO>
<HELLO_WORLD type="String">Hello, world!</HELLO_WORLD>
<TWO type="int">2</TWO>
<ONE type="int">1</ONE>
<three type="int">3</three>
<artichoke type="String">cauliflower cheese is awesome</artichoke>
</Arbitrary>
ddh after serialisation:
ONE: 1
TWO: 2
three: 3
four: 0
FIVE: 5
HELLO_WORLD: Hello, world!
FOO: [object Object]
test of dynamic vars, FOO.understand:
cake
and ddh2.artichoke
cauliflower cheese is awesome
Notice that the only data not transferred in the .four property, which only has a get defined (see the ddh class in the bundle for the details). It is initialised on the first object by calling setFour().
Apologies for the silly test data. Enjoy the free code! I am releasing this under the MIT license since it's not much more than a snippet, so yes you can use it at work. It would be nice if you put a link back the project if possible though!
Installation
All you need to do to get this working in your application is create an h2j9k folder in your FLA's directory and copy in the XMLSerialiser. You can delete the constructor and the import flash.display.* (and the "extends MovieClip" nonsense which is just to get it working as a document class in the test setup) and just import h2j9k.XMLSerialiser.
Download
Umm... apologies, but Drupal appears to be rubbish. Here is a direct link to the ZIP file "attached to this page":
Download Version 0.1
Credits
Thanks to These guys and girls for implementing an in-browser html escape generator, which allowed me to print the output XML trace in a non-insane way in under 5 minutes.