为什么XPath从我的整个文档返回节点,而不仅仅是select节点

时间:2017-11-15 23:23:06

标签: java xml xpath

假设:

public class XPathTest {

    public static void main(String args[]) throws Exception {
        String xmlString
                = "<a>"
                + "<b c=\"1\"/>"
                + "<b c=\"2\"/>"
                + "</a>";

        ByteArrayInputStream bis = new ByteArrayInputStream(xmlString.getBytes());
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(bis));

        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile("//b");

        NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
        dumpNodeList(nl);
        for (int i = 0; i < nl.getLength(); i++) {
            Node n = nl.item(i);
            NodeList nl2 = (NodeList) expr.evaluate(n, XPathConstants.NODESET);
            dumpNodeList(nl2);
        }

    }

    public static void dumpNodeList(NodeList nl) {
        System.out.println("NodeList length = " + nl.getLength());
        for (int i = 0; i < nl.getLength(); i++) {
            System.out.println("Node #" + i);
            Element e = (Element) nl.item(i);
            System.out.println("Name = " + e.getTagName());
            System.out.println("Attr = " + e.getAttribute("c"));
        }
        System.out.println();
    }
}

示例结果:

NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2

NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2

NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2

我评估XPath表达式//b,将根文档节点传递给求值程序。它应该返回两个b节点。

我感到困惑的是当我评估相同的表达式时,而不是传入根节点,因为参数我传递给我之前找到的一个子节点。根据{{​​1}},它说在指定的上下文中评估已编译的XPath表达式,并将结果作为指定的类型返回。

表达式XPathExpression.evaluate(Object item)表示“给我所有//b个节点”。

直觉上,我认为如果我将一个Node传递给b,那么表达式将从该节点开始计算,作为“全部给我”部分的根,而不是整个文档。所以我希望得到一个节点的NodeList,而不是两个。

但相反,我从整个文档中获得了相同的两个节点。

所以,这两个问题是:

  1. 为什么表达式是相对于整个文档进行评估的,而不是仅仅使用传递节点作为评估的合成根?

  2. 如何使用传入的节点作为评估的合成根来评估表达式?

2 个答案:

答案 0 :(得分:1)

它的工作原理应该是{而不是//b,请尝试使用./b。也许M $帮助不是很有帮助,但here他们有一些方便的例子。

答案 1 :(得分:0)

/开头的表达式,如//b,首先从上下文节点向上导航到包含树的根。因此,您引用的文档是正确的,它是在当前上下文中进行评估的,但是您在某种程度上错误地认为它只是在查看以上下文节点为根的子树。如果您选择从上下文节点向上导航,则可以,这正是您所做的。

你可能想要.//b