I'm trying to replace pieces of XML and need an accumulator along the way. Say I have a fill-in-the-blank question stored as XML like so:
val q = <text>The capitals of Bolivia are <blank/> and <blank/>.</text>
At some point I'm going to want to turn those blanks into HTML input elements and I need to be able to distinguish the first and second so I can check them. (Ignore the fact that, in this case, the two capitals can appear in either order--that's a headache I'll deal with later.)
Thanks to some lovely answers on StackOverflow, I produced the following solution:
import scala.xml._
import scala.xml.transform._
class BlankReplacer extends BasicTransformer {
var i = 0
override def transform(n: Node): NodeSeq = n match {
case <blank/> => {
i += 1
<input name={ "blank.%d".format(i) }/>
}
case elem: Elem => elem.copy(child=elem.child.flatMap(transform _))
case _ => n
}
}
and this works reasonably well. I have to create a new BlankReplacer()
each time I want to start re-numbering, but it pretty much works:
scala> new BlankReplacer()(q)
res6: scala.xml.Node = <text>The capitals of Bolivia are <input name="blank.1"></input> and <input name="blank.2"></input>.</text>
Here's the question. Is there an easy way to avoid the mutation I have to do each time I replace a <blank/>
? What I have doesn't strike me as horrible, but I think this could be cleaner if I weren't creating a new instance of the BlankReplacer
class every time I had to convert a question to HTML. I'm sure there's some way to turn this into an accumulator, but I'm not sure how to do it.
Thanks! Todd