function XmlToJSONConvertor() {
    var self = this;
    var xmlDoc;
    var xmlhttp = null;
    
    this.escapeXML = true;
    this.ignoreWhiteSpace = true;
    this.stripTagsInCDATASections = false;
    
    this.loadXML = function(xmlPath, callbackFunction) {
        /*
        if(typeof(xmlPath)!="string" || xmlPath.length==0) {
            throw("Error in XmlToJsonConvertor: The URL doesn't appear to be valid");
            return;
        }
        
	    if (document.implementation && document.implementation.createDocument) {
		    xmlDoc = document.implementation.createDocument("", "", null);
		    xmlDoc.onload = function() {
		        callbackFunction(convertXMLToJson());
		    }
	    } else if (window.ActiveXObject) {
		    xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
		    xmlDoc.onreadystatechange = function () {
			    if (xmlDoc.readyState == 4) callbackFunction(convertXMLToJson());
		    };
 	    } else {
		    throw("Error in XmlToJsonConvertor: The browser cannot handle the scripts in this page.");
		    return;
	    }
	    xmlDoc.load(xmlPath);
	    */
        
        if (window.XMLHttpRequest) {        // code for Mozilla, etc.
            xmlhttp=new XMLHttpRequest();
        } else if (window.ActiveXObject) {  // code for IE
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }

        if (xmlhttp!=null) {
            xmlhttp.onreadystatechange = function() {
                if(xmlhttp.readyState == 4) {
                    if(xmlhttp.status == 200) {
                        xmlDoc = (new DOMParser()).parseFromString(xmlhttp.responseText, "text/xml");
                        callbackFunction(convertXMLToJson());
                    } else {
						alert("Problem retrieving XML data");
                    }
                }
            }
            
            xmlhttp.open("GET", xmlPath,true);
            xmlhttp.send(null);
        } else {
            alert("Your browser does not support XMLHTTP.")
        }
    }
    
    function convertXMLToJson() {
        if(self.ignoreWhiteSpace)
            cleanWhitespaceInDom(xmlDoc);

        return(parseXMLForJSON(xmlDoc));
    }
    
    function escape(stringValue) {
        if(!self.escapeXML)
            return stringValue;
        
        stringValue = stringValue.replace(/&amp;/gi, "&");
        stringValue = stringValue.replace(/&rsquo;/gi, "’");
        stringValue = stringValue.replace(/&quot;/gi, "\"");
        stringValue = stringValue.replace(/&lt;/gi, "<");
        stringValue = stringValue.replace(/&gt;/gi, ">");
        stringValue = stringValue.replace(/&nbsp;/gi, " ");
        stringValue = stringValue.replace(/&apos;/gi, "'");
        stringValue = stringValue.replace(/&iexcl;/gi, "¡");
        stringValue = stringValue.replace(/&cent;/gi, "¢");
        stringValue = stringValue.replace(/&copy;/gi, "©");
        stringValue = stringValue.replace(/&laquo;/gi, "«");
        stringValue = stringValue.replace(/&reg;/gi, "®");
        stringValue = stringValue.replace(/&micro;/gi, "µ");
        stringValue = stringValue.replace(/&acute;/gi, "´");
        stringValue = stringValue.replace(/&para;/gi, "¶");
        stringValue = stringValue.replace(/&cedil;/gi, "¸");
        stringValue = stringValue.replace(/&ordm;/gi, "º");
        stringValue = stringValue.replace(/&raquo;/gi, "»");
        stringValue = stringValue.replace(/&ldquo;/gi, "“");
        stringValue = stringValue.replace(/&rdquo;/gi, "”");
        stringValue = stringValue.replace(/’/gi, "'");
        stringValue = stringValue.replace("%3A", ":");

        return(stringValue);
    }
    
    function parseXMLForJSON(elem) {
        //  COMMENT_NODE
        if ( elem.nodeType == 7 ) {
            return;
        }

        //  TEXT_NODE CDATA_SECTION_NODE
        if ( elem.nodeType == 3 || elem.nodeType == 4 ) {
            var bool = elem.nodeValue.match( /[^\x00-\x20]/ ); // for Safari
            if ( bool == null ) return;     // ignore white spaces
        }

        var retval;
        var cnt = {};

        //  parse attributes
        if ( elem.attributes && elem.attributes.length ) {
            retval = {};
            for ( var i=0; i<elem.attributes.length; i++ ) {
                var key = elem.attributes[i].nodeName;
                if ( typeof(key) != "string" ) continue;
                var val = elem.attributes[i].nodeValue;
                if ( ! val ) continue;
                if ( typeof(cnt[key]) == "undefined" ) cnt[key] = 0;
                cnt[key] ++;
                addNode( retval, key, cnt[key], val );
            }
        }

        //  parse child nodes (recursive)
        if ( elem.childNodes && elem.childNodes.length ) {
            var textonly = true;
            if ( retval ) textonly = false;        // some attributes exists
            for ( var i=0; i<elem.childNodes.length && textonly; i++ ) {
                var ntype = elem.childNodes[i].nodeType;
                if ( ntype == 3 || ntype == 4 ) continue;
                textonly = false;
            }
            if ( textonly ) {
                if ( ! retval ) retval = "";
                for ( var i=0; i<elem.childNodes.length; i++ ) {
                    retval += escape(elem.childNodes[i].nodeValue);
                }

                if(self.stripTagsInCDATASections) {
                    retval = retval.replace(/<.*?>/g, "");
                }
            } else {
                if ( ! retval ) retval = {};
                for ( var i=0; i<elem.childNodes.length; i++ ) {
                    var key = elem.childNodes[i].nodeName;
                    if ( typeof(key) != "string" ) continue;
                    var val = parseXMLForJSON( elem.childNodes[i] );
                    if ( ! val ) continue;
                    if ( typeof(cnt[key]) == "undefined" ) cnt[key] = 0;
                    cnt[key] ++;
                    addNode( retval, key, cnt[key], val );
                }
            }
        }
        return retval;
    }
    
    function addNode ( hash, key, cnts, val ) {
        if ( this.usearray == true ) {              // into array
            if ( cnts == 1 ) hash[key] = [];
            hash[key][hash[key].length] = val;      // push
        } else if ( this.usearray == false ) {      // into scalar
            if ( cnts == 1 ) hash[key] = val;       // only 1st sibling
        } else if ( this.usearray == null ) {
            if ( cnts == 1 ) {                      // 1st sibling
                hash[key] = val;
            } else if ( cnts == 2 ) {               // 2nd sibling
                hash[key] = [ hash[key], val ];
            } else {                                // 3rd sibling and more
                hash[key][hash[key].length] = val;
            }
        } else if ( this.usearray[key] ) {
            if ( cnts == 1 ) hash[key] = [];
            hash[key][hash[key].length] = val;      // push
        } else {
            if ( cnts == 1 ) hash[key] = val;       // only 1st sibling
        }
    }
    
    function cleanWhitespaceInDom(node) {
        for (var x = 0; x < node.childNodes.length; x++) {
            var childNode = node.childNodes[x];
            if ((childNode.nodeType == 3)&&(!/\S/.test(childNode.nodeValue))) {
                // that is, if it's a whitespace text node
                node.removeChild(node.childNodes[x]);
                x--;
            }
            if (childNode.nodeType == 1) {
                // elements can have text child nodes of their own
                cleanWhitespaceInDom(childNode);
            }
        }
    }
}

/* from http://erik.eae.net/archives/2005/07/03/20.19.18/ */
if (typeof DOMParser == "undefined") {
   DOMParser = function () {}

   DOMParser.prototype.parseFromString = function (str, contentType) {
      if (typeof ActiveXObject != "undefined") {
         var d = new ActiveXObject("MSXML.DomDocument");
         d.loadXML(str);
         return d;
      } else if (typeof XMLHttpRequest != "undefined") {
         var req = new XMLHttpRequest;
         req.open("GET", "data:" + (contentType || "application/xml") +
                         ";charset=utf-8," + encodeURIComponent(str), false);
         if (req.overrideMimeType) {
            req.overrideMimeType(contentType);
         }
         req.send(null);
         return req.responseXML;
      }
   }
}
