【发布时间】:2016-10-15 03:10:02
【问题描述】:
给定以下 XML 实例:
<entities>
<person><name>Jack</name></person>
<person><name></name></person>
<person></person>
</entities>
我正在使用以下代码:(a) 遍历人员并 (b) 获取每个人的姓名:
XPathExpression expr = xpath.compile("/entities/person");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++) {
Node node = nodes.item(i);
String innerXPath = "name/text()";
String name = xpath.compile(innerXPath).evaluate(node);
System.out.printf("%2d -> name is %s.\n", i, name);
}
上面的代码无法区分第 2 人称(姓名为空字符串)和第 3 人称(根本没有姓名元素),只是打印:
0 -> name is Jack.
1 -> name is .
2 -> name is .
有没有办法使用不同的innerXPath 表达式来区分这两种情况?在this SO question 中,XPath 的方式似乎是返回一个空列表,但我也尝试过:
String innerXPath = "if (name) then name/text() else ()";
...输出还是一样的。
那么,有没有办法用不同的innerXPath 表达式来区分这两种情况?我的类路径中有 Saxon HE,因此我也可以使用 XPath 2.0 功能。
更新
因此,根据接受的答案,我能做的最好的事情如下:
XPathExpression expr = xpath.compile("/entities/person");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0 ; i < nodes.getLength() ; i++) {
Node node = nodes.item(i);
String innerXPath = "name";
NodeList names = (NodeList) xpath.compile(innerXPath).evaluate(node, XPathConstants.NODESET);
String nameValue = null;
if (names.getLength()>1) throw new RuntimeException("impossible");
if (names.getLength()==1)
nameValue = names.item(0).getFirstChild()==null?"":names.item(0).getFirstChild().getNodeValue();
System.out.printf("%2d -> name is [%s]\n", i, nameValue);
}
以上代码打印:
0 -> name is [Jack]
1 -> name is []
2 -> name is [null]
在我看来,这不是很令人满意,因为逻辑分布在 XPath 和 Java 代码中并且限制了 XPath 作为宿主语言和与 API 无关的符号。我的特定用例是将 XPath 集合保存在属性文件中并在运行时评估它们,以便获得我需要的信息,而无需任何特别的额外处理。显然这是不可能的。
【问题讨论】:
-
那么你到底想完成什么?你想要的结果是什么?
-
例如,如果元素名称不存在则返回 null,如果元素存在且内容为空字符串,则返回空字符串 ("")。我需要一个 XPath 表达式,如果元素
<name>根本不存在与它以空值存在,它将以不同的方式计算。 -
我没有过多地使用 Java 的 XML API,但听起来
evaluate()函数将始终返回一个非空字符串,方法是将结果转换为字符串值。像这样的东西怎么样:String innerXPath = "if (name) then name/text() else '[UNSPECIFIED]'"; -
@JLRishe 这是一个选项,但我想尽可能避免使用特殊字符串。