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 RewriteRule
s and corresponding RuleTransformer
s 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?