E4X XML Binding & CDATA

The benefit with using international standards when creating software is that you can blame to stupid design decisions on “an international team of brilliant computer scientists”. That way, if someone tries to body-check you on the pathetic implementation, you can defer to aforementioned governing body. That way, you’re calling an international standards body a bunch of crackheads, thus making you look like a crackhead. Who in their right mind would attempt to insult a group of talented individuals from around the globe brought together for the specific purpose to collaborate on creating a new programming API?

Me. I call it like I see it and it’s crap; specifically, CDATA handling in E4X.

For background, CDATA is a way to put “character data” which is basically text that could have funky characters in it like HTML. Since XML is made up of HTML like syntax, you want to make sure that you can put HTML into XML, and not have itscrew up when parsed. Enter the CDATA tag, a special tag that tells the parser (whoever is converting the XML text into something useful, like Flash or Flex for example), to ignore parsing anything inside of it. Kind of like the “pre” and “code” tags in HTML.

Putting these special tags into E4X XML is impossible when combined with binding. Binding is an extremely useful way of creating dynamic XML from variables without having to construct it manually. Since XML is a first class citizen in AS3, you can basically copy and paste real XML into your ActionScript, and set it to a variable.

Even cooler, though, is the binding; sort of like Flex’ databinding, except it works inside of the XML nodes. So, if you are building Factory classes for example that create XML request packets to send to somewebservice, you can make a function that takes some parameters to customize the request, and return the XML, like so:

function getLoginRequest ( username : String, password : String ) : XML
{
    var request:XML = <request>
                            <login>
                                <username>{username}</username>
                                <password>{password}</password>
                            </login>
                        </request>;
    return request;
}
var request:XML = getLoginRequest("Jesse", "moogoo123");

Working with a talented PHP dev at work named Nick, and he requires me to send a URL in my request to one of the services. We don’t make heavy use of attributes, which you can actually get away with a lot of HTML character data without XML getting mad, even in the old DOM way.

The URL, however, kept getting URL encoded. The URL was ALREADY URL encoded because it had some parameters on it that the server would use later. However, it seems E4X does automatic URL encoding (akaencodeURIComponent or it’s ilk) on the text you throw into nodes.

So, I tried Just putting a CDATA tag instead:

var theURL:String = "http://some.com?var=someval&foo=bar";
<the_url><![CDATA[{theURL}]]></the_url>

…however, bindings don’t work in CDATA tags like that. Since the CDATA is doing what it’s told, and telling the XML parser in ActionScript to ignore the inner contents, this includes the binding. Shoot!

So, I tried creating it as a String:

var s:String = "<![CDATA[" + theURL + "]]>";
<the_url>{s}</the_url>

…but then it URL encodes the URL again!!!

<the_url><![CDATA[http://some.com?var=someval&amp;foo=bar]]></the_url>

Son of a…

I then tried various other ways of doing the same thing, all to no avail. In DOM, we had XML.ignoreWhite, which basically told the parser to ignore whitespace. There doesn’t seem to be the same sort of setting for E4X to turn of automatic encoding. Furthermore, you can treat the CDATA node as just a normal String, unlike the old DOM which was a tad more explicit like node.firstChild vs. node.firstChild.firstChild (or was it nodeValue… forget).

Anyway, DAMMIT!

Michael Schmalle had a fix. You CAN bind to functions as well. It’ll do an automatic invoke (just like a getter for example), and you can return whatever you want. So, doing this:

function cdata(theURL:String):XML
{
    var x:XML = new XML("<![CDATA[" + theURL "]]>");
    return x;
}
<the_url>{cdata("http://some.com?var=someval&foo=bar")}</the_url>

Flexcoders for the win.

I’ve gotten used to namespaces. They make sense; while verbose code, at least verbose pays off in AS3 with speed at runtime.

CDATA handling, however, is an f’ing joke. If it DOES handle it well, then the docs are an f’ing joke. Neither of which is funny. No one cares, though, because I gotta fix and Nick could remove his Base64 decoding hack he put in for me as a temporary band-aid.

10 Replies to “E4X XML Binding & CDATA”

  1. wait, are you implying that Macrodobe would publish insufficient documentation? Why, I never!

  2. Considering the auto-url encoding that goes on when sharing xml data with a php driven backend … how many times is the xml being url encoded/decoded and by whom? I am sure php does it before it gets sent off to Flex. I agree Jesse. Someone’s else’s idea of helpfulness can be a severe drag.

  3. Flex 3 does not support using bindings from actionscript onto XML or E4X. You have to use the {} or tag from mxml. I filed a feature request to add a new method onto the BindingUtil class to help with bindings from AS3. Vote for or comment on this issue below:

    https://bugs.adobe.com/jira/browse/ASC-3054

  4. I have just try your method and I also try this function cdata(theURL:String):XML

    still have parse error..

  5. So I haven’t needed this until now… but man did it save me some time. I believe that’s TWO beers I owe you now ;)

  6. “an international team of brilliant computer scientists”- another exceptional area i’m finding is AS3’s handling of CSS, why would they design a new type of CSS? ie:camelCase naming. wouldn’t it be great if you could just import a regular old CSS2/3 doc?

Comments are closed.