Reputation: 12861
Note: This question and its answer are valid for most/all programming languages and libraries that support XPath, not just JavaScript!
With the following code that creates a very simple HTML-page (the actual code loads a remote page, but I'm trying to put your focus on the main problem here):
var dt = document.implementation.createDocumentType("html", "-//W3C//DTD HTML 4.01 Transitional//EN", "http://www.w3.org/TR/html4/loose.dtd");
var doc = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", dt);
var src = "<head></head><body></body>";
doc.documentElement.innerHTML = src;
alert(doc.evaluate(".", doc, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue);
alert(doc.evaluate("/body", doc, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue);
alert(doc.evaluate("//body", doc, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue);
alert(doc.evaluate("/html", doc, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue);
The first alert()
shows "[object HTMLDocument]", the other alert()
shows "null". Why is that? What am I missing to make XPath queries work and have it find the body-element?
EDIT:
Upvotes: 2
Views: 673
Reputation: 23637
The first XPath selects the document root (.
is the current context).
The second one is null because there is no body
at the root context. You could use:
/html/body
or
//body
This will get you the nodes. From there you can get child nodes in context using contextual XPath expressions or DOM methods and properties. To see the node names you can use the nodeName
property on the node you selected:
doc.evaluate(".", doc, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null)
.singleNodeValue.nodeName;
doc.evaluate("//body", doc, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null)
.singleNodeValue.nodeName;
This alternative version uses DOM to create the nodes.
var head = document.createElement("head");
var body = document.createElement("body");
doc.documentElement.appendChild(head);
doc.documentElement.appendChild(body);
It also enforces a namespace (which is ignored in Chrome, in the first example), so the XPath expressions either need to include a namespace mapping function (as the third parameter of the evaluate
method, or ignore them (using wildcards and local name testing as in the example below).
doc.evaluate(".//*[local-name()='body']", doc.documentElement, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue.nodeName
Note that I also used doc.documentElement
as the context node.
Try it in your browser:
Upvotes: 2