文档声明单独的空命名空间渲染命名空间感知结果无用



我正在尝试对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/"不匹配的空命名空间,其中"是默认的无命名空间,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 查询返回结果?

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

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 文档中,它引用"默认"命名空间(无命名空间或任何通过使用xmlns="...."声明来覆盖它的内容(。

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

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

这实际上意味着,即使您不需要 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);

最新更新