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

标签 xml scala

现在我知道如何parse xml in scala as a stream我需要帮助来理解一个重要的例子。

我想将以下 xml 解析为流,并在解析出完整消息时发送一条消息(在本例中打印到控制台)。

我知道 scala 中基于流的解析使用案例类来处理不同的元素,但我才刚刚开始,我不太明白如何做到这一点。

我使用 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>

最佳答案

这是 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
  }
}

关于xml - 如何将 xml 解析为 "messages"并使用流解析在 scala 中打印出来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2929590/

相关文章:

xml - RSS 中的缩略图有一些标准的 xml 标签吗?

Javascript 显示根 XML 文件中有多少个元素

Scala 集合 : transform content and type of the collection in one pass

java - Apache Camel 文件组件 - 如何只扫描新文件?

java - Hibernate 正在提交但不保存

r - 从 R 列表生成 xml

wpf - 我应该使用 XML 文件还是数据库?

scala - 如何确定scala模块是否作为脚本运行

java - 类型不匹配,找到单位,需要整数。使用模式匹配、Scala 和 Java 库

java - 无响应的actor系统: ThreadPoolExecutor dispatcher only creates core thread pool,显然会忽略最大线程池大小