JavaScript JavaScript and XML — “XPath” Points for Attention

Time:2019-9-11

XPath is a means designed to find nodes in DOM documents, so the processing of XML is also important. Many browsers implement this standard, IE has its own way of implementation.

DOM3 level XPath

The following code is used to detect whether the browser supports DOM3-level XPath:

var supportsXPath=document.implementation.hasFeature("XPath","3.0");

Among the types defined by the XPath specification at the DOM3 level, the two most important types are

  • XPathEvaluator

  • XPathResult

XPathEvaluatorUsed to evaluate XPath expressions in a specific context. This type consists of three methods:

  • createExpression(expression,nsresolver)Convert the XPath expression and the corresponding namespace information into an XPath expression, which is a compiled version of the query. It is useful to use the same query many times.

  • createNSResolver(node)Create a new XPathNSResolver object based on node’s namespace information. When evaluating XML documents based on namespaces, you need to use XPathNSResolver objects.

  • evaluate(expression.context,nsresolver,type,result)XPath is evaluated in a given context based on specific namespace information, and the remaining parameters specify how to return the result.

The evaluate method is most commonly used. This method receives five parameters:

  1. XPath expression

  2. Context node

  3. Namespace Solver

  4. The type of result returned and the XPathResult object that saves the result (usually null, because the result is returned as a function value).

The third parameter needs to be specified when the XML namespace is used only in the XML code, and if not, null.
The value range of the fourth parameter is one of the following constants:

  • XPathResult.ANY_TYPEReturns the data type that matches the XPath expression

  • XPathResult.NUMBER_TYPE: Figures

  • XPathResult.STRING_TYPEString

  • XPathResult.BOOLEAN_TYPEBoolean value

  • XPathResult.UNORDERED_NODE_ITERATOR_TYPEUnordered set of matching nodes

  • XPathResult.ORDERED_NODE_ITERATOR_TYPEOrdered set of node matches

  • XPathResult.UNORDERED_NODE_SNAPSHOT_TYPEUnordered set of snapshots of matching nodes

  • XPathResult.ORDERD_NODE_SNAPSHOT_TYPEOrderly set of matching node snapshots

  • XPathResult.ANY_UNORDERED_NODE_TYPEReturns a set of matching nodes in a sequence that does not necessarily correspond to the original.

  • XPathResult.FIRST_ORDERED_NODE_TYPEReturns a collection of nodes

The type of result specified determines how the value of the result is obtained.

var result = xmldom.evaluate("employee/name", xmldom.documentElement, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
if (result !== null) {
    var node = result.iterateNext();
    while (node) {
        alert(node.tagName);
        node = result.iterateNext();
    }
}

The XPathResult point iterator returned in the above code needs to be usediterateNext()Method The matching nodes are obtained from the nodes.

Another example is:

var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>","text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.ORDERED_NODE_ITETATOR_TYPE, null);
if (result !== null) {
    var node = result.iterateNext();
    while (node) {
        console.log(node.innerHTML);
        node = result.iterateNext();
    }
}

If you specify a snapshot result type, you must use

  • snapshotItem()Method and

  • snapshotLengthAttribute.

Such as:

var result = xmldom.evaluate("employee/name", xmldom.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (result !== null) {
    for (var i = 0, len = result.snapshotLength; i < len; i++) {
        alert(result.snapshotItem(i).tagName);
    }
}

Another example is:

var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
if (result !== null) {
    for (var i = 0, len = result.snapshotLength; i < len; i++) {
        console.log(result.snapshotItem(i).innerHTML);
    };
}

Single node result

XPathResult.FIRST_ORDERED_NODE_TYPEIt returns a matching node that can pass through the resultsingleNodeValueProperty to access the node.

var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
console.log(result.singleNodeValue.innerHTML); //Oliver

Can passsingleNodeValueProperty to access the node.

Simple type results

Simple types of results pass through

  • booleanValue

  • numberValue

  • stringValue

To visit.

XPathResult.BOOLEAN_TYPE

For Boolean value types, if at least one node matches an XPath expression, the evaluation results return true or false:

var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.BOOLEAN_TYPE, null);
console.log(result.booleanValue); //True

If a node matches “employee / name”, then true is returned.

XPathResult.NUMBER_TYPEandcount()Method:

var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("count(/root/name)", xmldom.documentElement, null, XPathResult.NUMBER_TYPE, null);
console.log(result.numberValue); //2

