Skip to content

Instantly share code, notes, and snippets.

@zentrope
Created December 4, 2010 08:23
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save zentrope/728034 to your computer and use it in GitHub Desktop.
Save zentrope/728034 to your computer and use it in GitHub Desktop.
Transforming XML using RewriteRule and RuleTransformer
// Import the magic libraries
import scala.xml._
import scala.xml.transform._
// Source xml. In Scala, xml is literal.
val xml =
<user>
<email>joe@example.com</email>
<password>secret</password>
<features>
<feature id="one"/>
<feature id="two"/>
<feature id="three"/>
</features>
<foo>
<bar id="qux" name="caddr"/>
<bar id="baz" name="cdddr"/>
</foo>
</user>
// The problem: replace the "features" list in the above XML
// with a new features list: ["a", "b", "c", "d"]
// Define a function to take a dom and replace the existing
// list of features with a new list of features.
def replaceFeatures(dom: Node, features: List[String]): Node = {
// You can define objects (or classes) inside functions.
object replaceFeatures extends RewriteRule {
// The rule replaces any "features" element with a new
// features element we build for the occasion.
override def transform(n: Node): Seq[Node] = n match {
// match on the "features" element
case Elem(prefix, "features", attribs, scope, _*) =>
// XML literals again...
// Can embed scala inside an XML literal: In this case,
// apply an anonymous function over the list of features
// in the original parameter list of the replaceFeatures
// function. The func turns a feature name into a feature
// node.
<features>
{ features map { d => <feature id={d}/> } }
</features>
// That which we cannot speak of, we must pass over
// in silence....
case other =>
other
}
}
// Subclass a RuleTransformer (because it's abstract), handing
// it a vararg list of rules to use (in this case, just one).
object transform extends RuleTransformer(replaceFeatures)
// Do the transform. (A scala function's return value is the
// value of the last expression (and everything's an expression).
transform(xml)
}
// Transform the xml, replacing the existing feature list
// with a new list constructed from our feature list.
val newXml = replaceFeatures(xml, List("a", "b", "c", "d"))
// Just for fun...
//
// Create a partial function pp so we don't have to have a nasty object
// floating around. pp(xml) is much better than printer.format(xml),
// eh? The underscore stands for the expected value.
val pp = new PrettyPrinter(123, 2).format(_:Node)
// Print before and after
println("before = \n" + pp(xml))
println("after = \n" + pp(newXml))
@zentrope
Copy link
Author

zentrope commented Dec 4, 2010

I had a problem similar to the above at work. Basically, I need to take an existing XML doc and alter some values so that I could then save it back to a data store. If you've ever had to work with DOM manipulation, you know it's pretty painful. I really like the Scala solution. Also, I love the "partial function" thing at the end. I really need to do more of that in my own code.

@zentrope
Copy link
Author

zentrope commented Dec 4, 2010

Output

before =

joe@example.com
secret









after =

<user>
  <email>joe@example.com</email>
  <password>secret</password>
  <features>
    <feature id="a"></feature>
    <feature id="b"></feature>
    <feature id="c"></feature>
    <feature id="d"></feature>
  </features>
  <foo>
    <bar name="caddr" id="qux"></bar>
    <bar name="cdddr" id="baz"></bar>
  </foo>
</user>

@christoph-neumann
Copy link

I love that when I search for Scala examples, your gists keep popping up! Thanks again!

@baallezx
Copy link

baallezx commented Jun 6, 2014

Hey I am interested in your code for doing xml transformations, but I am completely new to scala can you help explain the process of running this file?

@zebaslam
Copy link

zebaslam commented Aug 5, 2015

Does this work if there iare XML entities present in the file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment