AS3: E4X for DisplayObjects

This is a little thing I thought about doing as a result of this fk thread: Having E4X (ECMAScript for XML) work for display objects. It makes a lot of sense when you think about it since the display list is very much like XML in its hierarchical structure (or is it the other way around?).

The attached classes let you treat the display list like XML using E4X. Most XML operations are accounted for, including descendants (…) and attribute (property) access through at (@). Filtering is not the same, but made up for with a filter() method. Here’s a rundown of how it works with sample code.

import com.senocular.display.E4DisplayObject;
import com.senocular.display.E4DisplayList;
import com.senocular.display.e4d_internal;

// instantiation
var me:E4DisplayObject = new E4DisplayObject(this);


// property access
this.foo = "bar";
trace(me.@foo); // bar

me.@foo = "none";
trace(this.foo); // none

delete me.@foo;
trace(this.foo); // undefined

// display list traversal
addChild(new Sprite()).name = "a";
addChild(new Shape()).name = "a";
addChild(new MovieClip()).name = "b";
Sprite(getChildByName("a")).addChild(new Shape()).name = "c";
MovieClip(getChildByName("b")).addChild(new Bitmap()).name = "c";

trace(me.a); // [object Sprite], [object Shape]
trace(me.b); // [object MovieClip]
trace(me.c); // 
trace(me.c.valueOf()); // undefined
trace(me.a.c); // [object Shape]
trace(me..c); // [object Bitmap],[object Shape]


// multiple property access
trace(me..c.@alpha); // 1,1
me..c.@alpha = .5;
trace(Sprite(getChildByName("a")).getChildByName("c").alpha); // 0.5
trace(MovieClip(getChildByName("b")).getChildByName("c").alpha); // 0.5 


// method calling
function length() {
	return "hi!";
}
trace(me.length()); // hi!
trace(me.e4d_internal::length()); // 1


// filtering
trace(me.descendants().filterByName("a")); // [object Shape],[object Sprite]
trace(me.a.filterByType(Shape)); // [object Shape]
function customFilter(test:E4DisplayObject):Boolean {
	if (test.@alpha == 0.5){
		return true;
	}
	return false;
}
trace(me.descendants().filter(customFilter)); // [object Bitmap],[object Shape]


// display as XML
trace(me.toXMLString());
/*
<root1>
  <a>
    <c/>
  </a>
  <a/>
  <b>
    <c/>
  </b>
</root1>
*/
trace(me.a.toXMLString(["x", "y", "alpha"]));
/*
<a x="0" y="0" alpha="1">
  <c x="0" y="0" alpha="0.5"/>
</a>
<a x="0" y="0" alpha="1"/>
*/


// alter display list
delete me.a;
trace(me.toXMLString());
/*
<root1>
  <b>
    <c/>
  </b>
</root1>
*/
me.b.d = new MovieClip();
trace(me.toXMLString());
/*
<root1>
  <b>
    <c/>
    <d/>
  </b>
</root1>
*/


// iteration
var childName:String;
for (childName in me){
	trace(childName +": "+ me[childName]); // b: [object MovieClip]
}

var child:E4DisplayObject;
for each(child in me.descendants()){
	trace(child.@name);
}
/*
b
c
d
*/

The source is attached here, and I have the classes online for a quick reference if you don’t want to mess with the download:
Note: The linked classes will be more up to date than the download.
[list]
[]http://www.senocular.com/flash/actionscript.php?file=ActionScript_3.0/com/senocular/display/E4DisplayList.as
[
]http://www.senocular.com/flash/actionscript.php?file=ActionScript_3.0/com/senocular/display/E4DisplayObject.as
[*]http://www.senocular.com/flash/actionscript.php?file=ActionScript_3.0/com/senocular/display/e4d_internal.as
[/list]
More information about what’s going on can be found in the class’ comments.