scala / scala-xml

The standard Scala XML library
Apache License 2.0
297 stars 92 forks source link

Variable name collision in RewriteRule class #129

Closed hghina0 closed 5 years ago

hghina0 commented 7 years ago

Below program doesn't give expected output

import scala.xml.{Elem, Node, Text}
import scala.xml.transform.{RewriteRule, RuleTransformer}

object XmlTransform extends App {
  val name = "contents"
  val value = "2"

  val InputXml : Node =
    <root>
      <subnode>1</subnode>
      <contents>1</contents>
    </root>

  val transformer = new RuleTransformer(new RewriteRule {
    override def transform(n: Node): Seq[Node] = n match {
      case elem @ Elem(prefix, label, attribs, scope, _) if elem.label == name =>
        Elem(prefix, label, attribs, scope, false, Text(value))

      case other => other
    }
  })
  println(transformer(InputXml))
}

If I change "case if" statement like

case elem @ Elem(prefix, label, attribs, scope, _) if elem.label == "contents" =>
        Elem(prefix, label, attribs, scope, false, Text(value))

It transforms xml as expected. Is it known issue?

ashawley commented 7 years ago

Is it known issue?

No, probably not. You have come accross an unfortunate name-collision because of the lexical scoping rules of Scala. It's a sconsequence of this class member:

http://www.scala-lang.org/api/current/scala-xml/scala/xml/transform/RewriteRule.html#name:String

https://github.com/scala/scala-xml/blob/4c09977/src/main/scala/scala/xml/transform/RewriteRule.scala#L23

It's not clear what it's for, but there's probably no reason to have it there, IMO.

Here's a minimal version of your test

  @Test
  def rewriteRuleNameCollision = { // #129

    val name = "contents"

    val transformer = new RuleTransformer(new RewriteRule {
      override def transform(n: Node): Seq[Node] = n match {
        case elem @ Elem(prefix, label, attribs, scope, _) if elem.label == name =>
          Elem(prefix, label, attribs, scope, false, Text("2"))
        case _ => n
      }
    })
    assertEquals(<contents>2</contents>, transformer(<contents>1</contents>))
  }

It fails with

[error] Test scala.xml.Transformers.rewriteRuleNameCollision failed: expected:<<contents>2</contents>> but was:<<contents>1</contents>>
hghina0 commented 7 years ago

Thanks for quick clarification. I appreciate.