/** * com.sekati.data.XMLSA * @version 0.1.1 * @author jason m horwitz | sekati.com * Copyright (C) 2007 jason m horwitz, Sekat LLC. All Rights Reserved. * Released under the MIT License: http://www.opensource.org/licenses/mit-license.php * * Source from ca.nectere.data.XMLSA - XMLSA 0.1.0 - 2006-07-10 * based on XMLSA 1.4 by Max Ziebell @ http://proto.layer51.com/d.aspx?f=957 */ /** * XMLSA converts xml to simple object array * * {@code Usage: * _global.$c.onLoad = function(ok){ * if (ok) loadLanguage(); * }; * -or- * _global.$c.load(fv_configFile); * onEnterFrame = function(){ * trace("config : " + _global.$c.getPercent() ); * if (_global.$c.getPercent() == 100){ * delete onEnterFrame; * loadLanguage(); * } * }; * } */ class com.sekati.data.XMLSA { private var xmlobj:Object; private var $xml:Object; private var $root:Object; private var $parent:Object; private var $version:String; private var attributes:Object; private var _noCache:Boolean = false; // Constructor public function XMLSA(watchXML:Object) { this.xmlobj = watchXML; this.$xml = new Object( ); this.$root = new Object( ); this.$parent = new Object( ); _global.ASSetPropFlags( this, null, 1, 1 ); if (watchXML != undefined) { this._parse.apply( this, arguments ); } ; // hidde all functions to for..in loops _global.ASSetPropFlags( XMLSA.prototype, null, 1, 1 ); } // load public function load():Void { this._cleanup( ); var loader:Object = this._makeLoader( this ); arguments[0] = this._makeURL( arguments[0] ); loader.load.apply( loader, arguments ); //keep ref xmlobj = loader; } // send public function send():Void { this._cleanup( ); arguments[0] = this._makeURL( arguments[0] ); if(arguments.length == 2) { this.$root.send.apply( this.$root, arguments ); } else { this.$root.sendAndLoad.apply( this.$root, arguments[0], new XML( ) ); } } // toString public function toString():String { return this.$xml.toString( ); } // sendAndLoad public function sendAndLoad(host:String, target:Object, method:Function):Void { this._cleanup( ); var loader:Object = this._makeLoader( target ); this.$root.sendAndLoad( this._makeURL( host ), loader, method ); } // search public function search(criteria:Object, recursive:Object):Object { XMLNode.prototype.$criteria = criteria; arguments.shift( ); var result:Object = this._search.apply( this, arguments ); delete (XMLNode.prototype.$criteria); return result; } //return a reference to XML public function getXML():Object { return this.$xml; } // return the value of the firstChild if its a textElement public function getValue():Object { return (this.$xml.firstChild.nodeType == 3 ? this.$xml.firstChild.nodeValue : undefined); } // set a textNode public function setValue( text:Object ):Boolean { // check if the node has a textElement? if (this.$xml.firstChild.nodeType == undefined) { // seems like we have to create one... var tmp_xml:Object = new XML( ); this.$xml.appendChild( tmp_xml.createTextNode( text ) ); return true; // else check if firstChild is a textElement and set it... }else if (this.$xml.firstChild.nodeType == 3) { this.$xml.firstChild.nodeValue = text; return true; // retrun success on setValue // seams like it ain't possible } else { return false; // retrun failed on setValue } } //return the nodeName public function getNodeName():Object { return this.$xml.nodeName; } // append a child public function appendChild(element:Object):Void { if (element instanceof XML) { element = element.firstChild; } this.$xml.appendChild( element ); //XML this._reParse( );//XMLSA } // return a XML object with cloneNode public function cloneNode(rekursiv:Object):Object { return this.$xml.cloneNode( rekursiv );//XML } // this one I added as it's sometimes simpler just want // to add a new member... public function appendElement(name:Object,value:Object,attribs:Object):Void { var temp:Object = new XML( ); this.$xml.appendChild( temp.createElement( name ) ); if (value != null) { this.$xml.lastChild.appendChild( temp.createTextNode( value ) ); } if (typeof(attribs) == "object" ) { // there is a bug in Flash MX so we got to do this... // a direct assignment would add __proto__ and constructor // to the attributes... for (var key in attribs ) { this.$xml.lastChild.attributes[key] = attribs[key]; } } this._reParse( );//XMLSA } // remove child by index public function removeChildByIndex(name:Object,idx:Object):Void { this[name][idx].$xml.removeNode( ); this[name].splice( idx, 1 ); } // remove child by index public function removeNode():Void { this.$xml.removeNode( ); this.$parent._reParse( ); } // insert before public function insertBefore(node:Object):Void { this.$parent.$xml.insertBefore( node, this.$xml ); this.$parent._reParse( ); } //================================================================== //added 2006-06-05 by nectere public function getPercent():Number { var total:Number = xmlobj.getBytesTotal( ); if (total == null) return 0; return Math.round( xmlobj.getBytesLoaded( ) / total * 100 ); } //================================================================== //added 2006-06-08 by nectere public function $(attName:Object, attVal:Object):Object { //find by attributeIndex! //ex; _c.call.index("id", "getPatchesByID").attributes.group; //ex; _c.call.index("id", "getPatchesByID"); //ex; _c.call.$("id", name).end.$("id", "jwt_dev").getValue(); //the attributeName used as index should be unique inside that node //this should reference where we are right now in the structure. //So this can be called from any node for (var i:Object in this) { if (this[i].attributes[attName] == attVal) { return this[i]; break; } } //not found return false; } //================================================================== //mod 2006-06-08 by nectere private function _makeURL(host:String):String { //made the cache system as in option in the constructor if (this._noCache && this._online( )) { var c:Number = (random( 100000 ) + 100000); if (_global.sessionID != undefined) { return host + "?sid=" + _global.sessionID + "&nocache=" + c; } else { return host + "?nocache=" + c; } } else { return host; } } /*************************************************/ // Private /*************************************************/ // Parser // called by the constructor and by reParse private function _parse(node:Object, parent:Object):Void { this.$parent = parent; // make shure we work with XMLNode if (node instanceof XML) { this.$version = "XMLSA 1.4"; this.$root = node; node = node.firstChild; } else { this.$root = this.$parent.$root; } // store a reference to $xml this.$xml = node; this.attributes = node.attributes; if (node.nodeType == 1 && node.firstChild.nodeType != 3) { //if (node.nodeType == 1 and node.firstChild.nodeType != 3) { for (var childCounter:Number = 0; childCounter < node.childNodes.length ; childCounter++) { var tempName:Object = node.childNodes[ childCounter ].nodeName; if (this[ tempName ] == undefined) { this[ tempName ] = new Array( ); this[ tempName ].__resolve = XMLSA.prototype.mixed__resolve; _global.ASSetPropFlags( this[ tempName ], null, 1, 1 ); } this[ tempName ].push( new XMLSA( node.childNodes[childCounter], xmlobj ) ); } } } // reParse // free a brach and reparse it private function _reParse():Void { this._cleanup( ); // parse it again... this._parse( this.$xml, this.$parent ); } private function _cleanup():Void { // delete all for (var found in this) { if (found != "onLoad") { trace( found ); delete (this[found]); } } } private function _online():Boolean { // are we online? return (_root._url.substr( 0, 7 ) == "http://"); } // used by send, load and sendAndLoad private function _makeLoader(target:Object):Object { var loader:Object = new XML( ); loader.ignoreWhite = true; loader.link = target; loader.onLoad = function(ok:Boolean):Void { if (ok) { _global.ASSetPropFlags( this.link, [ "onLoad" ], 1, 1 ); this.link._cleanup( ); _global.ASSetPropFlags( this.link, [ "onLoad" ], 0, 1 ); this.link._parse( this ); this.link.onLoad( true ); // Experimental Session Support //--------------------------------------------------- // use the attribute 'session' in the root tag to // submit a sessionID if you transmit the word // 'timeout' or 'end' the session gets deleted var header:Object = this.link.attributes; if (header.session != undefined) { switch (header.session) { case "timeout": case "end": if (_global.session != undefined) { delete(_global.session); _global.onSessionEnd( header ); } break; default: _global.session = new Object( ); _global.session.id = header.session; _global.onSessionStart( header ); break; } } } else { this.link.onLoad( false ); } }; return loader; } private function _search(recursive:Object):Array { var result:Array = new Array( ); for (var found in this) { for (var node in this[found]) { if (this[found][node].$xml != undefined) { if (this[found][node].$xml.$criteria( ))result.push( this[found][node] ); if (recursive) result = result.concat( this[found][node]._search.apply( this[found][node], arguments ) ); } } } return result; } // new since 1.4 allows notations without a nodenumber because // it defaults them to 0 in that case! (redirection) private function mixed__resolve(found:Object):Object { return this[0][found]; } }