If you deal with XML documents, you probably appreciate AS3’s support for the E4X operators. These make it really easy to access the XML class like any old object with the .x (dot) operator as well as XML-specific operators like ..x for descendants and @x for attributes. Even fancier, there’s support for arbitrary expressions like .(@id == "123"). With all this convenience we should wonder- how slow are the E4X expressions?

The docs don’t give much information about what you can do with E4X expressions, but they’re generally like other AS3 expressions. The basic form is like this:

xml.(@id == "123")

That will return all elements with an attribute that is “123”. You can use other comparison operators if you convert the attribute string to a numeric value:

xml.(Number(@id) > 123)

The expression can grow more and more complex as you add logical and (&&) and or (||) operators:

xml.(@name == "Smith" && Number(@age) >= 18)

In this example, it’ll return elements where the name attribute is “Smith” and the age attribute is greater than or equal to 18.

So, how does this compare to a more manual approach? These simple E4X expressions can be re-written with a for-each loop combined with an if check. Here’s the manual version of @id == "123":

for each (var elem:XML in xml)
{
    if (elem.@id == "123")
    {
        // do something with the element
    }
}

Now to test the E4X version against the manual version:

package
{
	import flash.display.*;
	import flash.utils.*;
	import flash.text.*;
 
	public class E4XTest extends Sprite
	{
		private var logger:TextField = new TextField();
		private function row(...cols): void
		{
			logger.appendText(cols.join(",") + "\n");
		}
 
		public function E4XTest()
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
 
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			init();
		}
 
		private function init(): void
		{
			const REPS:int = 1000;
			const SIZE:int = 1000;
			var i:int;
			var beforeTime:int;
			var afterTime:int;
			var elem:XML;
			var count:int;
 
			var xmlStr:String = "<xml>";
			for (i = 0; i < SIZE; ++i)
			{
				xmlStr += '<elem id="' + i + '"/>';
			}
			xmlStr += "</xml>";
			var xml:XML = XML(xmlStr);
 
			row("Operation", "Time");
 
			count = 0;
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				for each (elem in xml.elem.(@id == "0"))
				{
					count++;
				}
			}
			afterTime = getTimer();
			row("E4X", (afterTime-beforeTime));
 
			beforeTime = getTimer();
			for (i = 0; i < REPS; ++i)
			{
				for each (elem in xml.elem)
				{
					if (elem.@id == "0")
					{
						count++;
					}
				}
			}
			afterTime = getTimer();
			row("Manual", (afterTime-beforeTime));
		}
	}
}

Run the test

I ran this test in the following environment:

  • Release version of Flash Player 12.0.0.44
  • 2.3 Ghz Intel Core i7-3615QM
  • Mac OS X 10.9.1
  • Google Chrome 32.0.1700.107
  • ASC 2.0.0 build 354071 (-debug=false -verbose-stacktraces=false -inline -optimize=true)

And here are the results I got:

Operation Time
E4X 950
Manual 813

E4X Expression Performance Graph

Both versions are searching all the elements in the XML object, but the E4X version is taking 17% longer. This isn’t hugely slower than the manual version and arguably a lot cleaner, so you may opt to use it in areas of code that aren’t performance-critical. Still, as with the recommendation of previous XML articles, you should probably parse the XML object into a typed class instance for maximum performance.

Spot a bug? Have a question or suggestion? Post a comment!