AS3 E4X Rundown

View this article in other languages:

I’ve been using E4X in ActionScript 3.0 for a while now and the rumors of its simplicity have been greatly exaggerated. A lot of operations are easy and make sense, but others are less… obvious. E4X is essentially a whole new language which is part of the AS3 grammar, just as regular expressions have their own completely different language but exist within ActionScript 3.0. And being so new, there really isn’t a whole lot of documentation out there. This is further complicated by the fact that since E4X seems simple enough at first glance to explain in a few lines, a lot of documentation stops short.

Anyway. I’ve been infuriated by E4X more than a few times now, and I’d like to start a running post to demystify some of it. Please! use the comments to ask any questions you might have, and I’ll keep adding to this post. Hopefully this can turn into a decent resource for E4X lore. The fun begins after the cut.

For the following post, let’s use this XML block as an example:

var thePeople:XML = <people>
    <person name="Mims Wright" suffix="III">
        <age>27</age>
        <aka>Mims H Wright</aka>
        <aka>Teh AWesoeomes!</aka>
        <bio><![CDATA[This guy <b>rulz<b>!]]></bio>
    </person>
    <person name="Roger Braunstein">
        <age>26</age>
        <aka>Rog</aka>
        <aka>That guy</aka>
        <bio><![CDATA[Likes food.]]></bio>
    </person>
</people>;

XMLList vs XML

Ok, first thing you notice is that you can just type in XML and it becomes an XML typed variable. You should also know that this XML class is not the same as the XML class in AS2. All new!

Second thing you should know is that there are two principally related classes: XML and XMLList. XML is well-formed XML (mostly; see Node Types for exceptions). XMLList is a list of XML nodes. The difference here is that XML must always have one single root node; XMLLists have multiple nodes at the base depth. For instance, the whole example above is XML because it is typed as XML and it has a single root node, <people>. In contrast, an XMLList is composed of zero or more root nodes, like:

<age>27</age>
<age>26</age>

This can’t be XML because there are two root nodes. You can, however, think of it as a list of XML, since each <age> node is itself a single root node. It’s important to note that an XMLList can also have one (like XML) or zero nodes.

Anyway, most of the basic operations for E4X are filtering operations. You take the XML and find some subset of the XML. Often, you want to find a particular node. Any filtering you do is going to result in a number of possible nodes, so you will notice soon that XML always turns into XMLList when you filter it. Most of the time you’ll be dealing with XMLLists. The same kinds of filters are available on both classes, except where noted.

The Basics

These are the basics of E4X. You’ve probably figured these ones out already cuz you is a pimp!

thePeople.person.age

Use dot syntax to select child nodes by name. The variable is already associated with the root node so there’s no need to write <people> into the expression. The expression above has two successive filters. The first one gets you all the <person> nodes immediately below the root node, in other words, an XMLList. The second one gets you all the <age> nodes below all the nodes in the first filter. Result:

<age>27</age>
<age>26</age>

Again, this is an XMLList, and notice how it retrieves all the age nodes under all the person nodes.

thePeople.person.@name

Use the @ symbol to select attributes instead of child nodes. This example is two subsequent filters. The first finds all the <person> nodes under the root, and the second finds all the name attributes of those nodes. This time, the result is not a list of nodes but a list of attributes. It gets weird here, but the result is an XMLList of attributes. This sure isn’t valid XML, but we’ll talk more about node types later.

thePeople.person.(age >= 21)

Possibly your most powerful tool, a parenthetical can filter nodes based on arbitrary criteria. This expression returns an XMLList with both Mims and I because we’re both totally legal drinking age AWESOME! Another expression you could create:

thePeople.person.(@name.charAt(0) == "R"); //Roger's <person> node
thePeople.person[1]

Use square brackets to get XML nodes out of XMLLists, like an indexed array. This is your way to get from XMLList to XML. Result:

<person name="Roger Braunstein">
    <age>26</age>
    <aka>Rog</aka>
    <aka>That guy</aka>
    <bio><![CDATA[Likes food.]]></bio>
</person>

Also, since all filters available to you return all possible matches, when searching out a specific node you’ll use this all the time. For instance, you can create a sequence of filters that should only have one match, but you might find yourself picking out the first result of every test. E.g.,

thePeople.person.(@name == "Roger Braunstein").age; //XMLList with one node
thePeople.person.(@name == "Roger Braunstein")[0].age[0]; //XML

I think it’s kind of unfortunate that there’s no shortcut to pick the only result of a filter, because complex E4X expressions can frequently become polluted with [0]s. Alternately, you can just place one at the end of a chain of filters. In the second example above, the expression goes from XML→XMLList→XMLList→XML→XMLList→XML.

thePeople..age

