XPath:有没有办法为查询设置默认命名空间?

有没有办法将Java的XPath设置为表达式的默认名称空间前缀? 例如,代替:/ html:html / html:head / html:title / text()“,查询可以是:/ html / head / title / text()

使用命名空间前缀时,必须有一种更优雅的方式。

我现在正在做的示例代码片段:

Node node = ... // DOM of a HTML document XPath xpath = XPathFactory.newInstance().newXPath(); // set to a NamespaceContext that simply returns the prefix "html" // and namespace URI ""http://www.w3.org/1999/xhtml" xpath.setNamespaceContext(new HTMLNameSpace()); String expression = "/html:html/html:head/html:title/text()"; String value = xpath.evaluate(query, expression); 

很不幸的是,不行。 几年前有一些关于为JxPath定义默认命名空间的讨论 ,但是快速查看最新的文档并不表示发生了任何事情。 不过,您可能希望花更多时间浏览文档。

如果你真的不关心命名空间,那么你可以做的一件事就是在没有它们的情况下解析文档。 只需省略您当前对DocumentBuilderFactory.setNamespaceAware()的调用。

另外,请注意您的前缀可以是您想要的任何内容; 它不必匹配实例文档中的前缀。 所以你可以使用h而不是html ,并尽量减少前缀的视觉混乱。

我实际上没有尝试过这个,但是根据NamespaceContext文档,带有前缀“”(emtpy string)的名称空间上下文被认为是默认名称空间。


那个我有点太快了。 如果在XPath表达式“/ html / head / title / text()”中根本没有使用前缀,则XPath求值程序不会调用NamespaceContext来解析“”前缀。 我现在要进入XML详细信息,我不是100%肯定,但使用像“/:html /:head /:title / text()”这样的表达式可以与Sun JDK 1.6.0_16一起使用,并且会询问NamespaceContext解析空前缀(“”)。 这是非常正确和预期的行为还是Xalan中的错误?

我知道这个问题已经过时了,但我花了3个小时研究试图解决这个问题, @ kdgregorys的回答帮了我很多。 我只是想把我用kdgregorys答案作为指导。

问题是,如果你的查询没有前缀,java中的XPath甚至不会查找命名空间,因此要将查询映射到特定的命名空间,你必须为查询添加前缀。 我使用任意前缀来映射到模式名称。 对于这个例子,我将使用OP的命名空间和查询以及前缀abc 。 你的新表达式如下所示:

String expression = "/abc:html/abc:head/abc:title/text()";

然后执行以下操作

1)确保您的文档设置为名称空间感知。

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); 

2)实现将解析前缀的NamespaceContext 。 这是我从SO上的其他post中获取并修改了一下

 public class NamespaceResolver implements NamespaceContext { private final Document document; public NamespaceResolver(Document document) { this.document = document; } public String getNamespaceURI(String prefix) { if(prefix.equals("abc")) { // here is where you set your namespace return "http://www.w3.org/1999/xhtml"; } else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) { return document.lookupNamespaceURI(null); } else { return document.lookupNamespaceURI(prefix); } } public String getPrefix(String namespaceURI) { return document.lookupPrefix(namespaceURI); } @SuppressWarnings("rawtypes") public Iterator getPrefixes(String namespaceURI) { // not implemented return null; } } 

3)创建XPath对象时,设置NamespaceContext。

 xPath.setNamespaceContext(new NamespaceResolver(document)); 

现在,无论实际的模式前缀是什么,您都可以使用自己的前缀来映射到正确的模式。 所以使用上面的类的完整代码看起来像这样。

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); Document document = factory.newDocumentBuilder().parse(sourceDocFile); XPathFactory xPFactory = XPathFactory.newInstance(); XPath xPath = xPFactory.newXPath(); xPath.setNamespaceContext(new NamespaceResolver(document)); String expression = "/abc:html/abc:head/abc:title/text()"; String value = xpath.evaluate(query, expression);