XPath子节点的Java计数

时间:2014-05-01 14:32:05

标签: java xml xpath

我想计算给定xml的一些子节点。但它总是让我回归0,我无法弄清楚原因。

这里是xml:

<FirstOne xmlns:xxx="http://www.w3.org/2001/XMLSchema-instance">
  <Formulas xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <xxx:yyy>
      <aa:bb>something</aa:bb>
      <cc:dd>something</cc:dd>
    </xxx:yyy>
    <xxx:yyy>
      <aa:bb>something</aa:bb>
      <cc:dd>something</cc:dd>
    </xxx:yyy>
    <xxx:yyy>
      <aa:bb>something</aa:bb>
      <cc:dd>something</cc:dd>
    </xxx:yyy>
  </Formulas>

</FirstOne>

我想计算&#34; xxx:yyy&#34;的数量。在这个例子中3。 我尝试了以下方法:

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setValidating(false);
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(new FileInputStream(new File(fileArray[i].toString())));
    XPathFactory factory = XPathFactory.newInstance();
    XPath xpath = factory.newXPath();
    String expression;
    expression = "count(//Formulas/xxx:yyy)";
    Double result = (Double) xpath.evaluate(expression, doc, XPathConstants.NUMBER);

总是给我0.0 ......

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

问题都来自命名空间。

首先,XPath评估仅在名称空间良好的XML上定义,因此您需要确保aacc前缀正确映射到XML中的名称空间URI。

其次,您需要使用名称空间感知解析器将XML解析为DOM树(我只能假设这是历史原因,DocumentBuilderFactory不受名称空间感知默认值)。

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new FileInputStream(new File(fileArray[i].toString())));

现在,您需要在XPath中正确处理命名空间的正确的命名空间格式良好的DOM树。您需要定义NamespaceContext告诉XPath如何关联前缀和名称空间URI。令人讨厌的是,核心Java库中没有此接口的默认实现,但是存在第三方实现,例如Spring's SimpleNamespaceContext,或者只有三种方法可以自己实现它。使用SimpleNamespaceContext

XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
SimpleNamespaceContext nsCtx = new SimpleNamespaceContext();
xpath.setNamespaceContext(nsCtx);

nsCtx.bindNamespaceUri("x", "http://www.w3.org/2001/XMLSchema-instance");

有了这个上下文,您现在可以在XPath表达式中选择命名空间节点:

String expression = "count(//Formulas/x:yyy)";

(您使用的前缀是NamespaceContext中的前缀,不一定是原始XML源中的前缀。)


虽然某些 DOM解析器和XPath实现可能会让您解析非命名空间感知并省略XPath表达式中的前缀,但这是一个实现细节,并且行为不是由规格。它可能在一个版本中工作但在另一个版本中失败,或者如果您向项目中添加其他JAR以更改默认解析器等,则表现不同。

答案 1 :(得分:0)

虽然xxx是标记前缀,但只使用count(//Formulas/yyy)