Using two dots instead of one (..) finds all the applicable nodes that are at any depth rather than at the the next depth. It lets you search for descendents instead of children. For example, you could find all <div> tags in an XHTML document this way. The result of this query is:

<age>27</age>
<age>26</age>

We didn’t bother to look for the <person> tags; those <age> tags can come from anywhere in the XML.

thePeople.*.age

The asterisk operator (*) selects all children of the node. If the example had a non-<person> tag with an <age> child, this line would return it as well as the <age> nodes under the <person> nodes. It doesn’t care what the first generation child is, as long as the second generation child is <age>

Strings and XML

When you’re printing out XML elements, if you don’t specify a different conversion function, toString() is called. This will print out “complex content” like XML and “simple content” like its string value. You can use hasSimpleContent() and hasComplexContent() to test these: simple content are text nodes, attribute nodes, or a single XML element with no XML node children (such as <age>26</age>). This means you can print out my age with:

trace(thePeople.person.(@name == "Roger Braunstein").age); //26

Even though this expression returns an XMLList, that list happens to have just one element, an XML node with a text child, and XMLList.toString() prints out its text value, 26. The same applies for:

trace(thePeople.person[0].@name); //Mims Wright

Use toString() as a simple way to get text content out of attributes and simple XML containers like <age>26</age>.

If you want to ensure that the content prints out like XML, use toXMLString().

trace(thePeople.person.(@name == "Roger Braunstein").age.toXMLString()); //<age>26</age>

You can use the text() filter to grab text nodes out of XML. For instance, grabbing an attribute like thePeople.person[0].@name returns a text node. The only child of <age>26</age> is a text node.

trace(thePeople.person[0].age.text()[0]); //27

Again, this filter returns an XMLList of all the text nodes found, and we use array access to grab the first one. We could extract a list of all of the text nodes inside all the age tags with the following:

trace(thePeople..age.text()); //2726

Note that toString() doesn’t add any space. toXMLString() does, but since they’re both text nodes, it prints out as:

27
26

Function-style Properties

In E4X, using a property name in an expression finds child nodes with the specified name, like thePeople.person. We want to be able to name XML nodes anything we want, so all the filters, calculated properties, and functions of XML nodes are implemented as functions. In other words, thePeople.person.length would look for <length> nodes in the XML; but we can find the number of <person> nodes with:

thePeople.person.length(); //2

All the tests and filters are implemented as functions, even if corresponding properties in other classes are implemented as implicit accessors.

Synonyms, Other Axes

An “axis” is a direction of movement. In space, we can travel over the axes x, y, and z. In XML, however, we can travel down to child nodes, sibling nodes, and the like. In the E4X vs. XPath comparison, E4X loses out on axes big-time. It’s missing several important ones.

In the basics, I covered a bunch of directions you can travel already. Those were actually shortcuts for more verbose functions. This list will show which shortcuts exist.

attribute(name), attributes()

These axes find attributes of the corresponding XML. The first filters by the name of the attribute, and the second retrieves a list of all attributes. Their shortcuts are @name and @*.

Important! The attribute(name) axis will frequently serve you better than the @name shortcut! The shortcut only works when the attribute exists on all nodes in the list. This is a huge limitation, and a good reason to use the function version.

thePeople.person.@suffix; //OK, list of all suffix attributes
thePeople.person.(@suffix == "III"); //ERROR!!!
thePeople.person.(attribute("suffix") == "III"); //OK, Mims' node
child(name), children()

These axes find the children of the given node[s]; by child I mean a first-generation descendent. The first finds a child of a specific name, and is the same as typing that name in literally. The second finds all children, which we’ve seen before as the asterisk operator.

The following holds true:

thePeople.child("*") == thePeople.children() == thePeople.*

There are benefits to using this (and all the filters) as axis functions rather than shortcuts. The major benefit is that you can use a variable name as the parameter to an axis function.

var interestedNode:String = "bio";
thePeople.person[0].child(interestedNode); //Mims' bio

You can also pass an index to child() to retrieve a child at a certain index, just like using the array access notation. In my opinion this is more confusing than helpful.

descendants(name)

This axis returns all descendants (children, grandchildren, etc.) of a node set whose node name matches the name passed. Unlike child() and children(), this axis has one function, but if a name is not passed, it will return all the descendants. In other words, it defaults to *. Its shortcut is the double dot (..).

thePeople..age == thePeople.descendants("age")
thePeople..* == thePeople.descendants() == thePeople.descendants("*")
parent()

This axis returns the node’s parent or nodeset’s immediate parents. There is no shortcut for this. For instance:

var age0:XML = thePeople..age[0]; //<age>27</age>
trace(age0.parent().@name); //Mims Wright

