Bit of a bizarre one, this, and I'm tempted to assume it may be a bug. Background - I have a whole load of XML that looks like this:
<foo id="1">
 <bar id="0">
  <baz id="0" blah="blah" etc="etc">
   <buz id="0" />
  </baz>
  <buz id="0" blah="blah" etc="etc">
   ...
  </buz>
 </bar>
</foo>
<foo id="2">
 <bar id="0">
  <baz id="0" blah="blah" etc="etc">
   <buz id="0" />
  </baz>
  <buz id="0" blah="blah" etc="etc">
   ...
  </buz>
 </bar>
</foo>
....
What I want to do is to transform this such that, for each foo element, I replace all the zero ids inside it with the id of foo.
To do this - firstly, I'm using Daniel's code along with an implicit conversion to provide 'Elem' with a mapAttributes method:
class ElemWithUsefulAttributes(elem : Elem) extends Elem(elem.prefix, elem.label, elem.attributes, elem.scope, elem.child : _*) {
def mapAttributes(f : GenAttr => GenAttr) = this.copy(attributes = mapMetaData(elem.attributes)(f))
}
implicit def Elem2ElemWithUsefulAttributes(elem : Elem) = new ElemWithUsefulAttributes(elem)
Then I've got a 'replaceId' method:
def replaceId(attr : String, id : String)(in : GenAttr) = in match {
  case g@GenAttr(_,key,Text(v),_) if (key.equals(attr)) => g.copy(value=Text(id))
  case other => other
}
Finally, I construct a couple of RewriteRules and corresponding RuleTransformers to deal with this:
class rw1(id : String) extends RewriteRule {
  override def transform(n : Node) : Seq[Node] = n match {
    case n2: Elem if (n2.label == "bar") => n2.mapAttributes(replaceId("id", id))
    case n2: Elem if (n2.label == "baz") => n2.mapAttributes(replaceId("id", id))
    case n2: Elem if (n2.label == "buz") => n2.mapAttributes(replaceId("id", id))
    case other => other
  }
}
class rt1(id : String) extends RuleTransformer(new rw1(id))
object rw2 extends RewriteRule {
  override def transform(n : Node) : Seq[Node] = n match {
    case n2@Elem(_, "foo", _, _, _*) => (new rw1(n2.attribute("id").get.toString))(n2)
    case other => other
  }
}
val rt2 = new RuleTransformer(rw2)
After calling rt2(xml), I get output that looks like the following:
<foo id="1">
 <bar id="1">
  <baz id="0" blah="blah" etc="etc">
   <buz id="1" />
  </baz>
  <buz id="0" blah="blah" etc="etc">
   ...
  </buz>
 </bar>
</foo>
<foo id="2">
 <bar id="2">
  <baz id="0" blah="blah" etc="etc">
   <buz id="2" />
  </baz>
  <buz id="0" blah="blah" etc="etc">
   ...
  </buz>
 </bar>
</foo>
....
In other words, the attributes haven't been changed where there are multiple attributes. Naturally, one wants to suppose this is a problem with the mapAttributes code - however, if I dump out the results of the transform in the 'match' statement in rw1, I can clearly see it showing:
  <baz id="2" blah="blah" etc="etc">
   <buz id="2" />
  </baz>
Further, if I alter a single baz, say, to remove the extra attributes then it works correctly and gets mapped. So it seems to be a strange combination of the multiple attributes and the transforms.
Can anybody make head or tail of this?