XPath ::运行计数器两个级别

时间:2013-07-02 21:26:59

标签: xpath saxon xpath-2.0 jaxp

使用count(preceding-sibling::*) XPath 表达式可以获得递增计数器。但是,同样也可以在两级深度序列中完成吗?

示例XML实例

<grandfather>
    <father>
        <child>a</child>
    </father>
    <father>
        <child>b</child>
        <child>c</child>
    </father>
</grandfather>

代码(用于XPath 2.0功能的CLASSPATH上的Saxon HE 9.4 jar)

尝试为具有不同类型的XPath表达式的三个子节点获取1,2和3的计数器序列:

    XPathExpression expr = xpath.compile("/grandfather/father/child");
    NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
    for (int i = 0 ; i < nodes.getLength() ; i++) {
        Node node = nodes.item(i);
        System.out.printf("child's index is: %s %s %s, name is: %s\n"
                          ,xpath.compile("count(preceding-sibling::*)").evaluate(node)
                          ,xpath.compile("count(preceding-sibling::child)").evaluate(node)
                          ,xpath.compile("//child/position()").evaluate(doc)
                          ,xpath.compile(".").evaluate(node));
    }

以上代码打印:

child's index is: 0 0 1, name is: a
child's index is: 0 0 1, name is: b
child's index is: 1 1 1, name is: c

我试过的三个 XPaths 中没有一个设法产生正确的序列:1,2,3。很明显,使用i循环变量可以轻松完成,但如果可能,我想用 XPath 完成它。此外,我需要保持评估 XPath 表达式的基本框架,以获取所有要访问的节点,然后在该集合上进行迭代,因为这是我正在处理的实际应用程序的结构。基本上我访问每个节点,然后需要在其上评估一些 XPath 表达式(node)或文档(doc);其中一个 XPAth 表达式应该产生这个递增序列。

2 个答案:

答案 0 :(得分:1)

使用前面的轴代替名称测试。

count(preceding::child)

使用XPath 2.0,有一种更好的方法可以做到这一点。获取所有<child/>个节点并使用position()函数获取索引:

//child/concat("child's index is: ", position(), ", name is: ", text())

答案 1 :(得分:1)

你没有说效率很重要,但我真的很讨厌用O(n ^ 2)代码完成这个! Jens的解决方案展示了如何以一系列(位置,名称)对的形式使用结果的方法。您还可以使用// child /(string(。),position())返回交替的字符串和数字序列:虽然您希望使用s9api API而不是JAXP,因为JAXP只能真正处理数据类型在XPath 1.0中出现。

如果您需要计算每个节点的索引作为其他处理的一部分,那么在单个初始传递中为每个节点计算索引可能仍然值得,然后在表中查找它。但是如果你这样做,最简单的方法肯定是迭代//child的结果,并在迭代中从节点到序列号构建一个映射。