/** * Converts an Xml document to an object corresponding with the xml structure. * * Eg * * * * rocks * * * * Becomes an object in which you can do: myObj.top.children.mychild (has value rocks) * * If a certain node has 2 children with the same name, it becomes an array: * * * rocks * drums * * * * trace (myObj.top.children.mychild[0]); //rocks * trace (myObj.children.mychild[1]); //drums * * If a single string valued node has a type attribute, the value is typed as well (possible types are number and boolean): * * * true * false * * * * The top and children nodes have one or more children, but neither of them of type string, so the type attribute simply * becomes a value of the object (eg top.type traces boolean). The mychild node has only one child and of type string as well, * so top.children.mychild[i] will be of type boolean since it will be converted. * * In general all other attributes becomes properties of the object but name clashes might cause an toArray conversion: * * * * true * false * * * * top will now hold a children object of type array, with element 0 = nothanks, and element1 is another array * * $Id: XML2Obj.as 8 2008-01-10 15:30:33Z hansw $ * * @author J.C. Wichman, TriMM Interactive Media (www.trimm.nl / j.c.wichman@trimm.nl), * ObjectPainters.com (blog.objectpainters.com / j.c.wichman@objectpainters.com) */ class nl.trimm.util.XmlUtil { public static function convert (pXml:XMLNode):Object { return _doConversion (pXml); } private static function _doConversion (pXmlTree:XMLNode):Object { //if xmlnode only has one child and it is a string, return it if (pXmlTree.childNodes.length == 1 && pXmlTree.childNodes[0].nodeName == null) { //only return node value, any attribs are ignored, except type attrib var lReturnValue:Object = pXmlTree.childNodes[0].nodeValue; switch (pXmlTree.attributes.type) { case "number": lReturnValue = Number (lReturnValue); break; case "boolean": lReturnValue = (lReturnValue == "true"); break; default : break; //do nothing } return lReturnValue; } else { if (pXmlTree.attributes == null && pXmlTree.childNodes.length == 0) return null; //if xmlnode has nested children.... var lStore:Object = new Object(); //first store attributes for the current node //attributes are always simple values for (var i:String in pXmlTree.attributes) { lStore[i] = pXmlTree.attributes[i]; } //then do nested children themselves for (var i:Number = 0; i < pXmlTree.childNodes.length; i++) { var lChild:XMLNode = pXmlTree.childNodes[i]; //first time we found a child with this name if (lStore [lChild.nodeName] == null) { lStore[lChild.nodeName] = _doConversion (lChild); } else { //if child was already converted to an array, just add it if (lStore[lChild.nodeName] instanceof Array) { lStore[lChild.nodeName].push (_doConversion(lChild)); } else { //first convert what was already there var currentNode:Object = lStore[lChild.nodeName]; lStore[lChild.nodeName] = new Array (); lStore[lChild.nodeName].push (currentNode); //now add new one: lStore[lChild.nodeName].push (_doConversion (lChild)); } } } return lStore; } } /** * Converts the child with the parent to an array node IF it is not already an array. * If it is already an array nothing happens. * * @param pObject * @param pChild */ public static function forceArrayNode (pParent:Object, pChild:String) { if (pParent[pChild] == null) { return; } //if child was already converted to an array ignore it if (pParent[pChild] instanceof Array) { return; } else { //first convert what was already there var currentNode:Object = pParent[pChild]; pParent[pChild] = new Array (); pParent[pChild].push (currentNode); } } public static function getNodeAsArray (pPath:Object):Array { if (pPath == null) return null; if (pPath instanceof Array) return [pPath][0]; return [pPath]; } }