﻿/**
	XMLDocument.toObjectAsync(url, function(returnObject) {
		alert("The object has " + returnObject.length + " members.");
	});
*/

XMLDocument = {

	inIE: function() {
		return (typeof window.ActiveXObject == "function");
	},
	
	inMozilla: function() {
		return (document.implementation && typeof document.implementation.createDocument == "function");
	},

	/**	This work is licensed under Creative Commons GNU LGPL License.
		License: http://creativecommons.org/licenses/LGPL/2.1/
		Version: 0.9
		Author:  Stefan Goessner/2006
		Web:     http://goessner.net/ 
	*/
	toObject: function(xmlInDOM) {
			var xml = xmlInDOM;
			var X = {
				toObj: function(xml) {
		        var o = {};
		        if (xml.nodeType==1) {   // element node ..
		            if (xml.attributes.length)   // element with attributes  ..
						for (var i=0; i<xml.attributes.length; i++)
							o[/*"@"+*/xml.attributes[i].nodeName] = (xml.attributes[i].nodeValue||"").toString();
		            if (xml.firstChild) { // element has child nodes ..
						var textChild=0, cdataChild=0, hasElementChild=false;
						for (var n=xml.firstChild; n; n=n.nextSibling) {
							if (n.nodeType==1) hasElementChild = true;
							else if (n.nodeType==3 && n.nodeValue.match(/[^ \f\n\r\t\v]/)) textChild++; // non-whitespace text
							else if (n.nodeType==4) cdataChild++; // cdata section node
						}
						if (hasElementChild) {
							if (textChild < 2 && cdataChild < 2) { // structured element with evtl. a single text or/and cdata node ..
		                    X.removeWhite(xml);
								for (var n=xml.firstChild; n; n=n.nextSibling) {
		                        if (n.nodeType == 3)  // text node
									o["#text"] = X.escape(n.nodeValue);
		                        else if (n.nodeType == 4)  // cdata node
									o["#cdata"] = X.escape(n.nodeValue);
		                        else if (o[n.nodeName]) {  // multiple occurence of element ..
									if (o[n.nodeName] instanceof Array)
										o[n.nodeName][o[n.nodeName].length] = X.toObj(n);
									else
										o[n.nodeName] = [o[n.nodeName], X.toObj(n)];
		                        }
		                        else  // first occurence of element..
									o[n.nodeName] = X.toObj(n);
								}
							}
							else { // mixed content
								if (!xml.attributes.length)
									o = X.escape(X.innerXml(xml));
								else
									o["#text"] = X.escape(X.innerXml(xml));
							}
						}
						else if (textChild) { // pure text
							if (!xml.attributes.length)
								o = X.escape(X.innerXml(xml));
							else
								o["#text"] = X.escape(X.innerXml(xml));
						}
						else if (cdataChild) { // cdata
							if (cdataChild > 1)
								o = X.escape(X.innerXml(xml));
							else
								for (var n=xml.firstChild; n; n=n.nextSibling)
									o["#cdata"] = X.escape(n.nodeValue);
						}
					}
		            if (!xml.attributes.length && !xml.firstChild) o = null;
		        }
		        else if (xml.nodeType==9) { // document.node
					o = X.toObj(xml.documentElement);
		        }
		        else
					alert("unhandled node type: " + xml.nodeType);
		        return o;
		    },
		    toJson: function(o, name, ind) {
				var json = name ? ("\""+name+"\"") : "";
				if (o instanceof Array) {
					for (var i=0,n=o.length; i<n; i++)
						o[i] = X.toJson(o[i], "", ind+"\t");
						json += (name?":[":"[") + (o.length > 1 ? ("\n"+ind+"\t"+o.join(",\n"+ind+"\t")+"\n"+ind) : o.join("")) + "]";
					}
					else if (o == null)
						json += (name&&":") + "null";
					else if (typeof(o) == "object") {
						var arr = [];
						for (var m in o)
							arr[arr.length] = X.toJson(o[m], m, ind+"\t");
						json += (name?":{":"{") + (arr.length > 1 ? ("\n"+ind+"\t"+arr.join(",\n"+ind+"\t")+"\n"+ind) : arr.join("")) + "}";
					}
					else if (typeof(o) == "string")
						json += (name&&":") + "\"" + o.toString() + "\"";
					else
						json += (name&&":") + o.toString();
					return json;
				},
				innerXml: function(node) {
					var s = ""
					if ("innerHTML" in node)
						s = node.innerHTML;
					else {
						var asXml = function(n) {
						var s = "";
						if (n.nodeType == 1) {
							s += "<" + n.nodeName;
							for (var i=0; i<n.attributes.length;i++)
								s += " " + n.attributes[i].nodeName + "=\"" + (n.attributes[i].nodeValue||"").toString() + "\"";
							if (n.firstChild) {
								s += ">";
								for (var c=n.firstChild; c; c=c.nextSibling)
									s += asXml(c);
								s += "</"+n.nodeName+">";
							}
							else
								s += "/>";
						}
						else if (n.nodeType == 3)
							s += n.nodeValue;
						else if (n.nodeType == 4)
							s += "<![CDATA[" + n.nodeValue + "]]>";
						return s;
		            };
		            for (var c=node.firstChild; c; c=c.nextSibling)
		               s += asXml(c);
				}
			return s;
				},
				escape: function(txt) {
					return txt.replace(/[\\]/g, "\\\\")
							.replace(/[\"]/g, '\\"')
							.replace(/[\n]/g, '\\n')
							.replace(/[\r]/g, '\\r');
				},
				removeWhite: function(e) {
				    if (e == null) return "";
					for (var n = e.firstChild; n; ) {
						if (n.nodeType == 3) {  // text node
							if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { // pure whitespace text node
								var nxt = n.nextSibling;
								e.removeChild(n);
								n = nxt;
							}
						else
							n = n.nextSibling;
		            }
		            else if (n.nodeType == 1) {  // element node
						X.removeWhite(n);
						n = n.nextSibling;
		            }
		            else                      // any other node
						n = n.nextSibling;
		        }
		        return e;
		     }
		};
		if (xml.nodeType == 9) // document node
			xml = xml.documentElement;
		var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, "\t");
		//alert(json);
		return eval("({" + json + "})"); 
	},
	
	create: function() {
		if (XMLDocument.inMozilla() == true)
			return document.implementation.createDocument("", "", null);
		else if(XMLDocument.inIE() == true) 
			return new ActiveXObject("MSXML2.DOMDocument");
		return null;
	},
	
	/**
	 * Asynchronously load and parse an XML document from the specified URL.
	 * When the document is ready, pass it to the specified callback function.
	 * This function returns immediately with no return value.
	 */
	toObjectAsync: function(url, callback) {

		if (XMLDocument.inMozilla() == true) {
		
		    var httpRequest = new XMLHttpRequest();
		    
		    httpRequest.open("GET", url, true);
		    httpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
            httpRequest.onreadystatechange = function() {
            
                if (httpRequest.readyState == 4)
				    callback(XMLDocument.toObject(httpRequest.responseXML));
                
            };
            
            // Trigger the HTTP request
            httpRequest.send(null);
            
            /**
            
            // The above code replaces this simple code:
            
            var xmldoc = XMLDocument.create();
            xmldoc.onload = function() {
				callback(XMLDocument.toObject(xmldoc));
			};
			xmldoc.load(url);
            
            // ...because sometimes callback() never fires!
            
            */
            
		}
		else if(XMLDocument.inIE() == true) {
		
		    // Async by default
		    var xmldoc = XMLDocument.create();
			
			xmldoc.onreadystatechange = function() {
				if (xmldoc.readyState == 4)
					callback(XMLDocument.toObject(xmldoc));
			};
			
		    // Trigger the HTTP request
		    xmldoc.load(url);
		}
		
	}
	
};