Reputation: 369
I have some xml where there is an <id/>
node at the top level, and also inside descendant nodes. Is there a way for me to change the value at the top level and not at the lower levels?
Sample input is
val inputXml =
<top>
<id>123</id>
<a>
<id>innerId</id>
</a>
<b>other info</b>
<c>
<id>444</id>
</c>
</top>
The output I'd like to see is:
val expectedOutputXml =
<top>
<id>999</id>
<a>
<id>innerId</id>
</a>
<b>other info</b>
<c>
<id>444</id>
</c>
</top>
I've tried using RewriteRule like this:
import scala.xml.transform.{RewriteRule, RuleTransformer}
import scala.xml.{Elem, Node, NodeSeq}
def changeTopId(root:Node, newId:String) = {
val dontChg = root \ "_" filter {e => List("a", "b").contains(e.label)}
object t1 extends RewriteRule{
override def transform(n: Seq[Node]): Seq[Node] = n match {
case e:Elem if dontChg.contains(e) => e
case e:Elem if e.label == "id" => <id>{newId}</id>
case other => other
}
}
object changeTopOne extends RuleTransformer(t1)
changeTopOne(root)
}
But it affects all <id/>
nodes, resulting in:
scala> changeTopId(inputXml, "999")
res1: scala.xml.Node =
<top>
<id>999</id>
<a>
<id>999</id>
</a>
<b>other info</b>
<c>
<id>999</id>
</c>
</top>
Thanks
Upvotes: 1
Views: 186
Reputation: 369
Turns out I didn't need Rewrite Rule. Here's a 5 line solution.
val xs = (inputXml \ "_") map {
case e: Elem if e.label == "id" => <id>999</id>
case other => other
}
inputXml.copy(child=xs)
And the resulting value (formatted manually)
scala.xml.Elem =
<top>
<id>999</id>
<a>
<id>innerId</id>
</a>
<b>other info</b>
<c>
<id>444</id>
</c>
</top>
Upvotes: 1