/**
* 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];
}
}