后续的RewriteRules不会转换在先前转换中添加的元素

时间:2018-09-05 10:42:13

标签: scala scala-xml

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时,确实会将子级添加到第一步中添加的元素中。我们希望changechangeWorkaround函数产生相同的输出。

Issue raised at scala xml

1 个答案:

答案 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,以便递归地工作。

这是如此令人困惑,我花了一些时间才能将代码重新跟踪到我从中回忆起的内容。在这里:

  1. RuleTransformer节点=> Seq [Node]调用超级(BasicRewrite)
  2. BasicRewrite节点=> Seq [Node]调用子节点上的Seq [Node] => Seq [Node]
  3. BasicRewrite Seq [Node] =>每个Seq [Node]调用Node => Seq [Node]
  4. 由于Node => Seq [Node]被覆盖,如果Seq不为空,它将递归回1
  5. 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>)