我想计算给定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 ......
感谢您的帮助!
答案 0 :(得分:2)
问题都来自命名空间。
首先,XPath评估仅在名称空间良好的XML上定义,因此您需要确保aa
和cc
前缀正确映射到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)
。