XML Proxy Class
Posted by Jesse Freeman | Filed under Code
This is a little class I built after reading AS 3 Design Patterns by Joey Lott and Danny Patterson1. I use this as a base class for building objects out of XML.
Download and take a look at the source for the XML Proxy Class and I will go over the important functions:
XMLProxyModel
Created by Jesse Freeman on 2007-04-27.
Copyright (c) 2007 bFreeDesign.com All rights reserved.
*/
package {
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.utils.Proxy;
import flash.utils.flash_proxy;
dynamic public class XMLProxyModel extends Proxy implements IEventDispatcher {
public static const INIT:String = "init";
private var eventDispatcher:EventDispatcher;
protected var _data:XML;
public function XMLProxyModel(data:XML) {
_data = data;
eventDispatcher = new EventDispatcher();
}
flash_proxy override function getProperty(name:*):* {
return xml_retriever(name);
}
override flash_proxy function callProperty(name:*, … rest):*
{
var _item:Object = new Object(); // Hack used to allow callProperty
return _item[name].apply(_item, rest);
}
protected function xml_retriever(name:*):*{
//extend this method with xml retrieve pattern;
return null;
}
public function trace_properties():void{
trace("none");
}
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, weakRef:Boolean = false):void {
eventDispatcher.addEventListener(type, listener, useCapture, priority, weakRef);
}
public function dispatchEvent(event:Event):Boolean {
return eventDispatcher.dispatchEvent(event);
}
public function hasEventListener(type:String):Boolean {
return eventDispatcher.hasEventListener(type);
}
public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void {
eventDispatcher.removeEventListener(type, listener, useCapture);
}
public function willTrigger(type:String):Boolean {
return eventDispatcher.willTrigger(type);
}
}
}
Great, so what do with do with it? For starters, let say you want to build a model, or object that is defined by xml. The best example I can use is a photo model for a gallery. Here is sample of what a photo may look like in xml:
<property id="name">< ![CDATA[Photo 1]]></property>
<property id="description">< ![CDATA[Photo 1]]></property>
<property id="large_url">images/image_01.jpg</property>
</photo>
Looks really simple right? Well if we extend off of the XML proxy class and create a new class called PhotoModel we can start putting this xml data to good use.
PhotoModel
Created by Jesse Freeman on 2007-04-27.
Copyright (c) 2007 bFreeDesign.com. All rights reserved.
*/
package {
import XMLProxyModel;
dynamic public class PhotoModel extends XMLProxyModel{
public function PhotoModel(xml_data:XML = null){
super(xml_data);
}
override protected function xml_retriever(name:*):*{
return _data.property.(@id == String(name));
}
override public function trace_properties():void{
var prop_list:XMLList = _data.property;
trace("Photo:");
for each(var item:XML in prop_list) {
var prop_name:String = item.@id.toXMLString();
trace(" "+prop_name+": " + item.(@id == prop_name));
}
}
public function clone():PhotoModel{
return new PhotoModel(_data);
}
}
}
Notice how I overrode the xml_retriever in the PhotoModel. Well this method is where you can define an E4X search to return the xml data inside of the model. So when you create a new PhotoModel you pass it in a set of XML data defining a photo. When you need to get a property, you can access it just like any other object’s property because the Proxy call is being routed through an E4X search in the xml_retriever method. Here is an example of it:
var photo_xml:XML =
<photo>
<property id="name">< ![CDATA[Photo 1]]></property>
<property id="description">< ![CDATA[Photo 1]]></property>
<property id="large_url">images/image_01.jpg</property>
</photo>;
var photo_model:PhotoModel = new PhotoModel(photo_xml);
trace("name: "+photo_model.name);
You should see the name “Photo 1″ traced out into the output window. This is a really basic example of how to use something like this but the possibilities are endless. I know what you are thinking, why would I want to use something like this when I could just use getter’s and setters?
Some of the best examples I can think of all come from sports or data heavy sites. If you have a player and you are loading in stats for the player along with everyone else’s stats in his team you will run into performance issues if you parse out all the data for each player one by one in the list. If you use this XML proxy method, you can keep the data in its native form, and call it only when you need it. Sometimes, a player’s data come withs lots of extra stuff you may not need in Application A but you will need in Application B. Since I am lazy I tend to use the same classes all over the place. Usually these are set up in my shared repository. Since you want to keep the Player Model Flexible based on the data you need, using getters and setters are going to be too restrictive.
This method really shines when you build in variable caching. Lets say you need the name of the player in 4 different lists inside of the application. The application is only using one set of data but requesting that player name 4 times multiplied by the total number of players and becomes a little intensive if you are using E4X each time. You could modify the XML Proxy class to store an associate array of properties that have been accessed before instead of repeating the E4X search. This would speed up your application significantly.
This is also a good thing to use when quickly testing an application or building a demo. When the data is in flux, a few quick edits to the xml_retriever method will instantly relink your model to any xml structure changes that may have been made.
Give it a try and let me know what you think!
- Both were good speakers at Flash Belt 2007 [↩]
-
Proxy Guy












