Voici une autre approche qui mérite d'être considérée. Nous allons essentiellement construire le fichier scala.xml.Elem à partir d'une chaîne et utiliser des requêtes de style XPath.
import scala.xml._
def childUnion(parent: String, a: Elem, b: Elem): Elem = {
val open:String = "<" + parent + ">"
val close:String = "</" + parent + ">"
val children = a \\ parent \ "_" ++ b \\ parent \ "_"
return XML.loadString(open + children + close)
}
Tout d'abord nous avons créé les open
et close
balises, qui ne sont que des chaînes. Ensuite, nous construisons children
en utilisant une requête de style XPath.
\\
est un opérateur sur Elem qui retourne des éléments et toutes les sous-séquences de l'Elem.
\
est similaire mais il renvoie les éléments de l'Elem.
"_"
est le caractère générique.
Pourquoi ne pas simplement \
? J'ai eu du mal à comprendre cela sur la base de la documentation, mais en regardant XPath for Java, je pense que \\
comprend tout l'Elem lui-même et les enfants alors que \
ne comprend que les enfants, donc si nous avions <parent><x/></parent> \ "parent"
nous ne trouverions rien puisque seulement est passé.
Maintenant, cette méthode n'est pas géniale. Que pouvons-nous faire pour le rendre un peu plus génial? Nous ferions mieux d'utiliser la classe Option
de Scala et la méthode foldLeft
.
def childUnion(parent: String, a: Elem, b: Elem*): Option[Elem] = {
val parentElem = a \\ parent
parentElem.size match {
case 0 => None // no parent present
case _ =>
val children = b.foldLeft(parentElem \ "_")((d,c) => (d ++ (c \\ parent \ "_")))
val open:String = "<" + parent + ">"
val close:String = "</" + parent + ">"
Some(XML.loadString(open + children + close))
}
}
Bien sûr, a l'avantage de travailler doucement ajouté sur un seul Elem, les cas où le parent est absent, et un nombre variable de Elem comme argument. Voici une longue liste d'exemples que j'ai courus en présentant cette dernière méthode,
scala> a
res85: scala.xml.Elem = <fruit> <apple></apple> <orange></orange> </fruit>
scala> b
res86: scala.xml.Elem = <fruit> <banana></banana> </fruit>
scala> c
res87: scala.xml.Elem = <box><fruit><apple></apple></fruit></box>
scala> d
res88: scala.xml.Elem = <box><nofruit></nofruit></box>
scala> e
res89: scala.xml.Elem = <fruit></fruit>
scala> val f = <fruit />
f: scala.xml.Elem = <fruit></fruit>
scala> childUnion("fruit", a)
res91: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)
scala> childUnion("fruit", b)
res92: Option[scala.xml.Elem] = Some(<fruit><banana></banana></fruit>)
scala> childUnion("fruit", c)
res93: Option[scala.xml.Elem] = Some(<fruit><apple></apple></fruit>)
scala> childUnion("fruit", d)
res94: Option[scala.xml.Elem] = None
scala> childUnion("fruit", e)
res95: Option[scala.xml.Elem] = Some(<fruit></fruit>)
scala> childUnion("fruit", a, b)
res96: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange><banana></banana></fruit>)
scala> childUnion("fruit", a, e)
res97: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)
scala> childUnion("fruit", a, c)
res98: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange><apple></apple></fruit>)
scala> childUnion("fruit", a, d)
res99: Option[scala.xml.Elem] = Some(<fruit><apple></apple><orange></orange></fruit>)
scala> childUnion("fruit", e, d)
res100: Option[scala.xml.Elem] = Some(<fruit></fruit>)
scala> childUnion("fruit", d, d)
res101: Option[scala.xml.Elem] = None
scala> childUnion("fruit", f)
res102: Option[scala.xml.Elem] = Some(<fruit></fruit>)