jdom2 xPathExpression 拉取节点失败

jdom2 xPathExpression pull node fail

我尝试解析 xml 看起来像

<EvaluateHandRequest xmlns="http://www.aaa.com/aaa/schemas">
    <card>
        <suit>HEARTS</suit>
        <face>TEN</face>
    </card>
    <card>
        <suit>SPADES</suit>
        <face>KING</face>
    </card>
    <card>
        <suit>HEARTS</suit>
        <face>KING</face>
    </card>
    <card>
        <suit>DIAMONDS</suit>
        <face>TEN</face>
    </card>
    <card>
        <suit>CLUBS</suit>
        <face>TEN</face>
    </card>
</EvaluateHandRequest>

为此我使用了 XPathExpression,但我无法提取结果。

SAXBuilder jdomBuilder = new SAXBuilder();
Document jdomDocument = jdomBuilder.build(xmlSource);
Element element = jdomDocument.getRootElement(); 
XPathFactory xFactory = XPathFactory.instance();
XPathExpression xExpression = xFactory.compile("/*/*");
List<Element> list  = xExpression.evaluate(element);
System.out.println(list.size() + " "  + list.get(0).getName());//5 card
for (Element element2 : list) {
   System.out.println(element2.getValue());  //proper result
}

如果我在编译期间使用 /*/* 表达式,我会得到所有卡片及其值,其中 card 位于层次结构的顶部。 但是当我使用 /*/card 时,我没有从那里得到任何元素。 如果我在表达式中写下任何节点的任何名称,我将无法获得任何结果。 我有什么问题?

XPath 表达式始终是命名空间感知的。这就是它们的指定方式(section 2.3 - 强调我的):

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 (this is the same way attribute names are expanded). It is an error if the QName has a prefix for which there is no namespace declaration in the expression context.

因此,您需要指定要使用的名称空间...。不过,在我们解决该问题之前,让我们看看您对显示有效的 XPath 的用法:

XPathExpression xExpression = xFactory.compile("/*/*");
List<Element> list  = xExpression.evaluate(element);

那不应该编译....XPathExpression 是泛型类型 class。你想要它 return 元素...为了正确地做到这一点,你需要在编译方法中为结果添加一个过滤器。考虑您当前的行:

XPathExpression xExpression = xFactory.compile("/*/*");

这应该是:

XPathExpression<Element> xExpression = xFactory.compile("/*/*", Filters.element());

这将使所有的编译都没有任何错误或警告...

现在,要扩展 XPath 表达式以仅提取 card 元素,我们需要包含命名空间:

Namespace aaa = Namespace.getNamespace("aaa", "http://www.aaa.com/aaa/schemas");

例如,只获取花色元素:

    Namespace aaa = Namespace.getNamespace("aaa", "http://www.aaa.com/aaa/schemas");
    XPathExpression<Element> xExpression = xFactory.compile(
            "/*/aaa:card/aaa:suit", Filters.element(), null, aaa);

如果需要多个命名空间,您可以添加它们。

请注意,命名空间声明使用前缀 aaa,即使您的 XML 文档中没有使用前缀,您仍然需要一个前缀来引用 XPath 中的命名空间。仅仅因为您的文档中没有前缀并不意味着没有命名空间.....

阅读 Javadoc for compile(...)