¿Construir XML con etiqueta dinámica y atributos en Scala?
Pregunta
Quiero poder hacer esto:
val myXml = <myTag { someAttributes }> </myTag>
(porque no sé cuáles son los detalles del atributo en tiempo de compilación)
y esto:
val myXml = <{someTag}></{someTag}>
Esta sintaxis Scala no es válida. Lo más cerca que puedo llegar es usar el objeto Elem para construir elementos, pero es un poco problemático (insertar PCDATA donde no quiero). ¿Hay alguna forma de hacerlo como la anterior?
Solución
val myXml = <myTag/> % Attribute(None, "name", Text("value"), Null)
Ver scala.xml.Attribute
para diferentes constructores.
Agregando el mismo atributo a todos los hijos:
scala> val xml = <root><a/><b/><c/></root>
xml: scala.xml.Elem = <root><a></a><b></b><c></c></root>
scala> xml.child map (_ match {
| case elem : Elem => elem % Attribute(None, "name", Text("value"), Null)
| case x => x
| })
res3: Sequence[scala.xml.Node] = ArrayBuffer(<a name="value"></a>, <b name="value"></b>, <c name="value"></c>)
También puedes usar las cosas en scala.xml.transform para hacerlo recursivamente a todos los XML:
val rr = new RewriteRule {
override def transform(n: Node): Seq[Node] = n match {
case elem : Elem => elem % Attribute(None, "name", Text("value"), Null) toSeq
case other => other
}
}
val rt = new RuleTransformer(rr)
scala> rt(xml)
res5: scala.xml.Node = <root name="value"><a name="value"></a><b name="value"></b><c name="value"></c></root>
O puede agregar atributos a partes arbitrarias del xml:
scala> val xml = <root>{<a/> % Attribute(None, "name", Text("value"), Null)}</root>
xml: scala.xml.Elem = <root><a name="value"></a></root>
EDIT
Cambiar el nombre es fácil de hacer en Scala 2.8, así:
val someTag = "tag"
val myXml = <root>{<a/>.copy(label = someTag)}</root>
Otros consejos
Nota: necesita
import scala.xml.Null
para que esto funcione, y no scala.Null
, que también existe.