在scala中的简单Xpath查询

时间:2013-04-01 12:11:14

标签: xml scala xpath

我尝试使用scala运行XPath查询,但它似乎无法正常工作。 我的Xml看起来像(简化):

<application>
  <process type="output" size ="23"> 
     <channel offset="0"/>
      ....
     <channel offset="4"/>
  </process>
  <process type="input" size ="16"> 
     <channel offset="20"/>
      ....
     <channel offset="24"/>
  </process>
</application>

我想要使用process属性检索input,为此我使用此XPath查询:

//process[@type='input']

这应该有用,我用xpathtester验证了 现在,我的scala代码如下所示:

import scala.xml._
val x = XML.loadFile("file.xml")

val process = (x \\ "process[@type='input']")  // will return empty NodeSeq() !!!

process结束为空,它无法捕获我想要的内容。我像这样工作:

val process = (x \\ "process" filter( _ \"@type" contains Text("input")))

这更加丑陋。我的原始查询不应该起作用的任何已知原因?

3 个答案:

答案 0 :(得分:4)

“XPath”不应用于描述Scala标准库支持的内容。 XPath是一种成熟的表达式语言,迄今为止已有两个最终版本和第三个版本:

充其量你可以说Scala只有一小部分受XPath启发的操作。所以你不能指望采用XPath表达式并直接将它们粘贴到Scala而不需要做更多的工作。

第三方库可以为您提供更好的实际XPath表达式支持,包括:

  • Scales Xml
    • Scala库
    • “提供了比普通Scala XML更多的XPath体验,Paths看起来像XPath并且也像它们一样工作(具有许多相同的功能和轴)”
    • 如果我理解的话,它仍然不是真正的XPath
    • 旨在与Scala良好整合
  • Saxon
    • Java库
    • 开源
    • 对XPath 2(和XSLT 2)的完整且一致的支持
    • 有一个XPath API,可以在DOM和其他数据模型上运行,但目前没有特定的Scala支持

答案 1 :(得分:1)

这样做的一种方法是使用kantan.xpath

import kantan.xpath._
import kantan.xpath.implicits._

val input = """
     | <application>
     |   <process type="output" size ="23">
     |      <channel offset="0"/>
     |      <channel offset="4"/>
     |   </process>
     |   <process type="input" size ="16">
     |      <channel offset="20"/>
     |      <channel offset="24"/>
     |   </process>
     | </application>
     | """.stripMargin

val inputs = input.evalXPath[List[Node]](xp"//process[@type='input']")

这会产生List[Node],但您可以检索更有趣类型的值 - 通道偏移列表,例如:

input.evalXPath[List[Int]](xp"//process[@type='input']/channel/@offset")
// This yields Success(List(20, 24))

答案 2 :(得分:0)

我相信scala xml实现无法处理这种复杂的XPath查询。然而,创建一个小的丰富包装器来减少混乱并不困难,例如看看this thread。使用建议的包装器,您可以像这样解决问题:

x \\ "process" \@ ("type", _ == "input")