" /> Pete's Blog: July 2008 Archives

« June 2008 | Main | October 2008 »

July 03, 2008

Targeting XMLSchema subtypes for anonymous ActionScript Objects

When encoding ActionScript objects to XML using a schema, such as when using a SOAP based WebService, it is not uncommon to provide a subtype (say, an Employee class) to an API that merely specifies a base type (say, a Person class). An issue is that the encoder does not know the subtype that your value is targeting so you must provide a hint. For the decoding XML to ActionScript case, an xsi:type attribute provides the decoder with such a hint... so an equivalent is needed in ActionScript for the encoding XML case.

For strongly typed objects, you can implement the mx.rpc.xml.IXMLSchemaInstance interface to provide a QName for the xsiType property to target the subclass to be used during encoding. See: http://livedocs.adobe.com/flex/3/langref/mx/rpc/xml/IXMLSchemaInstance.html#xsiType

For anonymous ActionScript Objects, however, you may not know that you can wrap your object in an mx.utils.ObjectProxy instance and set its type property with a QName to achieve the same effect. See: http://livedocs.adobe.com/flex/3/langref/mx/utils/ObjectProxy.html#type

Using the following XML Schema as an example...

<s:schema xmlns:s="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:MyWebService"> <s:element name="Record"> <s:complexType> <s:sequence> <s:element name="person" type="Person" /> </s:sequence> </s:complexType> </s:element> <s:complexType name="Person"> <s:sequence> <s:element name="firstName" type="s:string" /> <s:element name="lastName" type="s:string" /> </s:sequence> </s:complexType> <s:complexType name="Employee"> <s:complexContent> <s:extension base="Person"> <s:sequence> <s:element name="employeeId" type="s:int" /> </s:sequence> </s:extension> </s:complexContent> </s:complexType> </s:schema>

We may want to provide an Employee instance as a Record's person value, but unless we tell the encoder we have something more than a Person instance, the Employee-specific properties will not be encoded.

<ns0:Record xmlns:ns0="urn:MyWebService"> <person> <firstName>John</firstName> <lastName>Smith</lastName> </person> </ns0:Record>

To avoid having to create Person or Employee strong types, here's a snippet showing how to create an ObjectProxy wrapper to instruct the encoder to encode an anonymous Object as an Employee:

import mx.utils.object_proxy;
import mx.utils.ObjectProxy;

...

        var emp:Object = {firstName:"John", lastName:"Smith", employeeId:1000};
        var employee:ObjectProxy = new ObjectProxy(emp);
        var employeeType:QName = new QName("urn:MyWebService", "Employee");
        employee.object_proxy::type = employeeType;

Now the encoder should know to include the Employee specific employeeId property:

<ns0:Record xmlns:ns0="urn:MyWebService"> <person> <firstName>John</firstName> <lastName>Smith</lastName> <employeeId>1000</employeeId> </person> </ns0:Record>

The source for a complete example is attached as a file to download.