【问题标题】:XPath normalize-space() to return a sequence of normalized stringsXPath normalize-space() 返回标准化字符串序列
【发布时间】:2012-07-07 20:48:25
【问题描述】:

我需要使用 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,但它只返回序列的第一个元素。

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

提前致谢。

【问题讨论】:

    标签: java xml xpath


    【解决方案1】:

    这取决于您使用的 XPath 版本。看看这篇文章,希望它能回答你的问题:Is it possible to apply normalize-space to all nodes XPath expression finds?祝你好运。

    【讨论】:

    • 就是这样,谢谢。我搜索了类似的问题,但没有找到。看来我毕竟要使用撒克逊人了……
    【解决方案2】:

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

    这让您有两个选择:

    1. 使用具有native interfaces for XPath 2.0 或可以convert sequences to a return type supported by JAXP 的XPath 2.0 处理器
    2. 仅使用 XPath 1.0 表达式。例如,在您的情况下,您可以简单地选择目标节点:

      //*[@slot="address"]
      

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

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

    【讨论】:

      【解决方案3】:

      表达式

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

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

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

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

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

      【讨论】:

      • 感谢您提供的信息,我不知道 XPath 1.0 是如此有限。我已经尝试过 Saxon,但我发现它比 JAXP 复杂一些。
      • @anahnarciso:如果您的意思是 XPath 2.0 比 JAXP 为其提供接口的 XPath (1.0) 版本更复杂,这可能是正确的。另一方面,如果您的意思是撒克逊语更难援引,我不太确定。我每天都使用 Saxon 执行许多转换——从命令行调用 Saxon 很简单。
      • 我的意思是,因为我已经习惯了 JAXP 并且我试图避免使用另一个外部库。我找到的最好的 Saxon Java 代码示例是官方网站上提供的。你知道关于撒克逊的任何其他有用的资源/教程吗?
      【解决方案4】:

      您的表达式在 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));
      }
      

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

      【讨论】:

      • 谢谢,您的回复很有帮助。
      猜你喜欢
      • 2019-04-13
      • 2019-08-26
      • 2023-04-01
      • 2010-12-22
      • 1970-01-01
      • 1970-01-01
      • 2019-09-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多