/****************************************************************************** * @(#) XMD.as A Flash/ActionScript XML utility class * Copyright (c) 2003 Emmanuel Okyere * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://opensource.org/licenses/cpl.php * * Contributers: * Emmanuel Okyere - initial API and implementation * Luar Yen - Bug Fix and Enhanced Version ******************************************************************************/ import mx.events.EventDispatcher; /** * A utility class that extracts the data in xml files--attributes, nodes * and associated values--and creates an object for use in ActionScript * with Flash, based on the structure of the xml file. Multiple nodes * with the same name at the same level--siblings with the same node name-- * are returned collectively as an Array, otherwise node names become keys * for an associative array that maps to the individual node values. * * * @version 1.0, 11/2003 */ dynamic class XMD { private var data:Object, xml:Object; public var addEventListener:Function; public var removeEventListener:Function; public var dispatchEvent:Function; public var dispatchQueue:Function; private static var _mixin1 = new EventDispatcher.initialize(XMD.prototype); function XMD() { data = new Object(); xml = new XML(); xml.ignoreWhite = true; xml.delegator = this; xml.onLoad = function(success) { // Luar Hack for prevent infinite loop in non existing xml file if (success) { var data:Object = this.delegator.parse(this.firstChild); var cnt:Number = 0; for (var i in data) { ++cnt; if (cnt>1) { break; } } if (cnt == 1) { data = data[i]; } this.delegator.data = data; this.delegator.finalize(); } else { var eventObj:Object = {target:this, type:"onXMDLoad"}; eventObj.success = success; this.delegator.dispatchEvent(eventObj); } }; } /** * Accepts a string representing the URL to the xml file to be parsed, * and loads the xml file. Once the file is successfully loaded, the * data in the xml file is extracted, and onLoad is called. * * @param url URL (String) to file containing xml structure to be parsed * * @see #onLoad() */ public function load(url:String) { xml.load(url); } /** * Called after the data from the xml file has been fully loaded and * extracted. At this point, calling getData() will return * all the data from the xml file converted into proper and associative * arrays (objects). *

* Developers *SHOULD* override this method *

* * @see #load() * @see #getData() */ public function onLoad() { } /** * Provides access to the parsed xml data. It is best to * call this method in the onLoad method which shd be overriden * by developers. * * @return Returns the parsed data from the xml structure * * @see #onLoad() */ public function getData() { return data; } /** * The meat of the class, it recursively converts an XMLNode object * and its childNodes to either an array or associative array, based * on the structure of the node. *

* At each level of the node and its childNodes, siblings with * identical names have their values coallesced into a single (proper) array * otherwise they are returned as an associative array. *

* * @param node The XMLNode to be parsed * @return Returns an Objectized equivalent of the node * * @see #getValue() * @see #getAttributes() */ private function parse(node:XMLNode):Object { var value:Object = new Object(); var nodes:Number = node.childNodes.length; for (var i = 0; i != nodes; ++i) { var name:String = node.childNodes[i].nodeName; if (name != null) { if (value[name] != undefined) { if (!(value[name] instanceof Array)) { value[name] = new Array(value[name]); } value[name].push(getValue(node.childNodes[i])); } else { value[name] = getValue(node.childNodes[i]); } } else { value = getValue(node.childNodes[i]); } } var attributes:Object = getAttributes(node); if (attributes != null) { if (nodes != 0) { if (!(value instanceof XMLNode)) { for (var i in value) { attributes[i] = value[i]; } } else { attributes['_val'] = value.nodeValue; } } return attributes; } return value; } /** * Queries the passed XMLNode for attributes and returns an * associative array, where attribute names act as keys that map to attribute * values. If no attributes are found, null is returned. * * @param node XML node from which to extract attributes * @return Returns an associative array of the attributes/vals found on * on the XMLNode passed to it, null otherwise */ private function getAttributes(node:XMLNode):Object { var attributes = new Object(); for (var i in node.attributes) { attributes[i] = node.attributes[i]; } return i != undefined ? attributes : null; } /** * Accepts an XMLNode, parses it if necessary, and * returns its value. * * @param node XML node from which to extract value * @return Returns the value of the node */ private function getValue(node:XMLNode):Object { switch (node.nodeType) { case 1 : return parse(node); case 3 : // Luar Hack for return data type String, not Object return node.toString(); } return null; } /** * cleans up any unnecessary data left lying around, and calls * onLoad */ private function finalize() { delete xml; /* Instead of calling an onLoad method, I have modified * the code slightly to broadcast a message when the XML * has been parsed * - ddura */ var eventObj:Object = {target:this, type:"onXMDLoad"}; eventObj.data = data; eventObj.success = true; dispatchEvent(eventObj); // onLoad(); } } /***************************************************************************** * changelog * 5th Augest 2004, Return node value in String (original version, it's data type is Object) * 5th Auguest 2004, Bug Fix by Luar for not exist XML cause infinite loop * 02/02/2004 07:14 AM cleaned up doc * 02/02/2004 08:00 AM added Event Broadcaster logic, removed onLoad call - ddura *****************************************************************************/