15

我正在研究在 Scala 和 XML 之间编组/解组数据的各种方法,并且我有兴趣获得社区反馈(最好以第一手知识/经验为基础)。

我们目前正在使用 JAXB,这很好,但我希望有一个纯 Scala 解决方案。我正在考虑以下方法:

  1. 使用 Scala 的内置 XML 工具:Scala->XML 会很容易,但我猜另一个方向会相当痛苦。另一方面,这种方法支持任意翻译逻辑。

  2. 数据绑定scalaxb 目前似乎有些不成熟,不能处理我们当前的模式,而且我不知道任何其他的 Scala 数据绑定库。与 JAXB 一样,需要一个额外的转换层来支持所涉及的转换。

  3. XML pickler 组合器GData Scala 客户端库提供 XML pickler 组合器,但最近的项目活动很少,我不知道当前状态如何。

问题:

  1. 您对我列出的方法/库有什么经验?
  2. 各自的相对优势和劣势是什么?
  3. 我应该考虑其他方法或 Scala 库吗?

编辑:

在我自己对这个问题的回答中,我添加了一些关于我对pickler 组合器的早期印象的注释,但我仍然对真正深入了解各种方法的人的反馈非常感兴趣。我希望的是一个比较全面的比较,可以帮助开发人员根据他们的需要选择正确的方法。

4

3 回答 3

5

我推荐使用 Scala 的内置 XML 特性。我刚刚为一个看起来像这样的文档结构实现了反序列化:

val bodyXML = <body><segment uri="foo"><segment uri="bar" /></segment></body>

请注意,这些段可以相互嵌套。

一个段实现如下:

case class Segment(uri: String, children: Seq[Segment])

要反序列化 XML,请执行以下操作:

val mySegments = topLevelSegments(bodyXML)

...而实现topLevelSegments只是几行代码。注意递归,它挖掘了 XML 结构:

def topLevelSegments(bodyXML: Node): Seq[Segment] = 
    (bodyXML \ "segment") map { nodeToSegment }

def nodeToSegment = (n: Node) => Segment((n \ "@uri")(0) text, childrenOf(n))

def childrenOf(n: Node): Seq[Segment] = (n \ "segment") map { nodeToSegment }

希望有帮助。

于 2011-01-12T01:21:24.497 回答
4

作为比较,我使用GData Scala 客户端库中的 pickler 组合器实现了David 的示例:

def segment: Pickler[Segment] =
   wrap(elem("segment", 
           attr("uri", text) 
           ~ rep(segment))) {    // rep = zero or more repetitions
      // convert (uri ~ children) to Segment(uri, children), for unpickling
      Segment.apply 
   } {
      // convert Segment to (uri ~ children), for pickling
      (s: Segment) => new ~(s.uri, s.children toList)
   }

def body = elem("body", rep(segment))

case class Segment(uri: String, children: List[Segment])

这段代码是指定Segments 和 XML 之间的两个转换方向所必需的,而在使用 Scala XML 库时,类似数量的代码只指定一个转换方向。在我看来,这个版本也更容易理解(一旦你了解了 pickler DSL)。当然,正如 David 在评论中指出的那样,这种方法需要一个额外的依赖项和另一个开发人员必须熟悉的 DSL。

将 XML 转换为 Segments 就像

body.unpickle(LinearStore.fromFile(filename)) // returns a PicklerResult[List[Segment]]

并以另一种方式翻译看起来像

xml.XML.save(filename, body.pickle(segments, PlainOutputStore.empty).rootNode)

就组合器库而言,它的状态似乎不错,并且可以在 Scala 2.8.1 中编译。我最初的印象是该库缺少一些oneOrMore可以相当容易地修复的细节(例如组合器)。我还没有时间看看它处理不良输入的能力如何,但到目前为止它看起来足以满足我的需求。

于 2011-01-12T23:30:57.223 回答
-1

将 scala.xml.Node 写入字符串并不是什么大问题。PrettyPrinter应该照顾你的需要。scala.xml.XML.save()将写入文件并scala.xml.XML.write()输出到Writer.

于 2011-01-12T03:34:11.827 回答