现在我知道如何parse xml in scala as a stream我需要帮助理解一个非平凡的例子。
每当我解析出完整的消息时,我想将以下xml解析为流并发送消息(打印到此示例的控制台)。
我理解scala中基于流的解析使用case类来处理不同的元素,但我刚刚开始,我不太明白如何做到这一点。
我使用stax解析器在java中工作,我正在尝试将其转换为scala。
非常感谢任何帮助。
<?xml version="1.0" ?>
<messages>
<message>
<to>john.doe@gmail.com</to>
<from>jane.doe@gmail.com</from>
<subject>Hi Nice</subject>
<body>Hello this is a truly nice message!</body>
</message>
<message>
<to>joe@gmail.com</to>
<from>jane.doe@gmail.com</from>
<subject>Hi Nice</subject>
<body>Hello this is a truly nice message!</body>
</message>
</messages>
答案 0 :(得分:5)
这是2.8。
处理事件的典型方法是使用匹配语句。在我的情况下,我总是需要在处理元素时存储父元素(例如,知道文本所在的标记):
import scala.xml.pull._
import scala.io.Source
import scala.collection.mutable.Stack
val src = Source.fromString(xml)
val er = new XMLEventReader(src)
val stack = Stack[XMLEvent]()
def iprintln(s:String) = println((" " * stack.size) + s.trim)
while (er.hasNext) {
er.next match {
case x @ EvElemStart(_, label, _, _) =>
stack push x
iprintln("got <" + label + " ...>")
case EvElemEnd(_, label) =>
iprintln("got </" + label + ">")
stack pop;
case EvText(text) =>
iprintln(text)
case EvEntityRef(entity) =>
iprintln(entity)
case _ => // ignore everything else
}
}
因为实体是事件,您可能需要转换为文本并将它们与周围文本组合。
在上面的示例中,我只使用了标签,但您也可以使用EvElemStart(pre, label, attrs, scope)
来提取更多内容,并且可以添加if
后卫以匹配复杂条件。
此外,如果您使用的是2.7.x,我不知道http://lampsvn.epfl.ch/trac/scala/ticket/2583是否被反向移植,您可能会遇到使用实体处理文本的问题。
更重要的是,为了简洁而处理from和to(虽然我不会称之为 Scala方式):
class Message() {
var to:String = _
var from:String = _
override def toString(): String =
"from %s to %s".format(from, to)
}
var message:Message = _
var sb:StringBuilder = _
while (er.hasNext) {
er.next match {
case x @ EvElemStart(_, "message", _, _) =>
message = new Message
case x @ EvElemStart(_, label, _, _) if
List("to", "from") contains label =>
sb = new StringBuilder
case EvElemEnd(_, "to") =>
message.to = sb.toString
case EvElemEnd(_, "from") =>
message.from = sb.toString
sb = new StringBuilder
case EvElemEnd(_, "message") =>
println(message)
case EvText(text) if sb != null =>
sb ++= text
case EvEntityRef(entity) =>
sb ++= unquote(entity) // todo
case _ => // ignore everything else
}
}