2010-05-28 5 views
3

Maintenant que je sais comment parse xml in scala as a stream j'ai besoin d'aide pour comprendre un exemple non trivial. Je souhaite analyser le fichier XML suivant en tant que flux et envoyer un message (imprimer vers la console pour cet exemple) chaque fois que j'ai analysé un message complet. Je comprends que l'analyse basée sur les flux dans scala utilise des classes de cas pour gérer les différents éléments, mais je commence tout juste et je ne comprends pas très bien comment faire cela. J'ai ce travail en Java en utilisant un analyseur stax, et j'essaye de traduire cela en scala.Comment analyser xml dans "messages" et les imprimer dans scala en utilisant l'analyse de flux?

Toute aide serait grandement appréciée.

<?xml version="1.0" ?> 
<messages> 
<message> 
    <to>[email protected]</to> 
    <from>[email protected]</from> 
    <subject>Hi Nice</subject> 
    <body>Hello this is a truly nice message!</body> 
</message> 
<message> 
    <to>[email protected]</to> 
    <from>[email protected]</from> 
    <subject>Hi Nice</subject> 
    <body>Hello this is a truly nice message!</body> 
</message> 
</messages> 

Répondre

4

Ceci est pour 2.8.

La façon classique de traiter des événements consiste à utiliser une instruction de correspondance. Dans mon cas, j'ai toujours eu le besoin de stocker les parents je traiter les éléments (à savoir, par exemple, dans quelle étiquette se trouve le texte):

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

Parce que l'entité sont des événements, vous aurez probablement besoin de se convertir à texte et combinez-les avec le texte environnant. Dans l'exemple ci-dessus, j'ai seulement utilisé l'étiquette, mais vous pouvez aussi utiliser EvElemStart(pre, label, attrs, scope) pour extraire plus de choses et vous pouvez ajouter un gardien if pour faire correspondre les conditions complexes.

Aussi si vous utilisez 2.7.x, je ne sais pas si http://lampsvn.epfl.ch/trac/scala/ticket/2583 a été back-porté, donc vous pouvez avoir des problèmes pour traiter le texte avec des entités.

Plus au point, juste traiter de et par souci de concision (bien que je ne dirais pas que la façon Scala ): ce

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 
    } 
} 
+0

Ceci est utile, mais pas encore tout à fait, je suis à la recherche de. Je pourrais être en mesure d'obtenir quelque chose de travail en utilisant cela. – ScArcher2

+0

J'essaie de découvrir la "scala" façon de construire un objet "message", ou peut-être même juste un tuple, puis imprimez-le en même temps au lieu de simplement imprimer lorsque je rencontre chaque balise et élément de texte. – ScArcher2

+0

Merci pour l'exemple! C'est exactement l'information que je cherchais. Je suis toujours intéressé par la "scala" façon de le faire s'il y a un moyen plus fonctionnel. Merci encore! – ScArcher2

Questions connexes