XPath在动态HTML文档中不起作用

时间:2014-06-08 18:07:04

标签: javascript xpath

注意:此问题及其答案适用于大多数/所有支持XPath的编程语言和库,而不仅仅是JavaScript!

使用以下代码创建一个非常简单的HTML页面(实际代码加载了一个远程页面,但我试着把重点放在这里的主要问题上):

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);

第一个alert()显示“[object HTMLDocument]”,另一个alert()显示“null”。这是为什么?我缺少什么使XPath查询工作并让它找到body-element?


编辑:

  • 在示例中添加了“// body”
  • 我想我应该提一下,我使用的是Opera 12.17。是否有任何解决方法可以使我得到相同的结果?

1 个答案:

答案 0 :(得分:2)

第一个XPath选择文档根目录(.是当前上下文)。

第二个为null,因为根上下文中没有body。你可以使用:

/html/body

//body

这将为您提供节点。从那里,您可以使用上下文XPath表达式或DOM方法和属性在上下文中获取子节点。要查看节点名称,可以使用所选节点上的nodeName属性:

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;

JSFiddle 1

此替代版本使用DOM创建节点。

var head = document.createElement("head");
var body = document.createElement("body");
doc.documentElement.appendChild(head);
doc.documentElement.appendChild(body);

它还强制执行命名空间(在第一个示例中在Chrome中被忽略),因此XPath表达式要么需要包含命名空间映射函数(作为evaluate方法的第三个参数,要么忽略它们(使用通配符和本地名称测试,如下例所示)。

doc.evaluate(".//*[local-name()='body']", doc.documentElement, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue.nodeName

请注意,我还使用doc.documentElement作为上下文节点。

在浏览器中试用:

JSFiddle 2