Flex 2, Actionscript 3, and E4X
I've found a feature of Actionscript 3 (AS3) that I've not seen in other languages that I think is pretty cool. It's taken me awhile to come to terms with it, but now that I've getting more comfortable with it I'm really starting to appreciate it. That feature is what is known as E4X or more officially Standard ECMA-357 ECMAScript for XML (E4X) Specification. At its core is the ability to work with and manipulate XML data in AS3 using standard language syntax instead of having to do everything through an API.
For example to create a variable that contains some hard coded XML you could just write:
var xml:XML =
<componentPackage>
<component id="MyButton" class="package1.MyButton"/>
<component id="MyOtherButton" class="package2.MyOtherButton"/>
</componentPackage>;
Notice the lack of any "new XML("")" or other traditional methods one might use to create an XML document. Pretty cool stuff. You can also do variable substitution when creating XML:
var attributeName:String = "class";
var xml:XML =
<componentPackage>
<component id="MyButton" {attributeName}="package1.MyButton"/>
<component id="MyOtherButton" {attributeName}="package2.MyOtherButton"/>
</componentPackage>;
That creates an XML document that looks exactly like the first XML example. Not the most convincing example, but you get the idea. You can substitute element names, attribute names, or whole attribute values. Besides being able to do inline XML document creation you can also do DOM style navigation to get at elements and attributes within the XML (these return XML or XMLList objects). Going back to the first XML example:
xml.component[0]; // <component id="MyButton" class="com.example.ui.MyButton"/>
xml.component[0].@id; // MyButton
Where things get really cool is the XPath like operations, technically called filters since it isn't as expressive as XPath:
xml.component.(@id == "MyButton"); // <component id="MyButton" class="com.example.ui.MyButton"/>
That searches for all component elements under the root that have an id of MyButton. There are a bunch more. In fact the Working with XML (doc link subject to change) section of the Flex 2 documentation has many good examples. It's at this point that I want to offer a hard learned lesson about what doesn't work with E4X (at present anyway, I can only hope that it will be solved in a future Flex 2 release).
The following line of code doesn't compile (again using the first XML example from above):
xml.component[0].@class; // Error: Expecting identifier before class
The reason is that "class" is a reserved keyword. Thankfully E4X provides alternative attribute access syntax, an example is:
xml.component[0].@["class"]; // package1.MyButton
A little clunky, but still reasonable. What I haven't been able to get working is any of the alternative syntaxes when trying to do a filter using the same attribute:
xml.component[0].(@class == "package1.MyButton"); // Error: Expecting identifier before class
I've tried all four listed variations: element.@attrName, element.attribute("attrName"), element["@attrName"], and element.@["attrName"]. None of them work in the above example, adjusted of course to account for the () filtering operation. This afternoon I finally stumbled upon a solution. This is even more clunky then the alternative attribute accessors, but it does eliminate the need to write custom loops to handle filters like the one above:
xml.component.(@\u0063lass == "package1.MyButton"); // <component id="MyButton" class="com.example.ui.MyButton"/>
In this case I'm using the Unicode value for the letter c (0063) which to my surprise worked. As I said earlier I hope this keyword issue is just a beta issue and it will be resolved. If not, consider using this approach to construct E4X filters that might reference AS3 keywords.
Comments
it is possible to write: xml.component.(attributes("class") == "package1.MyButton");
same is when working with elements: xml.component.(elements("component") == "SOME TEXT"); Enjoy :)
Posted by: Ilia | May 3, 2007 5:23 AM
Posted by: Roger Braunstein | May 21, 2007 9:40 PM
Posted by: Evan | July 17, 2008 2:10 PM
Posted by: Ken | September 25, 2008 5:35 PM