【问题标题】:Performing complicated XPath queries in Scala在 Scala 中执行复杂的 XPath 查询
【发布时间】:2010-06-16 19:01:56
【问题描述】:

在 scala 中用于对文档执行以下 XPath 查询的最简单 API 是什么?

//s:Annotation[@type='attitude']/s:Content/s:Parameter[@role='type' and not(text())]

//s:Annotation[s:Content/s:Parameter[@role='id' and not(text())]]/@type

s 被定义为特定命名空间的昵称)

我能找到的关于 Scala 的 XML 库的唯一文档没有关于执行复杂的真实 XPath 查询的信息。

我曾经喜欢 JDOM 用于此目的(在 Java 中),但由于 JDOM 不支持泛型,因此在 Scala 中使用会很痛苦。 (其他用于 Java 的 XML 库在 Java 中往往更加痛苦,但我承认我不太了解情况。)

【问题讨论】:

  • s:... 是什么意思?我假设它与命名空间有关,但我在 XPath 规范中找不到。
  • 是的,它是一个命名空间前缀。请参阅介绍的倒数第二段,其中说“在以下语法中,非终结符 QName 和 NCName 在 [XML Names] 中定义,S 在 [XML] 中定义。”表达式 s:Annotation 是一个 QName。

标签: java xml scala xpath jdom


【解决方案1】:
//s:Annotation[@type='attitude']/s:Content/s:Parameter[@role='type' and not(text())]

好吧,我不理解s: 表示法,也无法在XPath 规范中找到它。然而,忽略这看起来像这样:

(
  (xml 
    \\ "Annotation" 
    filter (_ \ "@type" contains Text("x"))
  ) 
  \ "Content" 
  \ "Parameter" 
  filter (el => (el \ "@type" contains Text("type")) && el.isInstanceOf[Text])
)

注意括号的必要性,因为\ 的优先级高于filter。我已将格式更改为多行表达式,因为 Scala 等效项对于单行来说太冗长了。

不过,我无法回答有关命名空间的问题。不知道如何在搜索中与他们合作,如果可能的话。文档提到 @{uri}attribute 的前缀属性,没有提到任何关于前缀元素的内容。另外,请注意,您需要传递一个解析为您想要的命名空间的 uri,因为不支持搜索中的文字命名空间。

【讨论】:

  • 好吧,这很丑,但至少可行。
  • @Ken Java 的所有库都可用...我确实认为没有更好的 XPath 支持是一种耻辱。
  • 而不是:(xml \\“注释”过滤器(_ \“@type”包含文本(“x”)))我会使用:(xml \\“注释”过滤器(x = > (x \ "@type").text == "x"))
  • @David 您可以有多个属性值,因此您的替代方案并不严格等效。你的或我的都是正确的——这取决于属性的语义到底是什么。
  • s:-notation 的意思是:命名空间中的元素绑定到 s 前缀...这肯定在 XPath 规范中;)
【解决方案2】:

我想我会轻轻拉皮条XOM。 XOM 作者决定不公开子节点等的集合有点可惜,但他们在 Java 中比在 Scala 中这样做有更多的工作和更少的优势。 (而且它是一个设计良好的库。)

编辑: 毕竟我最终还是拉起了 JDOM,因为 XOM 不会提前编译 XPath 查询。由于这次我的大部分精力都集中在 XPath 上,因此我能够提出一个很好的模型来回避大多数泛型问题。在org.jdom.Element 中想出方法getChildrengetAttributesgetAdditionalNamespaces 的合理泛化版本应该不难(通过使用名称略有改变的新方法来拉皮条。)我不'我不认为getContent 有修复,我不确定getDescendants

【讨论】:

【解决方案3】:

Scales Xml 添加了基于字符串的完整 XPath 评估和内部 DSL,为查询提供了相当完整的覆盖范围

【讨论】:

【解决方案4】:

我想当scalaxmljaxen 成熟时,我们将能够在 scala 的内置 XML 类上可靠地做到这一点。

【讨论】:

    【解决方案5】:

    我建议使用kantan.xpath:

     import kantan.xpath._
     import kantan.xpath.implicits._
    
     input.evalXPath[List[String]](xp"/annotation[@type='attitude']/content/parameter[@role='type' and not(text())]/@value")
    

    这会产生:

    res1: kantan.xpath.XPathResult[List[String]] = Success(List(foobar))
    

    【讨论】:

      猜你喜欢
      • 2016-06-07
      • 2016-11-21
      • 2012-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-21
      • 2021-09-11
      相关资源
      最近更新 更多