2010-10-25 7 views
4

. Je peux très bien analyser le fichier xml, mais j'ai besoin de remplacer les nœuds du xml existant et de réécrire le résultat. par exemple:en remplaçant les valeurs xml par scala

<dependency> 
    <groupId>foo</groupId> 
    <artifactId>bar</artifactId> 
    <version>1.0-SNAPSHOT</version> 
</dependency> 

Je veux trouver tous les nœuds comme celui-ci et les remplacer par:

<dependency> 
    <groupId>foo</groupId> 
    <artifactId>bar</artifactId> 
    <version>1.0</version> <!-- notice the lack of -SNAPSHOT here --> 
</dependency> 

Alors, je peux obtenir tous les noeuds de version assez simplement, mais la façon de les remplacer par la nœud que je veux?

// document is already defined as the head of the xml file 
nodes = for (node <- document \\ "version"; if (node.text.contains("SNAPSHOT"))) yeild node 

alors je veux faire quelque chose comme:

for (node <- nodes) { 
    node.text = node.text.split("-")(0) 
} 

qui ne fonctionne pas parce que le noeud est immuable. J'ai regardé la méthode de copie pour un nœud, mais il n'inclut pas text en tant que paramètre.

Des pointeurs vers examples/doc seraient appréciés.

Merci, Jeff

+0

http://stackoverflow.com/questions/970675/scala-modifying- imbriqués-éléments-en-xml/1306415 # 1306415 – retronym

+0

Quelques bonnes réponses ici. Voir aussi http://stackoverflow.com/a/23092226/35274 – Philippe

Répondre

12

Vous devriez vraiment jeter un oeil à d'autres questions sur Stack Overflow à propos de la modification de XML. Regardez les liens "connexes" à droite.

ici:

scala> <dependency> 
    |  <groupId>foo</groupId> 
    |  <artifactId>bar</artifactId> 
    |  <version>1.0-SNAPSHOT</version> 
    | </dependency> 
res0: scala.xml.Elem = 
<dependency> 
    <groupId>foo</groupId> 
    <artifactId>bar</artifactId> 
    <version>1.0-SNAPSHOT</version> 
</dependency> 

scala> new scala.xml.transform.RewriteRule { 
    | override def transform(n: Node): Seq[Node] = n match { 
    |  case <version>{v}</version> if v.text contains "SNAPSHOT" => <version>{v.text.split("-")(0)}</version> 
    |  case elem: Elem => elem copy (child = elem.child flatMap (this transform)) 
    |  case other => other 
    | } 
    | } transform res0 
res9: Seq[scala.xml.Node] = 
<dependency> 
    <groupId>foo</groupId> 
    <artifactId>bar</artifactId> 
    <version>1.0</version> 
</dependency> 
+0

Avez-vous une idée de la complexité dans le temps de votre solution? Quel est le coût de la correspondance/recherche dans l'arborescence XML? O (log n)? – Themerius

+0

@Themerius J'avais l'habitude d'être n au carré, pour la profondeur n, si je me souviens bien. Il y avait un ticket et un patch pour ça, mais je ne me souviens pas si ça a été corrigé. –

2

texte est représenté comme Node intérieur du Element de nœud. Donc, un peu de récursion fonctionnelle vous permettra de faire une copie complète & filtre:

def deepCopy(node:Node) : Node = node match { 
    case e : Elem => e.copy(child = this.child.toSeq.map(deepCopy)) 
    case t : Text => new Text(t.text.split("-").head) 
    case x => x 
} 

Avertissement: ce code n'a pas été testé pour les erreurs

0

En utilisant Scalate's Scuery CSS3 transforms et scala.xml.Elem#copy:

val xml = 
    <dependency> 
    <version>1.0-SNAPSHOT</version> 
    <version>2.0</version> 
    </dependency> 

new Transformer { 
    $("dependency > version") { node => 
    node.asInstanceOf[Elem].copy(child = Text(node.text.stripSuffix("-SNAPSHOT"))) 
    } 
}.apply(xml) 

cède

NodeSeq(<dependency><version>1.0</version><version>2.0</version></dependency>) 
Questions connexes