scalaでxmlのタグを置換したりする時に使うBasicTransformerにバグがあるようで、何度も同じタグに
対する置換処理が走ってしまうようです。既にバグの報告がされていて、パッチも投稿されていました。
http://lampsvn.epfl.ch/trac/scala/ticket/3689
投稿されているパッチを使ってみたところ、特定のパターンでやはり同じタグの置換処理が走る場合が
あって、さらに修正を施す必要がありました。
結果、できたものが下記のコードです。うまくオーバーライドとかでできればよかったのですが、だめだったので
BasicTransformerをコピってtransformメソッドを書き換えました。
class BugFixedBasicTransformer {
/**
* @param n ...
* @param ns ...
* @return ...
*/
protected def unchanged(n: Node, ns: Seq[Node]) =
ns.length == 1 && (ns.head == n)
/** Call transform(Node) for each node in ns, append results
* to NodeBuffer.
*/
def transform(it: Iterator[Node], nb: NodeBuffer): Seq[Node] =
it.foldLeft(nb)(_ ++= transform(_)).toSeq
/** Call transform(Node) to each node in ns, yield ns if nothing changes,
* otherwise a new sequence of concatenated results.
*/
// def transform(ns: Seq[Node]): Seq[Node] = {
// val (xs1, xs2) = ns span (n => unchanged(n, transform(n)))
//
// if (xs2.isEmpty) ns
// else xs1 ++ transform(xs2.head) ++ transform(xs2.tail)
// }
def transform(n: Node): Seq[Node] = {
if (n.doTransform) n match {
case Group(xs) => Group(transform(xs)) // un-group the hack Group tag
case _ =>
val ch = n.child
val nch = transform(ch)
if (ch eq nch) n
else Elem(n.prefix, n.label, n.attributes, n.scope, nch: _*)
}
else n
}
def apply(n: Node): Node = {
val seq = transform(n)
if (seq.length > 1)
throw new UnsupportedOperationException("transform must return single node for root");
else seq.head
}
def transform(ns: Seq[Node]): Seq[Node] = {
val xs = ns.toStream map transform
val (xs1, xs2) = xs zip ns span { case (x, n) => unchanged(n, x) }
if (xs2.isEmpty) ns
else {
(xs1 map (_._2)) ++ transform(xs2.head._1) ++ transform(ns drop (xs1.length + 1))
}
}
}
class BugFixedRuleTransformer(val rules: BugFixedRewriteRule*) extends BugFixedBasicTransformer {
override def transform(n: Node): Seq[Node] =
rules.foldLeft(super.transform(n)) { (res, rule) => rule transform res }
}
abstract class BugFixedRewriteRule extends BugFixedBasicTransformer {
/** a name for this rewrite rule */
val name = this.toString()
override def transform(ns: Seq[Node]): Seq[Node] = super.transform(ns)
override def transform(n: Node): Seq[Node] = n
}