6

我需要使用 XPath 函数 normalized-space() 来规范化我想从 XHTML 文档中提取的文本:http: //test.anahnarciso.com/clean_bigbook_0.html

我正在使用以下表达式:

//*[@slot="address"]/normalize-space(.)

它在我用来测试 XPath 表达式的工具 Qizx Studio 中完美运行。

    let $doc := doc('http://test.anahnarciso.com/clean_bigbook_0.html')
    return $doc//*[@slot="address"]/normalize-space(.)

这个简单的查询返回一个xs:string.

144 Hempstead Tpke
403 West St
880 Old Country Rd
8412 164th St
8412 164th St
1 Irving Pl
1622 McDonald Ave
255 Conklin Ave
22011 Hempstead Ave
7909 Queens Blvd
11820 Queens Blvd
1027 Atlantic Ave
1068 Utica Ave
1002 Clintonville St
1002 Clintonville St
1156 Hempstead Tpke
Route 49
10007 Rockaway Blvd
12694 Willets Point Blvd
343 James St

现在,我想在我的 Java 代码中使用前面的表达式。

String exp = "//*[@slot=\"address"\"]/normalize-space(.)";
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile(exp);
Object result = expr.evaluate(doc, XPathConstants.NODESET);

但最后一行抛出异常:

Cannot convert XPath value to Java object: required class is org.w3c.dom.NodeList; supplied value has type xs:string

显然,我应该改变XPathConstants.NODESET一些东西;我试过XPathConstants.STRING了,但它只返回序列的第一个元素。

如何获得类似字符串数组的东西?

提前致谢。

4

4 回答 4

5

您的表达式在 XPath 2.0 中有效,但在 XPath 1.0(在 Java 中使用)中是非法的 - 它应该是normalize-space(//*[@slot='address']).

无论如何,在 XPath 1.0 中,当normalize-space()在节点集上调用时,只会采用第一个节点(按文档顺序)。

为了做你想做的事,你需要使用兼容 XPath 2.0 的解析器,或者遍历生成的节点集并normalize-space()在每个节点上调用:

XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr;

String select = "//*[@slot='address']";
expr = xpath.compile(select);
NodeList result = (NodeList)expr.evaluate(input, XPathConstants.NODESET);

String normalize = "normalize-space(.)";
expr = xpath.compile(normalize);

int length = result.getLength();
for (int i = 0; i < length; i++) {
    System.out.println(expr.evaluate(result.item(i), XPathConstants.STRING));
}

...输出您给定的输出。

于 2012-07-07T21:01:20.097 回答
3

这取决于您使用的 XPath 版本。看看这篇文章,希望它能回答你的问题:是否可以将 normalize-space 应用于 XPath 表达式找到的所有节点?祝你好运。

于 2012-07-07T20:51:25.680 回答
3

正如您所注意到的,XPath 2.0 表达式//*[@slot="address"]/normalize-space(.)返回一个字符串序列。JAXP 类不支持这种返回类型XPathConstants,因为 JAXP 接口不是为支持 XPath 2.0 而设计的。

这让您有两个选择:

  1. 使用具有 XPath 2.0 的本机接口或可以将序列转换为 JAXP 支持的返回类型的 XPath 2.0 处理器
  2. 仅使用 XPath 1.0 表达式。例如,在您的情况下,您可以简单地选择目标节点:

    //*[@slot="address"]
    

    然后迭代生成的节点集,将结果收集到一个数组或List.

请注意,区分用于评估表达式的处理器和用于启动评估的接口非常重要。

于 2012-07-07T21:00:47.560 回答
3

表达式

//*[@slot="address"]/normalize-space(.)

在语法上是合法的(并且实际上很有用)XPath 2.0 表达式。

在 XPath 1.0 中,相同的表达式在语法上是不合法的——定位步骤不允许作为函数调用。

事实上,不可能编写一个XPath 1.0 表达式,其求值结果是所需的字符串集。

您需要在程序中使用实现 XPath 2.0 的产品——例如 Saxon 9.x。

于 2012-07-07T21:01:07.197 回答