I want to choose arbitrary element in xml at runtime and update its value. For example, given xml like
<root>
<abc>123</abc>
<def>456</def>
</root>
I want to arbitrary pick either <abc>
or <def>
at runtime (not hardcoded) and update its value. I found many question in related links but all solution hard code label name upfront.
I tried function that takes element name and new value as params like
object RuleFactory {
// This function should not hard code literals "abc" or "def"
def createRuleTransformer(name:String, value : String) : RuleTransformer = {
new RuleTransformer(new RewriteRule {
override def transform(n: Node): Seq[Node] = n match {
case elem @ Elem(prefix, label, attribs, scope, _) if elem.label.equalsIgnoreCase(name) => Elem(prefix, label, attribs, scope, false, Text(value))
case other => other
}
})
}
}
and
object RuleFactory {
def createRuleTransformer(name:String, value : String) : RuleTransformer = {
new RuleTransformer(new RewriteRule {
override def transform(n: Node): Seq[Node] = n match {
case elem : Elem if elem.label.equalsIgnoreCase(name) => elem copy (child = Text(value) flatMap (this transform))
case other => other
}
})
}
}
However both don't print updated xml when I perform transform like
val trasnformer = RuleFactory.createRuleTransformer("def", "2") // These params will be random
println(trasnformer(InputXml))
Is this possible with RewriteRule?
From https://github.com/scala/scala-xml/issues/129
It turns out to be unfortunate name-collision because of the lexical scoping rules of Scala. It's a consequence of this class member:
http://www.scala-lang.org/api/current/scala-xml/scala/xml/transform/RewriteRule.html#name:String
Changing variable name solve the problem. Here is updated code.
object RuleFactory {
def createRuleTransformer(key:String, value : String) : RuleTransformer = {
new RuleTransformer(new RewriteRule {
override def transform(n: Node): Seq[Node] = n match {
case elem @ Elem(prefix, label, attribs, scope, _) if elem.label.equalsIgnoreCase(key) =>
Elem(prefix, label, attribs, scope, false, Text(value))
case other => other
}
})
}
}