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

Document declares separate empty namespace rendering NamespaceAware results useless

我正在尝试对 Maven 使用的 "correct" pom.xml 执行一些检索查询。为此,我使用来自 JDOM 的基本 XPath 查询。

不幸的是,查询没有 return 任何结果(简单的后代过滤器也没有)。我有理由相信问题出在 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/" 都不匹配的空命名空间,其中“”是默认的无命名空间,xmlns 命名空间是默认的 xmlns命名空间。

所以给定一个 Document,当我想执行如下的 XPath 查询时:

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 查询得到 return 结果?

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

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

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

XPath 尤其不遵循与常规 XML 文档相同的规则,因为在处理 "" 名称空间时存在差异。在 XML 文档中,它指的是 "default" 命名空间(无命名空间或通过使用 xmlns="...." 声明覆盖它的任何内容)。

然而,在 XPath 中,规则略有不同(参见 the spec - 强调我的 ):

A QName in the node test is expanded into an expanded-name using the namespace declarations from the expression context. This is the same way expansion is done for element type names in start and end-tags except that the default namespace declared with xmlns is not used: if the QName does not have a prefix, then the namespace URI is null

这实际上意味着,即使您不需要在 XML 中为诸如 dependencies 之类的内容添加名称空间前缀,您仍然需要在 XPath 查询中添加前缀。前缀可以是任何东西——不需要匹配 XML 文档中的任何东西。所以,选择一个任意的命名空间,比如 'ns',你可以有一个查询:

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