Do you notice what’s missing? Yes, siblings would be really nice. It was so easy in AS2 to use nextSibling and previousSibling. But believe it or not, you have to hack your way around this by going to the parent and finding the next index. This is my workaround for sibling traversal. Let me know if you have a better one.

var node:XML = thePeople.person[0];

//in general, for any node:
node.parent().children(); //all siblings
node.parent().*[node.childIndex() + 1]; //next sibling
node.parent().*[node.childIndex() - 1]; //previous sibling

The ancestor axis (parent, grandparent, great-grandparent, etc.) is also missing from E4X.

Node Types

In addition, there are axes which select specific kinds of nodes. In actuality, an XML instance can hold a node of any type: element, comment, text, or processing instruction. This means that XML typed variables aren’t always valid XML documents. A text node by itself is not valid XML.

You can use the nodeKind() function to identify the type of a node. It will return “element,” “comment,” “text,” or “processing-instruction.” Note also that processing instructions and comments are typically ignored unless you change those settings on the XML object.

The elements(), comments(), text(), and processingInstructions() axes select nodes of these types as children.

Creating and Updating Values

When you select nodes with a filter chain, you’ll end up with an XMLList object or XML object. These objects are always pointers to the original data (unless you use copy() to clone them), and they are writable! So you can change attributes and elements that already exist:

thePeople.person[1].age = 80; //sets my age to 80
thePeople.person.age = 80; //ERROR! you can't set multiple elements with one assignment
thePeople.person[1].@suffix = "Sr."; //set my suffix to Sr.

You can create new XML nodes, as we’ve seen, by literally typing them in. In addition, E4X lets you embed variables in XML literals using curly braces:

var names:Array = ["Alice", "Bob", "Ivan"];
var newPerson:XML = <person name={names[int(Math.random() * names.length)]}></person>;

You can use stored values and expressions as not only attribute names, but node names and whole nodes, as well.

var nodeName:String = "age";
var newAge:XML = <{nodeName}>{Math.round(Math.random() * 100)}</{nodeName}>;

var names:Array = ["Alice", "Bob", "Ivan"];
var newPerson:XML =
  <person name={names[int(Math.random() * names.length)]}>
    {newAge}
  </person>;

You can create XMLList literals by using a root tag with no node name. This is kind of cracked out:

var aliases:XMLList = <>
	<aka>Elmo</aka>
	<aka>The Fonz</aka>
	<aka>Peanut Butter</aka>
</>;

Adding Values

There are many ways to append values to existing XML. As with the rest of E4X, there are a lot of shortcuts that sometimes make sense and sometimes not…

Say I want to add an alias to my name. The += operator is overridden for XMLLists, so you can use this as a quick way to append nodes:

thePeople.person[1].aka += <aka>Rog</aka>;
thePeople.person[1].* += <eyes>Brown</eyes>;
thePeople.person[1].children() += <test>hi</test>; //ERROR!

I’m not sure why the last line doesn’t work.

You can also immediately set non-extant values to create them, like pushing to an array by assigning to the first vacant index.

thePeople.person[0].eyes[0] = "Green"; //adds <eyes>Green</eyes> to Mims' node.

Perhaps a more sensical way to insert new nodes into existing XML is to use the appendChild(), insertChildBefore(), and insertChildAfter() methods. These methods take the Object type because they will attempt to convert their argument to a String and insert it as text if you don’t pass XML. But pass XML, and it will work as you might expect:

thePeople.person.(@name == "Mims Wright").appendChild(<aka>Von Kaiser</aka>);

Deleting Values

There is no corresponding removeChild() method. Instead, the delete operator is your only way to remove values. You can use delete with a single node or a whole XMLList, or an attribute.

delete thePeople.person.bio; //delete all <bio> tags
delete thePeople..bio; //Doesn't work but no error. Why?!?
delete thePeople.person.@suffix; //deletes all suffix attributes of <person> tags
delete thePeople.person.(@name == "Roger Braunstein").*; //clears out children of my node

Namespaces

I can write more about namespaces in a future revision, but for now check out the good discussion started in my previous post, Using E4X? Watch Your Namespaces.

There’s one odd addition to the language that’s specified in the E4X spec, and that’s the construct default xml namespace. Whereas opening a namespace allows you to read in XML in that namespace, setting a default XML namespace will also implicitly apply that namespace to new nodes you create.

var xhtml:Namespace = new Namespace("http://www.w3.org/1999/xhtml");
default xml namespace = xhtml;
var xml:XML = <html/>; //notice we didn't set a namespace manually
trace(xml.toXMLString()); //<html xmlns="http://www.w3.org/1999/xhtml"/>


Loading External Data

