在Scala中编组/解组XML

时间:2011-01-12 00:36:40

标签: xml scala marshalling unmarshalling

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

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

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

  2. 数据绑定scalaxb目前似乎有点不成熟,并没有处理我们当前的架构,我不知道任何其他数据绑定库对于斯卡拉。与JAXB一样,需要额外的转换层来支持相关的转换。

  3. XML pickler组合器GData Scala Client库提供XML pickler组合器,但最近的项目活动一直很少,我不知道当前状态是什么。

  4. 问题:

    1. 您对我列出的方法/图书馆有什么经验?
    2. 每个人的相对优势和劣势是什么?
    3. 我应该考虑使用其他方法或Scala库吗?
    4. 修改

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

3 个答案:

答案 0 :(得分: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 }

希望有所帮助。

答案 1 :(得分:4)

为了进行比较,我使用David's example库中的pickler组合器实现了GData Scala Client

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])

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

将XML翻译为细分就像

一样简单
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组合者),可以相当容易地补救。我没有时间去看它处理错误输入的程度,但到目前为止它看起来足以满足我的需求。

答案 2 :(得分:-1)

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