I have a NodeSeq like this:
<foo>
<baz><bar key1="value1" key2="value2">foobar</bar></baz>
Blah blah blah
<bar key1="value3">barfoo</bar>
</foo>
I want to add a new attribute to all bar
s' attributes. I'm currently doing:
val rule = new RewriteRule() {
override def transform(node: Node): Seq[Node] = {
node match {
case Elem(prefix, "bar", attribs, scope, content@_*) => Elem(prefix, "bar", attribs append Attribute(None, "newKey", Text("newValue"), scala.xml.Null) , scope, content:_*)
case other => other
}
}
}
But the problem is that it only works on 1 node. I want it to recursively work on all nodes, and if I call the transform inside a for
loop, I can't replace them with new values since they become immutable. How can I solve this?
Here is a simplified version of your own solution (using Daniel's variant of the matching logic):
def updateBar(node: Node): Node = node match {
case elem @ Elem(_, "bar", _, _, child @ _*) => elem.asInstanceOf[Elem] % Attribute(None, "newKey", Text("newValue"), Null) copy(child = child map updateBar)
case elem @ Elem(_, _, _, _, child @ _*) => elem.asInstanceOf[Elem].copy(child = child map updateBar)
case other => other
}
Note that the major differences between this and your original code is that this one processes the nodes from the outside in, as shown here where I've added some print statements as in my first answer:
scala> updateBar(<foo><bar>blabla</bar></foo>)
processing '<foo><bar>blabla</bar></foo>'
processing '<bar>blabla</bar>'
processing 'blabla'
result: 'blabla'
result: '<bar newKey="newValue">blabla</bar>'
result: '<foo><bar newKey="newValue">blabla</bar></foo>'
res1: scala.xml.Node = <foo><bar newKey="newValue">blabla</bar></foo>
While your original code works from the inside out (simplified example):
scala> xf { <a><b><c/></b></a> }
transforming '<c></c>'
result: '<c></c>'
transforming '<b><c></c></b>'
result: '<b><c></c></b>'
transforming '<a><b><c></c></b></a>'
result: '<a><b><c></c></b></a>'
res4: scala.xml.Node = <a><b><c></c></b></a>
There are probably cases where these two techniques will yield different results.
The other difference is that the matching code is slightly more verbose: you need one case for the actual transformation of the relevant element, and one case for recursively processing the subnodes. The example shown could probably be refactored a bit, though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With