You can convert any String to XML by using the top-level XML() function. This looks like a cast operator and acts like one as well: it converts its argument to the XML type, but instead of just changing the type annotation, it performs a conversion.

You can use this function to get XML from other functions and variables:

var xmlString:String = '<root><device name="mouse" buttons="2"><connection type="usb"/></device></root>';
var xml:XML = XML(xmlString);
trace(xml.device[0].connection.@type); //usb

You can also use it to load data from an external file with the URLLoader class. Check out the documentation for more info on how to use this class.

var loader:URLLoader = new URLLoader(new URLRequest("http://partlyhuman.com/crossdomain.xml"));
loader.addEventListener(Event.COMPLETE, onLoadSuccess);
loader.addEventListener(IOErrorEvent.IO_ERROR, onLoadFailure);

function onLoadSuccess(event:Event):void
{
	trace("Loaded successfully!");
	var loader:URLLoader = URLLoader(event.target);
	var xml:XML = XML(loader.data);
	trace(xml.toXMLString());
}

function onLoadFailure(event:Event):void
{
	trace("Error loading file: " + event.type);
}

Conclusion

75% of what you’ll need to do with E4X is simple, but there are a bunch of gotchas, and I think it’s not doing AS3 any favors to try to gloss this over. I’m really not sure adding E4X was a great idea — certainly native XML and XML literals are excellent. But according to ECMA, the reasoning behind creating a whole new language for filtering when we have existing languages such as XPath and the Selectors API is that they are too difficult to learn, and not “simple” enough. I’m certainly happy that there’s some native XML support in AS3, but let’s be serious about explaining it.

Again, please add your comments, especially if you have any problems!

Note: If you are going to include XML in your comment, please convert the tags to HTML entities or they will be eaten! Use this tool.