Number of nodes whose output matches XPath syntax (2)

XPathResult.STRING_TYPE

var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.STRING_TYPE, null);
console.log(result.stringValue); //Oliver

Default type results

  • XPathResult.ANY_TYPEconstant

The type of result returned can be automatically determined.

  • resultTypeattribute

The type of test results that can be detected.

Such as:

var xmldom = null;
var parser = new DOMParser();
xmldom = parser.parseFromString("<root><name>Oliver</name><name>Troy</name></root>", "text/xml");
var result = xmldom.evaluate("/root/name", xmldom.documentElement, null, XPathResult.ANY_TYPE, null);
if (result !== null) {
    switch (result.resultType) {
        case XPathResult.STRING_TYPE:
            console.log(result.stringValue);
            break;
        case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
            var node = result.iterateNext();
            while (node) {
                console.log(node.innerHTML);
                node = result.iterateNext();
            }
            break;
    }
}

For XML evaluation using namespaces:

  • createNSResolver()Method

And creating a function, two ways

  1. adoptcreateNSResolver(node)Method to createXPathNSResolverObject, and then use evaluate () to get the result

Such as:

var nsresolver = xmldom.createNSResolver(xmldom.documentElement);
var result = xmldom.evaluate("wrox:book/wrox:author", xmldom.documentElement, nsresolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
alert(result.snapshotLength);
  1. Define a function that receives a namespace prefix and returns the associated URI

Such as:

var neresolver = function(prefix) {
    switch (prefix) {
        case "wrox":
            return "http://www.wrox.com/";
            // Other prefixes
    }
}
var result = xmldom.evaluate("count(wrox:book/wrox/author)", xmldom.documentElement, nsresolver, XPathResult.NUMBER_TYPE, null);
alert(result.numberValue);

Using XPath across browsers

The first cross-browser approach isselectSingleNode()To receive three parameters: context node, XPath expression, and optional namespace

function selectSingleNode(context, expression, namespace) {
    var doc = (context.nodeType != 9 ? context.ownerDocument : context);
    if (typeof doc.evaluate != "umdefined") {
        var nsresolver = null;
        if (namespace instanceof Object) {
            nsresolver = function(prefix) {
                return namespace[prefix];
            };
        }
        var result = doc.evaluate(expression, context, nsresolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        return (result !== null ? result.singleNodeValue : null);
    } else if (typeof context.selectSingleNode != "undefined") {
        if (namespace instanceof Object) {
            var ns = "";
            for (var prefix in namespace) {
                if (namespaces.hasOwnProperty(prefix)) {
                    ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
                }
            }
            doc.setProperty("SelectionNamespaces": ns);
        }
        return context.selectSingleNode(expression);
    } else {
        throw new Error("no XPath engine found");
    }
}

Here is an example of how to use this function:

var result = selectSingleNode(xmldom.documentElement, "wrox:book/wrox:author", {
    wrox: "http://www.wrox.com/"
});
alert(serializeXml(result));

The following functions are encapsulated across browsersselectNodes()Function, which receives the same three parameters as the previous function.


function selectNodes(context, expression, namespace) {
    var doc = (context.nodeType != 9 ? context.ownerDocument : context);
    if (typeof doc.evaluate != "umdefined") {
        var nsresolver = null;
        if (namespace instanceof Object) {
            nsresolver = function(prefix) {
                return namespace[prefix];
            };
        }
        var result = doc.evaluate(expression, context, nsresolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        var nodes = new Array();
        if (result !== null) {
            for (var i = 0, len = result.snapshotLength; i < len; i++) {
                nodes.push(result.snapshotItem(i));

            }
        }
        return nodes;
    } else if (typeof context.selectSingleNode != "undefined") {
        if (namespace instanceof Object) {
            var ns = "";
            for (var prefix in namespace) {
                if (namespace.hasOwnProperty(prefix)) {
                    ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
                }
            }
            doc.setProperty("SelectionNamespaces": ns);
        }
        var result = context.selectNodes(expression);
        var nodes = new Array();
        for (var i = 0, len = result.length; i < len; i++) {
            nodes.push(result[i]);
        }
        return nodes;
    } else {
        throw new Error("no XPath engine found");
    }
}

Following is an example of the use of the selectNodes () method:

var result = selectNodes(xmldom.documentElement, "wrox:book/wrox:author", {
    wrox: "http://www.wrox.com/"
});
alert(result.length);