if (jXmlDom._HAS_DOM_FEATURE && document.implementation.hasFeature("XPath", "3.0"))
{
    jNodeList = function (i){this.length = i;};
    jNodeList.prototype = [];
    jNodeList.prototype.constructor = Array;
    jNodeList.prototype.item = function(i) {return (i < 0 || i >= this.length) ? null : this[i];};
    jNodeList.prototype.expr = "";

    if (window.XMLDocument && (!XMLDocument.prototype.setProperty))
        XMLDocument.prototype.setProperty  = function(x,y) {};

    jXmlDom.setXpathNamespaces = function(doc, nss)
    {
        doc._jUseCustomResolver = true;

        var namespaces = nss.indexOf(" ") > -1 ? nss.split(" ") : [nss];
        
        doc._jXpathNamespaces = [];

        for(var i = 0; i < namespaces.length; i++)
        {
            var ns = namespaces[i];
            var colonPos = ns.indexOf(":");
            var assignPos = ns.indexOf("=");
        
            if (colonPos > 0 && assignPos > colonPos+1)
            {
                var prefix = ns.substring(colonPos + 1, assignPos);
                var uri = ns.substring(assignPos + 2, ns.length - 1);
                doc._jXpathNamespaces[prefix] = uri;
            }
            else
            {
                throw "Bad format on namespace declaration(s) given";
            }
        }
    };
    
    XMLDocument.prototype._jUseCustomResolver = false;
    XMLDocument.prototype._jXpathNamespaces = [];
    XMLDocument.prototype.selectNodes = function(expr, node, single)
    {
        var nsDoc = this;
        var nsresolver;
        
        if(this._jUseCustomResolver)
        {
            nsresolver = function(prefix)
            {
                var s = nsDoc._jXpathNamespaces[prefix];
            
                if (s)
                    return s;
                
                throw "No namespace URI found for prefix: '" + prefix + "'";
            };
        }
        else
        {
            nsresolver = this.createNSResolver(this.documentElement);
        }
        
        var result = null;
        
        if (!single)
        {
            var evalResult = this.evaluate(expr, (node ? node : this), nsresolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var nodeList = new jNodeList(evalResult.snapshotLength);

            nodeList.expr = expr;

            for(var i = 0; i < nodeList.length; i++)
                nodeList[i] = evalResult.snapshotItem(i);
            
            result = nodeList;
        }
        else
        {
            result = this.evaluate(expr, (node ? node : this), nsresolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
        }
        
        return result;      
    };
    
    Element.prototype.selectNodes = function(expr)
    {
        var doc = this.ownerDocument;
    
        if (doc.selectNodes)
            return doc.selectNodes(expr, this);

        throw "Method selectNodes is only supported by XML Elements";
    };

    XMLDocument.prototype.selectSingleNode = function(expr, node)
    {
        var ctx = node ? node : null;
        return this.selectNodes(expr, ctx, true);
    };
    
    XMLDocument.prototype.loadXML = function(xml) 
    {
        var parser = new DOMParser();
        var xmlDom = parser.parseFromString(xml, "text/xml");
    
        while (this.firstChild)
            this.removeChild(this.firstChild);
   
        for (var i = 0; i < xmlDom.childNodes.length; i++) 
            this.appendChild(this.importNode(xmlDom.childNodes[i], true));
    
        return xmlDom;
    };
    
    Element.prototype.selectSingleNode = function(expr)
    {
        var doc = this.ownerDocument;
    
        if (doc.selectSingleNode)
        {
            return doc.selectSingleNode(expr, this);
        }
        else
        {
            throw "Method selectNodes is only supported by XML Elements";
        }
    };
    
    Element.prototype.__defineGetter__("xml", function()
    {
        var serializer = new XMLSerializer();
        var xml = serializer.serializeToString(this, "text/xml");
        return xml;
    });

    Element.prototype.__defineGetter__("text", function()
    {
        return this.textContent;
    });

    Node.prototype.__defineGetter__("text", function()
    {
        return this.textContent;
    });

    jXmlDom.IS_ENABLED_SELECT_NODES = true;
}