100 Responses to “AS3 E4X Rundown”

  1. devon says:

    @Rian et all Re: #1119: Delete operator is not supported with operand of type XMLList… I have struggled and suffered here also…best I can figure is to access elements of the dynamically created XMLList via array index, ie:
    delete XML_nodes.term.(@tid == e.element.@tid)[0];

  2. Roger, this is a great post. It almost answered my question which took a lot of googling to find. The answer came from Peter Hall at a forum thread here: http://groups.google.com/group/xpath-as3/browse_thread/thread/7929b1384b6bcc5b.

    The question (what is this, jeopardy?) was how to replace the text value of a node, which turns out to be absurdly complicated – or maybe noone knows the official way, including the Flash documentation. Here is peter’s solution which works great, although i am not sure why e4x would make something normal into a crazy reach-around workaround…

    node.parent().children()[node.childIndex()] = “blah”;

    I would suggest adding a section to your post on replacing nodes and content, not just for this hack but also the official replace methods. (Pardon my griping but those methods are badly documented and seem relatively worthless.)

  3. Sam Goody says:

    It is not accepting variables ({}) in external e4x files. Claims it is malformed. Am I the only one with this problem? Is there any solution?

    My ultimate goal is to get a function name or attribute from the e4x. Since as3 has no eval(), I thought I could pass in an attribute as a variable.

    eg:
    in font.xml:

    in as3 file:

    var x:XML = new XML(new URLLoader(new URLRequest(”font.xml”)).data);

    var t:textFormat = newTextformat();
    for(var att:* in x.frmt.attributes) t[att.name()] = att;

    I hope the above is clear. It claims that align is malformed

  4. @Sam, the inline-variable syntax is only valid for XML literals (typed directly into code).

    Your XML was eaten by Wordpress, try editing your comment and using the link provided above the comments.

    Also, you know that you can’t load a file like that right? You have to wait for the URLLoader to complete loading before you can access the data property.

  5. @Moses, yes, there’s a very subtle difference between modifying existing nodes and replacing nodes. Most of the ways you modify data in E4X replacing nodes.

    Also, the problem you’re running into is that, in order to replace nodes, you have to do that from an outside perspective. You can’t just shoot at yourself, you have to stand up on a ledge so you can see what you wanna shoot and then shoot. Weird analogy. So that’s why you have that awkward syntax which jumps up and then finds its way back down.

    It’s a good idea, having a section on replacing and modifying data. I should add that.

  6. Sam Goody says:

    @Roger – Re:My last post
    1)
    I know how to load xml, just wanted the comment to be clean.
    How do I post without Wordpress eating my tags?
    2)
    XML is first and foremost an interchange language: a way that php, flash, aspx, and more could communicate with a common tongue. If you can’t use the power of e4x in external files, that kinda turns it into a vaporware. It is much more likely to have your example file above coming from a database (created by people.php) than residing in the flash file itself!!

    And if the abilities are going to be limited (I also had a problem with external CDATA), let there be clear documentation about the limitations. If you could add it, I think this article is already the semi-official docs ;)
    3)
    I guess the real gripe I have is Adobe dropping eval(). If it was still there, I would be able to evaluate the xml and get my variables and cdata. I also would be able to store the reference to a function inside the xml (func)function1(/func) which I cannot figure out any way of doing now. And to store unencoded urls, etc.
    3)
    I tried to put comments into the external URL using /* — */. It balked. Is that becuase external e4x doesn’t handle comments, or are comments left with a different format?
    4)
    Thanks for the great work

  7. @Sam:

    1. Please use the link provided above the comments thread to encode xml for comments.

    2. Well… XML is the interchange language. E4X is a programming tool. Nobody’s going to change the way XML works for E4X. The {} syntax is a convenient shortcut for creating XML inline… it’s not part of XML. When you load in an XML file with Flash, it had better treat that XML just like everyone else in the world treats XML or it won’t be very good at its job. I did coincidentally run into some problems with CDATA, so I’d like to add a section on that, indeed.

    3. The thing is, AS3 gets its speed from being compiled to a bytecode and then being interpreted by the AVM or even interpreted further into machine code, which all executes way closer to the speed of native applications. That means for you to be able to eval() things, each person’s copy of Flash Player would also have to have a full compiler for AS3. This would make Flash Player much bigger to download which goes against one of Adobe’s big priorities with the Flash Player platform. Furthermore, eval() would bring in a lot of interesting and strange exceptions to think about in terms of application context, security sandbox, compile-time errors in runtime code…

    3.5. Comments in XML must be typed in <!−− this kind of tag −−>

    4. Thanks for making it better with your comments!

  8. E4X: Beginner to Advanced, another great E4X article by Josh Tynjala @ Yahoo!

  9. Andrew says:

    Sorry if I missed this in here if someone already pointed out a technique.
    What would be the best approach for swapping positions of nodes in an xmllist?

  10. Andrew says:

    Well, I got it to work (swapping nodes) but can anyone explain this?

    This works:
    clone = blogs.blog[delNum];
    delete blogs.blog[delNum];
    blogs.insertChildBefore(blogs.blog[delNum-1],clone);

    This does not:
    clone = blogs.blog[delNum];
    blogs.insertChildBefore(blogs.blog[delNum-1],clone);
    delete blogs.blog[delNum];

    For both the above delNum is derived from the dataProvider the XMLList generated.
    ie: var delNum:Number = blogs_cb.selectedIndex

    Sorry if this was obvious but Deleting the node after doing a insertChildBefore was not working for me. I had to use the clone to hold the node while I deleted its original before inserting.

    If there is a better way….?

  11. allika says:

    Is TTS Engine(Text-To-Speech),an inbuilt feature of AS3

  12. Mims Wright says:

    @allika
    TTS is NOT a built-in feature of AS3. If anyone knows of a TTS implementation, let us know!

  13. greycat92 says:

    Along the lines of Moses’ post… I’m having a tough time figuring out how to strip out \r\n\t from text nodes. I’m new to as3 so maybe there’s an easy solution that I’m missing…
    I’m working with an external XML file to read text into some dynamic textfields. I’d like to give my XML file to a non-technical user so they can update the content, but I want to make sure that if they enter extra line breaks, tabs, etc., that these will be removed.
    I know how to use replace() for strings, but I wasn’t sure how to deal with the contents of text nodes in XML.

    Thanks for any help -

  14. @greycat92, one simple solution that might or might not work for you would be to try setting the XML parser to ignore whitespace:

    XML.ignoreWhitespace = true;

    And you’re right to think that a regular expression and String.replace() would do the task handily. To pull a String out of an XML node, you have to realize that the text inside a tag is itself a “text node”. In the example above, thePeople.person[0].age[0] is the whole XML block of the first age node, including the <age> tag itself. To get the text node inside it you could grab it with .text() or simply convert that xml node to its String equivalent (which ignores the XML) with .toString().

    thePeople.person[0].age.text() //"27"

  15. Monkey says:

    Nice Work!

    One think im having trouble with is this..

    Say i have an XML with this structure:

    <projects>
    <project>
    <title>Title1</title>
    <date>Date1</date>
    <url>Url1</url>
    </project>
    <project>
    <title>Title2</title>
    <date>Date2</date>
    <url>Url2</url>
    </project>
    </projects>

    and i want to loop through and pass the individual elements of each project (title, date, url) as seprate variables to a new holder class (ie i have a “Holder” class that displays each record in individual clips).

    Im currently doing this by turning the xml to an array and then looping through passing the variables to the new class instance and attaching to the stage, but im sure there must be an easyer way to do this with e4x!

    Sorry if it makes not sense!

  16. @Monkey, I’m sure your technique is fine. But did you know you can iterate over the XML nodes instead of converting to an array first? The for each.. in loop will take you through all the items in an XMLList:

    for each (var node:XML in projects.project)
    {
       addChild(new Holder(node.title, node.date, node.url));
       //or whatever
    }

    Or you can use the good old for loop:

    for (var i:int = 0; i < projects.project.length(); i++)
    {
       var node:XML = projects.project[i];
       //and then whatever...
    }
  17. Monkey says:

    YAY! i was actually getting close and you just tidy up the loose ends and now it all makes sense!

    Thank you so much!!!

  18. Roger again this is top notch stuff. Really it is. The lack of good documentation for e4x is spooky, even on w3schools of whom manage to explain xpath to a decent level. First you solved my namespaces issue with ur previous post, now my attribute(name) vs @name issue. Haven’t read the whole article yet, but will be back.

    L E G E N D.
    cheers!

  19. [...] in AS3 we have a cool feature of E4X support. The best article on the E4X explanation in AS3 i was able to find is one by Roger Braunstein . However i was not able to find out many Xpath based [...]

  20. Mark Easton says:

    Hey, there. Sorry, I cant see how to edit my last comment. Nevertheless I discovered what my issue was. If you look at this: http://bugs.adobe.com/jira/browse/FB-5859, you will see that the Flex 3 debugger does not support E4X. I was sitting there in the debugger trying out expressions and they were coming up with errors. Great article by the way! Many thanks, Mark.

  21. joshspoon says:

    You are so right. Most E4X examples are poor.

  22. pei says:

    Hi,
    thanks so much for such detail rundown! even a beginner like me feel more comfortable using E4X.

    I have a question though. I would like to build something like tagCloud. So each tag1tag2> will be tagged with few labels. some labels will be repeated. I asked around, and someone mentioned XPATH in as 2.0. I check with many sites and help document didn’t find anything specific to distinct the result of allTags = xxx.*.tag

    I think of one solution to put the result into an array, and check if the tag has been saved, if it is, then mark the usage times +1.

    however i am still wondering if there’s an easier way to deal with it directly with E4X.

    thank you for your help. :)

  23. pei says:

    sorry, my xml was eaten in the comment, in case you don’t understand where the tag1tag2> came from. XD

  24. Volkan says:

    An interesting pitfall on XML and AS3:

    Hi,

    Do not declare any “any” prototype property to Object class or XML and XMLList classes will mulfunction.

    Example: (on any as file linked to your swf)

    // an unnecessary function

    Object.prototype.checkName = function(): Boolean {
    return(this.name == ‘Roger’);
    }

    // this will make attribute (@) access impossible.

  25. Volkan says:

    Yep, this cleaves the children but leaves


    delete thePeople.person.(@name == "Roger Braunstein").*;

    When I tried to completely destroy Roger (I mean the node :) )
    This kicked me with a weird error:


    delete thePeople.person.(@name == "Roger Braunstein");

    but this worked perfectly :


    delete thePeople.person.(@name == "Roger Braunstein")[0];

    hope this helps…

  26. [...] AS3 E4X Rundown – a good E4X reference/refresher [...]

  27. Roger Albuquerque - Brasil says:

    Tnk´s, Roger …

    Excellent article.

  28. Joseph Sikorski says:

    Hey, I was curious about some filtering things. How would you pick out an element based on the contents and/or attributes of one of its descendants?

    I wanted to do something like
    xml.item.( props.prop.attribute( “att” ) == “bar” )
    but that doesn’t work. When I trace the test results, it prints a false for each .

    Is the only way to use a loop EG for each? Why doesn’t the way I tried work? Should it? (From a theoretical or wistful point of view, that is.)

  29. Kleber says:

    Hello guys,

    It’s works fine:

    thePeople.person.(age >= 21)

    But, for selection of AKA node???

    thePeople.person.(aka == “Rog”)

    It’s dont work… any idea?

  30. Kleber, there’s two problems here. First, you’re comparing an XMLList to an int, and to a String. Rather than trust AS3 to convert these automatically, you should probably compare the text inside the node:

    thePeople.person.(parseInt(age.text()) >= 21)

    and

    thePeople.person.(aka.text().toString() == "Rog")

    However, the person nodes have more than one aka node. So even if you query aka children from a single person node such as rogerNode.aka, you’ll actually get an XMLList with two entries. rogerNode.aka.text() will be an XMLList with two text nodes, and calling toString() on this concatenates them: “RogThat Guy”.

    In this case, since there’s multiple aka nodes that you’re searching in, you’d be better off finding the right one of those, and then traveling back up to its parent. Let’s find the right aka node:

    thePeople.person.aka.(text().toString() == "Rog")

    This should find us all the aka nodes that contain the text “Rog”. Now all we have to do is step back up to see who owns that aka node. Because of the way we constructed our query, we know that its parent will be a person node: we specified the type of the nodes all the way down: thePeople, person, aka.

    var foundPerson:XML = thePeople.person.aka.(text().toString() == "Rog")[0].parent();

    Note here we specified we’re happy to find the first person who has an aka of “Rog”. And, when we grab its parent, that’s going to be an XML node and not and XMLList.

    One final word; I’m being this verbose in order to be pedantic. As you found out, ActionScript will often convert variables to the right thing when you need to compare them. So I could have written

    thePeople.person.aka(text() == "Rog")[0].parent()

    or, I could get really lazy and type:

    thePeople..aka(text() == "Rog")[0].parent()

    I think that’s as simple as you can make this particular query, though.

  31. barry says:

    Hi Roger,

    Thanks for the article, any idea how to dynamically set a value within a CDATA tag of an XML literal? Is this possible? I’ve tried this,

    where _value is the variable i want to set the value of the CDATA tag too, but it returns

    Any idea’s?

    cheers.

  32. barry says:

    sorry, this is my xml

    <myXML><![CDATA[{_value}]]></myXML>

  33. Larry Emlich says:

    I think e4x in flex is only easy for developers after they’ve learned it. I was having great difficulty learning to do what I needed to do because the official docs are inadequate.

    Reading your post finally got me over the learning curve. Your comparisons of shortcuts to the equivalent method calls gave me the info I needed to solve my problem.

    Thanks and keep up the good work!

  34. iGman says:

    thePeople.length() // 1

  35. Renato says:

    I am new to Flex and e4x and have been struggling for weeks to find the right way to filter my xml based on two variables, that are set by two comboBox.
    One comboBox defines the language the user wants to read the info. The other defines the product it wants information.

    var selectedProduct (used to filter the attribute)
    var languageSelected (used to filter the child node, based on the selection of the attribute)

    Follows an example of the structure I am playing with:

    0
    Tennis ball
    Our products are etc,etc etc…
    Nossos produtos sao etc, etc, etc

    1
    Jogging shoes
    Our products are etc,etc etc…
    Nossos produtos sao etc, etc, etc

    So for example, if the user selects the prodX1 and the language is PT (portuguese) I should read “Nossos produtos sao etc, etc, etc”.

    Any ideas how to solve it? Thanks in advance….

  36. [...] Actionscript 3 E4X rundown Using E4X with XHTML? Watch your namespaces! [...]

  37. TG says:

    Great article, thank you!

    however, I still can?t understand how to use e4x to filter out dates.
    I have the following XML

    <tour>
    <show date="28 December" city="Buenos Aires" country="Argentina" venue="Teatro Flores" status="SOLD OUT"/>
    <show date="26 December" city="Curitiba" country="Brazil" venue="Hellooch" status="SOLD OUT"/>
    <show date="27 December" city="Sao Paulo" country="Brazil" venue="AVR Festival" status="SOLD OUT"/>
    <show date="23 December" city="Valparaiso" country="Chile" venue="El Huevo" status="SOLD OUT"/>
    <show date="22 December" city="Santiago" country="Chile" venue="Novedades" status="SOLD OUT"/>
    <show date="21 December" city="Concepcion" country="Chile" venue="Sala 2" status="http://www.ticketmaster.com/"/>
    <show date="21 December" city="Monterrey" country="Mexico" venue="Ibex" status="SOLD OUT"/>
    <show date="20 December" city="Mexico City" country="Mexico" venue="Hard Rock Live" status="SOLD OUT"/>
    <show date="17 December" city="Haskovo" country="Bulgaria" venue="KDK" status="SOLD OUT"/>
    <show date="16 December" city="Trinidad" country="Trinidad & Tobago" venue="Hellooch" status="SOLD OUT"/>
    <show date="12 December" city="Sao Paulo" country="Brazil" venue="AVR Festival" status="SOLD OUT"/>
    <show date="11 December" city="Valparaiso" country="Chile" venue="El Huevo" status="SOLD OUT"/>
    <show date="06 December" city="Santiago" country="Chile" venue="Novedades" status="SOLD OUT"/>
    <show date="05 December" city="Concepcion" country="Chile" venue="Sala 2" status="SOLD OUT"/>
    <show date="04 December" city="Monterrey" country="Mexico" venue="Ibex" status="SOLD OUT"/>
    <show date="03 December" city="Mexico City" country="Mexico" venue="Hard Rock Live" status="SOLD OUT"/>
    </tour>

    then I?m trying to put the upcoming dates in one DataGrid and the past in another, but it doesn?t seems to compare properly the date field.

    <mx:Script>
    <![CDATA[
    public var today:Date = new Date();
    ]]>
    </mx:Script>

    <mx:DataGrid dataProvider="{xmlProvider.show.(@date > today)}"/>

    any ideas?

  38. Thank you for this article. It is the best I’ve seen. I’ll be back with questions.

  39. Brian Hancock says:

    Thanks for the article.
    I am a little confused about the return type when filtering using either the square brackets indexed array notation or the the parenthetical predicates. For example
    if I use
    var obj:Object = thePeople.person.age[0] ;
    I can see in the debugger that obj is typed as an XMLList with one XML element, and if I check the toXMLString() method on that XML node it displays “27″
    But if I use
    var obj:Object = thePeople.person.age[0].text() ;
    it similarly returns an XMLList with one XML element but the toXMLString now just shows “27″
    Although the value is what I expect, I do not see how the value “27″ can be considered an XML document or node as it does not have a root element.
    This led me to try
    var x:XML = XML(29) ;
    and it was quite happy about this.
    It seems AS3’s definition of an XML document is a little more inclusive than I expected

    Brian

  40. simplychaos says:

    There actually is a nextSibling, parent, etc… but it’s on the XMLNode object. This make sense, because XMLList seems to be just a way to break XML into smaller chunks for processing, so they’re isolated objects. Each XMLNode however, has: parentNode, nextSibling, previousSibling, firstChild, lastChild, childNodes, and attributes.

    Good post, but needs some proof-reading for technical accuracy. I think you understand how it all works, but the written explanations aren’t always consistent.

  41. [...] not really taken that big step to form the way as2 talkes to XML to E4X. I started my reserch on dispatchevent.org then I viewed the E4X video from Mark Birat the Adobe MAX sessions and it helped put my research [...]

  42. Brendan D. says:

    I’m looking for a way to sum the numeric data in like nodes. Using your XML in the example, I want to create an XMLList for the Age nodes using thePeople..age and then add the two results together. ie: 27+26=53

  43. Marcela E. says:

    Brendan,
    I too was looking for a way to sum numeric data and was able to figure this out by looking at a few other e4x examples:

    var sum:Number = 0;
    xml.person.age.(sum += Number(valueOf()));
    trace(”Sum of ages:”, sum);

    Hope this comment finds you before you drive yourself crazy (or resort to a for…loop).

  44. Shawny says:

    Great post. So I got this idea last night to use an e4x expression as the source of a chart and advanceddatagrid dataProvider. I’ve found that mostly all of the “examples” online and in all the books only look at one or(at most) two nesting levels inside of an xml document. Unfortunately, my needs go beyond showing the number of apples or names of people in a contact list. So here’s some background:

    I have xml that is segregated in different levels, with the first level being a generic role and the second level being one of a type. There can be many different roles and many number of types under each role. Within each type is a list of datapoints that correspond to the specific role and type.

    So last night I was playing around and was able to get my adg to treat an e4x expression as the source by passing comparison values to the attributes which in turn only loaded the data items of interest. My e4x expression was sorta like this:

    I got this to work a couple of times but the dataProvider was not being modified once the values of the typeValue and roleValue changed. So, like an idiot, I started hacking around trying to treat my e4x expression as a solid data provider and it has since stopped working altogether. If Im really nice, and standing in just the right point of the room, I can get the dataProvider to load initially but ONLY for a single attribute comparison ie myColl..role.(@id==someRoleValue) but not for another level into the structure.

    Any words of wisdom would be GREAT at this point. I want to use the XML (or XMLListCollection if need be) as a dataProvider for my charts and datagrid, but since I want to filter the values based upon parent nodes (and be able to filter my data dynamically). I’ve made this work with arrayCollections but I dont want to have to redo my webservices to provide me with flat data just to get this to work. I would think this is the VERY reason for e4x…besides acting as xml processing shorthand :D

  45. Tyler says:

    This line::

    “The variable is already associated with the root node so there?s no need to write into the expression. ”

    just put an end to my 2 hour headache while dealing with converting old AS2 xml into my current Flex 3 Cairngorm project.

    Thank you, thank you, thank you. :- )

    — Now. I iz a pimp.

  46. Michael says:

    Is there a way to use a wildcard filter with a string to filter a title by a single word. So for example, I want to display only the titles that have the word “Flash” in them.

    I created a video player that feeds off the RSS of my blip.tv channel. I can get all the titles and videos but I want to create a custom video player that will only show the videos that have the word “flash” in the title.

  47. Borek says:

    Excellent article, maybe you could just add that the curly braces syntax will work only if the double quotes are missing, i.e. this will work:

    while this will not:

  48. bostown03 says:

    This article is the shiznit!

Leave a Reply