我正在研究Scala和XML之间编组/解组数据的各种方法,我很想获得社区反馈(最好以第一手知识/经验为基础)。
我们目前正在使用JAXB,这很好,但我希望有一个纯粹的Scala解决方案。我正在考虑以下方法:
使用Scala的内置XML工具:Scala-> XML很容易,但我的猜测是另一个方向会相当痛苦。另一方面,这种方法支持任意翻译逻辑。
数据绑定:scalaxb目前似乎有点不成熟,并没有处理我们当前的架构,我不知道任何其他数据绑定库对于斯卡拉。与JAXB一样,需要额外的转换层来支持相关的转换。
XML pickler组合器:GData Scala Client库提供XML pickler组合器,但最近的项目活动一直很少,我不知道当前状态是什么。
问题:
修改
我在自己对这个问题的回答中添加了关于我对pickler组合器的早期印象的一些注释,但我仍然对那些真正了解各种方法的人的反馈非常感兴趣。我希望的是一个有点全面的比较,可以帮助开发人员根据自己的需求选择正确的方法。
答案 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
。