Как мне разобрать xml в «сообщения» и распечатать их в scala, используя потоковый анализ? - PullRequest
3 голосов
/ 28 мая 2010

Теперь, когда я знаю, как разобрать xml в scala как поток, Мне нужна помощь в понимании нетривиального примера.

Я бы хотел проанализировать следующий xml как поток и отправить сообщение (в этом примере распечатать на консоль) всякий раз, когда я анализировал полное сообщение.

Я понимаю, что потоковый анализ в scala использует case-классы для обработки различных элементов, но я только начинаю и не совсем понимаю, как это сделать.

У меня это работает в Java с использованием синтаксического анализатора Stax, и я пытаюсь перевести это в 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>

1 Ответ

5 голосов
/ 28 мая 2010

Это для 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 перенесен обратно, поэтому у вас могут возникнуть проблемы при обработке текста с сущностями.

Более конкретно, просто для краткости и краткости (хотя я бы не назвал это Scala way ):

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
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...