import scala.xml._
import scala.xml.transform.{RewriteRule, RuleTransformer}
object TransformIssue {
def addNewElement(): RewriteRule = new RewriteRule {
override def transform(n: Node): Seq[Node] = n match {
case <element></element> => <element><new></new></element>
}
}
def addThingElement(): RewriteRule = new RewriteRule {
override def transform(n: Node): Seq[Node] = n match {
case <element>{ children@_*}</element> => <element>{ children }</element>
case <new></new> => <new><thing></thing></new>
}
}
def change(node: Node): Node =
new RuleTransformer(
addNewElement(),
addThingElement()
).transform(node).head
def changeWorkaround(node: Node): Node = {
val out1 = new RuleTransformer(
addNewElement()
).transform(node).head
new RuleTransformer(
addThingElement()
).transform(out1).head
}
}
-
import org.scalatest.{FlatSpec, FunSpec}
import org.scalatest._
class TransformIssueSpec extends FlatSpec with Matchers {
it should "apply transform to created elements" in {
val output = TransformIssue.change(<element></element>)
output should be(<element><new><thing></thing></new></element>)
} // fails
it should "work the same as the workaround imo" in {
TransformIssue.change(<element></element>) should equal(TransformIssue.changeWorkaround(<element></element>))
} // fails
}
当我们应用具有两个重写规则的转换时:第一个添加新元素,第二个将子元素添加到新元素;那么第二条重写规则与第一条规则中添加的元素不匹配。
当我们在两个单独的RuleTransformers中应用相同的RewriteRules时,确实会将子级添加到第一步中添加的元素中。我们希望change
和changeWorkaround
函数产生相同的输出。
答案 0 :(得分:1)
您没有将其应用于孩子。
def addThingElement(): RewriteRule = new RewriteRule {
override def transform(n: Node): Seq[Node] = n match {
case <element>{ children@_*}</element> => <element>{ transform(children) }</element>
case <new></new> => <new><thing></thing></new>
}
}
可行。
这就是问题所在:在BasicTransformer
上,def transform(n: Node): Seq[Node]
将def transform(ns: Seq[Node]): Seq[Node]
应用于n
的所有子节点,后一种方法将前者应用于每个节点。
RuleTransformer
会覆盖前一个方法,然后调用它,然后在结果上应用RewriteRule
,以便递归地工作。
这是如此令人困惑,我花了一些时间才能将代码重新跟踪到我从中回忆起的内容。在这里:
那么,在损坏的情况下,它将像这样:
RuleTransformer.transform(<element/>)
BasicRewrite.transform(<element/>)
BasicRewrite.transform(Seq.empty)
addNewElement(<element/>)
addThingElement(<element><new/></element>)
在工作情况下,它将像这样:
RuleTransformer.transform(<element/>)
BasicRewrite.transform(<element/>)
BasicRewrite.transform(Seq.empty)
addNewElement(<element/>)
RuleTransformer.transform(<element><new/></element>)
BasicRewrite.transform(<element><new/></element>)
BasicRewrite.transform(Seq(<new/>))
RuleTransformer.transform(<new/>)
BasicRewrite.transform(<new/>)
BasicRewrite.transform(Seq.empty)
addThingElement(<new/>)
addThingElement(<element><new><thing/></new></element>)