Flex 3, XML Schemas & automatic mapping of AS classes to XSD element definitions (Part 2)
This is a set of posts documenting my experiences with utilising functionality within the Flex SDK that provides the automatic mapping of custom ActionScript classes to element definitions within an XML Schema (XSD).
1. Part 1 – Introduction and background
2. Part 2 – Overview of Flex’s XML Schema classes (inc example code)
Part 2 – Overview of Flex’s XML Schema classes (including example code)
This post covers how to take advantage of these classes (including example code) – as at the time of writing there doesn’t seem to be any discussion of these features by Adobe or the community at large. I’ll also list a few caveats we have come across in using these classes.
First things first. The set of classes I will be referring to are found in the mx.rpc.xml package. If you look at the official documentation you will only find a handful of classes that support simple XML encoding and decoding. This is because the majority of the classes relating to XML Schema contain [ExcludeClass] metadata that excludes them from documentation and code hinting.
The easiest way to get visibility of these classes in your code is to place a copy of this package in your project and comment out all the [ExcludeClass] tags above the class definitions.
The key classes are:
- SchemaManager (manages multiple schema definitions)
- Schema (manages a single XML Schema Definition)
- SchemaLoader (manages the loading of an XML schema (including any imports/includes) at runtime)
- SchemaTypeRegistry (maps an XML schema type to an ActionScript Class)
- XMLDecoder (decodes an XML document into ActionScript objects based on a XML Schema definition
- XMLEncoder (encodes an ActionScript object into XML based of an XML Schema)
Example and explanation:
A really basic example Flex app that covers the core functionality of these classes can be viewed here (right click for source).
The primary steps are outlined below:
1. Create an instance of SchemaLoader and asynchronously load an XML schema from a given URL
This automatically loads any other schemas that are defined in XSD import or include elements.
schemaLoader = new SchemaLoader();
schemaLoader.addEventListener(SchemaLoadEvent.LOAD, schemaLoader_loadHandler);
schemaLoader.load("example.xsd");
2. Once the schema is loaded, add it to the SchemaManager and register any ActionScript classes to their corresponding schema type:
private function schemaXMLLoader_loadHandler(event:SchemaLoadEvent):void
{
schema = event.schema;
schemaManager.addSchema(schema);
schemaTypeRegistry.registerClass(new QName(schema.targetNamespace.uri, "example"), ExampleVO);
}
3. Load an XML file based off that schema.
4. Once the XML is loaded, decode the contents using XMLDecoder. Any classes registered in the schemaTypeRegistry will be used when decoding the xml
var xmlDecoder:XMLDecoder; var qName:QName; var result:*; xmlDecoder = new XMLDecoder(); xmlDecoder.schemaManager = schemaManager; qName = new QName(schema.targetNamespace.uri, "results"); result = xmlDecoder.decode(xml, qName)
5. Encode a custom ActionScript class back into XML using XMLEncoder. XMLEncoder.encode() supports various ways to define the corresponding element in the schema (top level element, a specific type or even a custom XSD definition) that will be used to encode the Actionscript object.
var qName:QName; var xmlEncoder:XMLEncoder; var xmlList:XMLList; qName = new QName(schema.targetNamespace.uri, "Example"); xmlEncoder = new XMLEncoder(); xmlEncoder.schemaManager = schemaManager; xmlList = xmlEncoder.encode(exampleVO, qName);
For futher explaination check out the source inside the example applicatio.
Issues and Notes
There are a few things to be aware of when using these classes.
1. It requires a XML Schema to already be in memory when decoding a loaded XML file. As this is an asynchronous task it is best to load the schemas required before loading any XML files based off them. The alternative is to check each XML file for schema information when they load, and delay the decoding of the data until that schema has then loaded. This would require additional checks and steps each time xml data is loaded.
2. Any additional schemas included or imported within the top level schema loaded by SchemaLoader must be referenced using an absolute path. This is because SchemaLoader assumes that relative paths are relative to the main application swf URL (and not relative to the original XSD url). As these two locations are unlikely to be the same in a real world project, changing these URLs to be relative to the swf will make it work with Flex, but will prevent any other XSD editor from being able to find the corresponding includes or imports.
As this will be an issue when relying on any XML API using relative paths that is outside the direct control of the Flex developer, I would say this is a bug and have submitted it to Adobe as such (link). Feel free to add your support to it.
—————————–
UPDATE July 2010
I’ve created an updated version of this example project that demonstrates some of the more advanced scenarios that people have posted questions about. This version targets flex 4.0 – but the code base is essentially identical to the old 3.x versions. I’d always recommend targeting the most recent 3.x or 4.x version of the flex rpc library as the flex team seem to make improvements in every release. Having said that, these mx.rpc libraries aren’t something i’m using on a regular basis – so i’m not actively checking what’s new or changed in each release.
This example includes the following additional scenarios/use cases:
- encoding to multiple ActionScript classes
- encoding/decoding from multiple actionscript classes
- encoding/decoding attributes as well as elements
- nested child elements decoding to an ArrayCollection
- basic validation of an XML file against the XSD
view it here (right click to view source)


November 30th, 2008 at 11:30 pm
[...] 1. Part 1 – Introduction and background 2. Part 2 – Overview of Flex’s XML Schema classes (inc example code) [...]
December 1st, 2008 at 7:34 am
Cool – glad to see some blogging on it from the Flex side of the equation. :)
February 1st, 2009 at 2:50 am
I just started out with Flex and XSD. It is really hard to find good online information about this topic. This is a killer tutorial, just what i needed for now. Thanks!
September 24th, 2009 at 2:03 pm
Hi.
What if you want to return an ArrayColelction of ExampleVO objects.
I’m trying to extend your sample here, but I’m having some trouble.
Thanks for your work!
November 18th, 2009 at 2:54 pm
Hi everyone,
i’m developing XSD-To-AS3 Class Generator, a simple Air app that allow developers to quickly build any Flex/Flash app XML based.
It takes an XML schema and an XML document and uses it to generate a class library. These classes map directly to data contained in your XML Schema, the generated classes is strongly typed, it forms a kind of template for the developer, ensuring that the data created conforms the underlying XML Schema.
It will be very usefull for quickly work with 3th party API RESTful interface!
The project is still in progress
Try it Adobe Air Marketplace
..:: The Ria Team ::..
January 18th, 2010 at 1:29 am
I have a strange problem and I’m hoping you can help me.
I cannot get FlexBuilder to access the following classes in mx.rpc.xml:
Schema, SchemaManager, SchemaLoader, XMLEncoder, XMLDecoder
and the following classes in mx.rpc.events:
XMLLoadEvent, SchemaLoadEvent
When I say “access”, I mean that when I type out “mx.rpc.xml.” I don’t see those classes. Also, when I type “new Schema()” there’s no auto-sense for it.
If I “take it on faith” that the classes are there and just use them, the classes exist and are visible in the debugger. I only discovered that, of course, after messing with FlexBuilder settings for hours (in-between trying to find web sites mentioning this), and also uninstalling and reinstalling FlexBuilder itself. Yuck.
Any thoughts?
Thanks,
Will
January 18th, 2010 at 1:32 am
I’m an idiot. Don’t answer that. The “Exclude Class” stuff didn’t jump out at me when I scanned the post. X|
January 22nd, 2010 at 2:31 pm
So your original example.xml file has the following root tag:
and when you re-encode you lose the schemaLocation, noNamesspaceSchemaLocation, and the xmlns:xsi schema instance tag:
That sort-of renders any output xml unusable, right? Have you found a way around that?
January 22nd, 2010 at 2:31 pm
(darn them for not having ‘preview’ on the comments section)
So your original example.xml file has the following root tag:
<result
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns=”http://www.misprintt.net”
xsi:schemaLocation=”http://www.misprintt.net schema.xsd”
xsi:noNamespaceSchemaLocation=”http://www.misprintt.net example.xsd” >
and when you re-encode you lose the schemaLocation, noNamesspaceSchemaLocation, and the xmlns:xsi schema instance tag:
<result xmlns=”http://www.misprintt.net”>
That sort-of renders any output xml unusable, right? Have you found a way around that?
February 23rd, 2010 at 1:01 am
Hi William,
I haven’t found a proper solution so far. In the past i have just manually re-added them to the xml after the default XMLEncode class has encoded the objects. I’m not sure if it is an issue with the flex XML schema classes, or something that needs to more explicitly defined in the xsd.
I’m not surprised that there is an issue. Because XML is a native type in AS3, dealing with namespaces in XML is notoriously awkward. In other projects I have resorted to complex regular expressions to strip out all namespace references from an xml string rather than have to juggle multiple namespaces!
March 1st, 2010 at 1:22 pm
Is there a way to just validate the xml against the schema? I don’t want/need the auto-created VO’s, i just want to examine the xml and throw errors if anything is invalid… does that happen implicitly during decodeXML()? Thanks!
May 20th, 2010 at 7:15 pm
Hi, this is great, thanks.
I do have one question: I have a well-structured complex xsd with several level of nested child-elements. My corresponding class would look like this:
class MainValueObject
{
something1: array; //array of another class “Something1″
something2: array; //array of another class “Something2″
… etc …
}
“Something1″ and “Something2″ also contain arrays of other classes.
So would this automated mapping of schema to AS object work?
How can I register the multiple levels of nested classes against the one xsd schema?
Thanks.
June 6th, 2010 at 1:42 pm
Hi,
I’m having the same issues as henry000, Do you have any ideia about It?
thanks
June 24th, 2010 at 4:44 am
My question is darrendb question, I need to validate my XML, and receive an error if something is wrong, that’s all…
Some ideas?
Thanks…
June 30th, 2010 at 4:11 am
Hi, how would one use the encode() method if i have for example an mxl looking like this:
joe
natty
jaddy
naomi
joel
nike
now in your XMLDecode() function,
the result.example as ExampleVO; was stored in a variable exampleVo;
and in your XMLEncode() function,
the value of that variable was passed to an object type o . pointing to the primary node of your xml ->example
o.example = exampleVO; and then it is attached to the Node
qname(o, qname);
that method selects the node passsed in and displays everything beneath. in my own case, itz not working. suppose you have the given xml above. where you have a root object, and an immediate element which has nested elements, how do you use the XMLEncode funntion or the QName() method to get the whole XML. mine is only displaying the root node and not the elements..
July 1st, 2010 at 3:54 am
in your example, in the encodeToXML() function,
where is the example in the statement:
o.example = exampleVO;
from? i am having a difficult time figuring out which of the files is this? is it the .xml, xsd or just the name of your element? let us know pls.
July 1st, 2010 at 3:57 am
I have been able to use your example to work on a very complex xml file but the problem is while it decodes properly, it encodes in a way such that the elements are not in the right position. i mean, the artributes are considered as elements. i am guessing itz the statement i am intested in knowing.. when i debug the exampleVO instance of the ExampleVO class , i have the right Objects but when i pass it to o.example, it bhaves funnily.. please elaborate on that statement/line. thanks
July 12th, 2010 at 5:39 am
Hi Kuchino,
‘exampleVO’ is my example data object created in the ‘decodeXML’ method.
‘o.example’ is a temporary object containing a reference to exampleVO.
The reason that this reference is added to ‘o.example’ rather than just ‘o’ is because source/destination example xml has a parent element called ‘result’ that contains the ‘example’ element.
I’m essentially reflecting that structure in the object that i send to the XMLEncoder.
July 12th, 2010 at 5:42 am
Hi Kuchino,
I’m not exactly sure what the issue is here – in my experience XMLEncoder faithfully serialises both elements and attributes correctly. The critical thing is to ensure that the object you send to encode has the same structure as the ‘result’ object created in the decodeXML function.
July 12th, 2010 at 6:02 am
Hi henry,
I’ve added a new example to the bottom of the post that includes an xml file with an array of child elements as well as multiple ActionScript value objects. I hope this helps
July 12th, 2010 at 1:55 pm
Hi,
Thanks for the great example and the explanation, it really helped us!
The link for the view source for your latest update seems to be broken?
August 16th, 2010 at 1:04 pm
Have you by chance found any way to address the performance implications of dealing with large XML documents (e.g. XMLLists with a large number of child elements)? I’ve found that the XMLDecoder is fine for small data sets, but it converts XML at a rate of about 100 objects/second, which given the nature of flash, ends up causing the flash player to hang and eventually causes the classic “script timeout” error. Anything upwards of a couple hundred items becomes harmful to the user experience, and anything in the range of 800-1000 items is effectively unusable.