views:

3512

answers:

6

A project I'm working on will pull XML from a web-server and build a data store from it. The data will have certain core fields but needs to be extendable... for example I have a and later might want to have which adds extra fields.

In the Flex app, I don't want the central data store to be working on XML objects or simply putting the properties into Objects. I want to have strong types, e.g a Person class, which are created/populated from the XML.

How can this be done in a flexible way? Is Flex able to automatically build a Person from an XML if the attribute names match, or do I need to write conversion functionality for , , etc?

+3  A: 

I don't think this can be done automatically. I generally create the a class to mirror the XML structure I have and then create a static class method to create an instance of the object given an XML node. For example:

package {

  public class Foo{

     public function Foo(barparam1:String, barparam2:uint, barparam3:String, barparam4:Number){
       this._bar1 = barparam1;
       this._bar2 = barparam2;
       this._bar3 = barparam3;
       this._bar4 = barparam4;
       }

     protected var _bar1:String;
     protected var _bar2:uint;
     protected var _bar3:String;
     protected var _bar4:Number;

     public function get bar1():String{ return this._bar1; }
     public function get bar2():uint    { return this._bar2; }
     public function get bar3():String  { return this._bar3; }
     public function get bar4():Number  { return this._bar4; }

     public function toString():String{
        return "[Foo bar1:\"" + this.bar1 + "\", bar3:\"" + this.bar3 + "\", bar2:" + this.bar2 + ", bar4:" + this.bar4 + "]";
        }

     public static function createFromXml(xmlParam:XML):Foo{

        /* XML Format:
          <foo bar1="bar1value" bar2="5">
            <bar3>bar3 data</bar3>
            <bar4>10</bar4>
          </foo>
        */

       return new Foo(xmlParam.@bar1, xmlParam.@bar2, xmlParam.bar3[0], xmlParam.bar4[0]);
       }
    }
  }
81bronco
+1  A: 

If you aren't tied to XML (e.g. you have an app server instead of a file server) you could consider using AMF (Action Message Format) to transfer the data. There are a few projects that expose AMF to servers including Adobe's own Blaze DS and community open source variants such as OpenAMF, AMFPHP, PyAMF and so on. This will give you the ability to transfer custom objects from the server to Flex, automatic parsing of data-types and type safety. Have a look at this comparison of data transfer options to get an idea of the relative merits.

That being said, XML can be very useful for things like app configuration data and in those instances you aren't running an app server. I agree with the other poster where I will immediately parse the xml into appropriate structures by hand. I usually store these with the post-fix VO (for Value Object) and I leave the members as public. I often do this hierarchically.

package model.vo
{
public class ConfigVO
{
    public var foo:String;
    public var bar:int;
    public var baz:Boolean;
    public var sections:Array;

    public function ConfigVO(xml:XML)
    {
        parseXML(xml);
    }

    private function parseXML(xml:XML):void
    {
        foo = xml.foo;
        bar = xml.bar;
        baz = (xml.baz == "true");

        sections = [];
        for each(var sectionXML:XML in xml.section)
        {
            sections.push(new SectionVO(sectionXML));
        }
    }
}
}

package model.vo
{
public class SectionVO
{
    public var title:String;

    public function SectionVO(xml:XML)
    {
        parseXML(xml);
    }

    private function parseXML(xml:XML):void
    {
        title = xml.@title;
    }
}
}

I've seen systems in the past that will bind XML element names to class definitions. These usually use some sort of introspection on the class to determine what properties to read off the xml or they will have some static class properties that map instance properties to xml tags or attributes. In my experience they are much more trouble than they are worth. It takes all of 2 seconds to add a new public property and a single line to read the data from an attribute or child tag. It is my suggestion to avoid such complex schemes but I'll give a simple example for completeness.

package model
{
    public class XMLReader
    {
        // maps <tagname> to a class 
        private static var elementClassMap:Object =
        {
            "section": SectionVO,
            "person": PersonVO
        };

        public var parsedElements:Array;

        public function XMLReader(xml:XML)
        {
            parsedElements = [];
            parseXML(xml);
        }

        private function parseXML(xml:XML):void
        {
            var voClass:Class;
            for each(var element:XML in xml.children())
            {
                voClass = elementClassMap[element.name().localname];
                if(voClass)
                {
                    parsedElements.push(new voClass(element));
                }
            }
        }
    }
}
James Fassett
A: 

converting xml to objects using the flex simplexmldecoder class @flexExamples

A: 

A little while ago I started working on a Flex Library that will help serialize and deserialize Action Script objects to and from XML. All you have to do is create your model objects, put some annotations on the fields to let the serializer know how you want the field to be serialized (element, attribute, what name, etc) and the call the (de)serialization process.

I think it suits your needs.

If you want, you can check it out at http://code.google.com/p/flexxb/.

Hope this will prove to be helpful.

A: 

Creating strong data types has several advantages, code completion and compile time syntax checking being the most important ones. Manual mappings can be done, but should be generated (and thus aren't really manual any more after all) to avoid being out of sync sooner or later.

Introspection-based general conversion libraries are versatile, easy to use, and should suffice for most use-cases.

JAXB is the standard for Java. ASXB provides a lightweight implementation of this idea for the Actionscript world. It uses explicit AS objects with annotations to (un)marshal objects from and to XML.

If you are forced to use XML on the wire, I'd suggest giving ASXB a closer look. If you're free to choose your format and have a supporting Server-side, Adobes own AMF format should be your choice, as it's directly supported in the language and has a much lower overhead during transport.

In our current project, we wrote small code generators which takes the external API of the Java side (source introspection, to also copy the Javadoc) and generate the AS classes from it during our build process. It was thus easy to switch from AMF to XML when external requirements forced us to do so.

PS: remember to add the compiler parameters to your flex config file to keep the annotations

Zefiro
A: 

AsBeanGen can do this. It generates value objects for DTD driven XML files.

maxmc