如何使用流解析将xml解析为"消息"并在scala中打印出来?

ScA*_*er2 3 xml scala

既然我知道如何在scala中解析xml作为流我需要帮助理解一个非平凡的例子.

我想解析下面的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>
Run Code Online (Sandbox Code Playgroud)

huy*_*hjl 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
  }
}
Run Code Online (Sandbox Code Playgroud)

因为实体是事件,所以您可能需要转换为文本并将它们与周围文本组合.

在上面的示例中,我只使用了标签,但您也可以使用它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
  }
}
Run Code Online (Sandbox Code Playgroud)