Document声明单独的空命名空间呈现NamespaceAware结果无用

时间:2017-07-24 12:50:04

标签: java xpath jdom jdom-2

我正在尝试对maven使用的“正确”pom.xml执行一些检索查询。为此我使用JDOM的基本XPath查询。

不幸的是,查询不会返回任何结果(简单的后代过滤器也不会)。我有理由相信问题出在pom.xml的根声明中:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!-- content -->
</project>

可以看出,定义了一个与"""http://www.w3.org/2000/xmlns/"不匹配的空命名空间,其中“”是默认的No-Namespace,xmlns命名空间是默认的xmlns命名空间。

所以给定Document,当我想执行如下的XPath-Query时:

XPathBuilder<Element> depQueryBuilder = new XPathBuilder<>("//dependencies/dependency", Filters.element());
XPathExpression<Element> depQuery = depQueryBuilder.compileWith(XPathFactory.instance());

for  (Element elem : depQuery.evaluate(document)) {
    // basically unreachable, since the resultset is always empty
}

鉴于所有XPath表达式和查询都需要知道名称空间(比较XPathHelper javadoc),我很确定我可以通过添加必需的名称空间声明来实现这一点。

我尝试了以下不同类型的失败:

depQueryBuilder.setNamespace("", document.getRootElement().getAttributeValue("xmlns"));
// NPE: Null URI
depQueryBuilder.setNamespace("", "http://maven.apache.org/POM/4.0.0");
// Cannot set a Namespace URI in XPath for "" prefix
depQueryBuilder.setNamespace(Namespace.NO_NAMESPACE);
// no error-message, but no results either
depQueryBuilder.setNamespace(document.getRootElement().getNamespace("xmlns"));
// NPE: Null Namespace
depQueryBuilder.setNamespace(document.getRootElement().getNamespace(""));
// Cannot set a Namespace URI in XPath for "" prefix
depQueryBuilder.setNamespace("xmlns", "http://maven.apache.org/POM/4.0.0");
// Name "xmlns" is not legal for JDOM/XML Namespace prefix

此时我甚至不确定我是否正确地攻击了这一点。如何让我的XPath查询返回结果?

注意:以下更简单的查询也不会返回结果:

document.getRootElement().getDescendants(Filter.element("dependency"));
// empty iterator
document.getRootElement().getChild("dependencies").getChildren("dependency"));
// NullPointerException because there is no child "dependencies"

1 个答案:

答案 0 :(得分:4)

XPath查询和XML中的文档导航通常需要有效使用命名空间。

XPath特别不遵循与常规XML文档相同的规则,因为""命名空间的处理存在差异。在XML文档中,它指的是&#34;默认&#34;命名空间(无命名空间或通过用xmlns="...."声明覆盖的任何命名空间)。

但是,在XPath中,规则略有不同(请参阅the spec - 强调我的 ):

  

使用表达式上下文中的名称空间声明,将节点测试中的QName扩展为扩展名。这与开始和结束标记 中的元素类型名称进行扩展的方式相同,除了使用xmlns声明的默认命名空间 :如果QName没有一个前缀,然后命名空间URI为空

这实际上意味着,即使您不需要在dependencies之类的XML中使用名称空间前缀,您仍然需要在XPath查询中使用前缀。前缀可以是任何东西 - 不需要匹配XML文档中的任何内容。因此,选择任意名称空间,例如&#39; ns&#39;,您可以查询:

XPathBuilder<Element> depQueryBuilder = new XPathBuilder<>("//ns:dependencies/ns:dependency", Filters.element());
depQueryBuilder.setnamespace("ns", "http://maven.apache.org/POM/4.0.0");
XPathExpression<Element> depQuery = depQueryBuilder.compileWith(XPathFactory.instance());

这可以通过以下方式更简单地完成:

Namespace ns = Namespace.getNamespace("ns", "http://maven.apache.org/POM/4.0.0");
XPathExpression<Element> depQuery = XPathFactory.instance()
  .compile("//ns:dependencies/ns:dependency", Filters.element(), null, ns);