http://joshblog.net/2007/05/17/filter-xml-data-with-e4x-in-flash-part-2/
If you haven't read my first post about filtering data with E4X, go check it out now. Today, I'll expand on it to add a few more options that you have at your disposal when working with XML in ActionScript 3.
The following is a simple XHTML document that I will reference in the examples below:
var html:XML = <html>
<body>
<ul class="links">
<li><a href="http://www.yahoo.com/" class="josh">Yahoo!</a></li>
<li><a href="http://www.adobe.com/">Adobe</a></li>
<li><a href="http://www.zeuslabs.us/" class="josh">Zeus Labs</a></li>
</ul>
<div id="intro">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</body>
</html>;
Consider a situation where you want to retrieve all the paragraphs from an XHTML document. Each paragraph could be nested in DIVs, lists, tables, or anything. If we want to retrieve an XMLList of every paragraph in that document, we need to use E4X's .. operator. A single dot only allows you to access direct children of a node, but this operator allows you to drill-down into the hierarchy of every descendant in an XML object to access grandchildren and more.
var paragraphs:XMLList = html..p;
You can combine this new operator with the filtering methods I introduced last time to build some pretty complex queries. The following example retrieves the URLs from all the anchors (links) in unordered lists with the class "links". Notice that I must use the attribute() function because class is an ActionScript keyword.
var urls:XMLList = html..ul.(attribute("class") == "links")..a.@href;
Of course, we don't need to access attributes through the complete hierarchy of their containing elements. Consider a situation where you want want a list of all the values of "class" attributes in an XHTML document. This attribute could appear on almost every element in the document. In most cases, you can directly reference the attribute with the @ symbol.
var classes:XMLList = html..@class; //error for "class"
However, like the previous example, we can't access the "class" attribute as easily because it's an ActionScript keyword. Instead, let's use the decendants() function, which returns every element (not limited to direct children) that is below an XML node, along with the attribute() function to get the "class" attributes. The query will be a little more complex, but I don't think it's unwieldy.
var classes:XMLList = html.descendants().attribute("class");
You'll notice that the query returns every single class attribute in the document, including duplicates. For instance, there are two anchors in document that I have given the class "josh" because they happen to point to sites that have content created by me (this blog, and my employer, Yahoo!). What if I want a list containing only unique items? In other words, how can I get results where the "josh" class only appears once?
Unfortunately, E4X doesn't provide a native way to retrieve a list with only unique values. That's unfortunate because I've found that it's a common requirement. Based on my previous knowledge of combining E4X with ActionScript (remember the trace() call from my last post?), I built the following query that should do the job:
var filteredClasses:XMLList = new XMLList();
html.descendants().(filteredClasses = addUniqueValue(attribute("class"), filteredClasses));
That snippet calls a simple function addUniqueValue() which I've included below.
private function addUniqueValue(value:Object, list:XMLList):XMLList
{
if(!list.contains(value))
{
list += value;
}
return list;
}
As I demonstrated last time, code within parentheses in an E4X query basically runs in a loop for every item in an XMLList. I've used this to my advantage to call a function for each item in the list that checks to see if has been included in the filtered list. Once the full query finishes, an XMLList with unique items has been placed into the filteredClasses variable.
By the way, did you notice that XMLLists support the += operator to append additional items? I didn't know that until I just tried it. Nice.
That should cover everything you need to know to go crazy with E4X. Keep in mind that E4X can be a bit slow if written poorly, and it's important to optimize your queries for large datasets. If you need to filter your data, like I did to get unique values, remember that you can call ActionScript functions and assign values within the parentheses. Finally, don't forget about the attribute() and child() functions. They're very useful for using dynamic strings in your queries. E4X rocks.