Flex Chronicles #25: E4X Gotchas

Couple of E4X gotchas that have bitten me in past few weeks.

Namespaces

The first is namespaces. There is a good article on them in the Flex docs, but it may not be apparent why at first your parsing code is failing. In effect, it may not be failing, but simply looking for the wrong nodes. To give you the quick version of namespaces, check the following XML.

<Button label="foo" />
<Button label="bar" />

Two XML nodes that represent Button’s in Flex. What if, however, you had a component called Button? How would you write it so Flex knew one was yours and the others was Adobe’s? Namespaces.

<mx:Button />
<jxl:Button />

Notice the prefixes. The mx one will map somewhere, usually on the root node which defines the namespace. The same goes for yours.

xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:jxl="com.jxl.controls.*"

Now, those values are really just unique string representations. The URL for example is not actually checked. The package path for jxl however is checked by Flex Builder. The point is, using namespaces allows the same XML nodes to be used in an a block of XML and be identified as different. Therefore, the default E4X way of accessing XML nodes won’t work as expected. For example, the quick way to get at “book” in the following:

var myXML:XML =
   <books xmlns="http://www.moogoo.com/">
       <book name="cheese">sup</book>
   </books>;

Is not:

trace(myXML.book); //

But:

var ns1:Namespace = new Namespace("http://www.moogoo.com/");
default xml namespace = ns1;
trace(myXML.book); // sup

Namespaces are used in ActionScript 3 to identify specific methods. For example, public, private, protected, and mx_internal are namespaces. E4X has a similar way of using namespaces in AS3 because XML is basically a first class citizen in AS3. So, you have to define the namespace ABOVE your E4X specific code.

If your XML doesn’t have namespaces, don’t worry about this jazz.

By Ref vs. By Val

The second gotcha is really hard for me to reproduce, so I’m not even sure this is accurately the problem but I DO know this is a working solution. I have a series of HTTPService POST’s to a series of PHP services. To work with the API, you send XML and get XML back. Simple stuff.

To call it, I just build the XML by hand per call, and databind my values into it. Here’s a sample factory method:

public static function getSampleRequest(userToken:String="",
                                                appName:String="",
                                                someParam:String=""):XML
{
       var request:XML =
                  <Request>
                       <authentication>
                           <user_token>{userToken}</user_token>
                           <app_name>{appName}</app_name>
                       </authentication>
                       <Some_Action>
                           <some_param>{someParam}</some_param>
                       </Some_Action>
                   </Request>;
        
       return request;
 }

I do the reverse when I get XML back, and parse out the values, converting those to Value Objects (strongly-typed AS3 classes that represent data objects; usually matching the database tables).

One particular request, however, is a file upload. The new upload complete data, the event that is fired after the file upload is successful and shows the returned server data, allows me to upload a file, and get info about that file from our API. This XML, however, wasn’t parsing like the others were. I’d get a DataEvent back, cast the data property to XML, and go from there. However, in this case… something whack was happening not matter what I did (converting to XMLList, snagging first child as XML… nothing).

I got so mad cause everything else was working, but I’d get weird parsing/casting results, like the XML getting a namespace prefix of “aaa” for all nodes. Weird stuff. I could copy and paste the exact XML into a new file and parse it just fine. Finally, I figured if it wasn’t the XML string, it must of been whatever it was attached to. So, instead of this:

var myXML:XML = event.data as XML;

I did this:

var xmlStr:String = event.data as String;
var my_xml:XML = new XML(xmlStr);

Boo-fing-ya, it worked. My only guess is the by reference was injecting something “else” into the XML object whereas a freshly created String (by val) was good and pure. Once shoved into the XML constructor, it was fine and didn’t contain whatever mess the by ref did.

4 Replies to “Flex Chronicles #25: E4X Gotchas”

  1. I just had a very similar problem where nodes were being named ‘aaa’ with a prefix of the actual node name!

    Incredibly, it only happened on one response from a WSDL service. Is this a bug in Flex, or Namespace, or what?

  2. Jesse,
    I was reading through EAS3 and they have a good chapter on e4x. I came across a similar problem to what you are discussing here. If we’re talking about the same thing- then according to moock’s book every XML child returned as a result will be wrapped and come back as an XMLList with one item in it. If you pass that value into a variable of type string though it returns the content of the node.
    Are we talking about the same issue?
    M

Comments are closed.