Scala FAQ: How can I dynamically generate XML from my Scala source code, such as creating output for a SOAP web service?
Solution
A great feature of Scala’s XML support is that you can interweave XML and regular Scala source code together. This lets you dynamically generate XML from your Scala code.
To create XML with dynamic, embedded data, just put your Scala code in curly braces inside the XML tags, as shown in the following example:
scala> val name = "Bill" name: String = Bill scala> val age = 42 age: Int = 42 scala> val p = <person><name>{name}</name><age>{age}</age></person> p: scala.xml.Elem = <person><name>Bill</name><age>42</age></person>
In this example, the Scala variables name and age are put inside curly braces, inside the XML literals. The variable p in the REPL results shows that they’re translated to their values (Bill and 42, respectively). Methods and other expressions can be used in the same way.
This ability to weave Scala code and XML together is similar to using a templating system, and is a great way to generate dynamic XML output, including output like an RSS news feed, all forms of business data, or a simple XHTML UL/LI tag combination:
scala> val fruits = List("apple", "banana", "orange") fruits: List[java.lang.String] = List(apple, banana, orange) scala> val ul = <ul>{fruits.map(i => <li>{i}</li>)}</ul> ul: scala.xml.Elem = <ul><li>apple</li><li>banana</li><li>orange</li></ul> scala> println(ul) <ul><li>apple</li><li>banana</li><li>orange</li></ul>
You can use the same technique to generate XHTML <select>
and <option>
tags, such as for a list of states or credit card options, and any other form of XML data.
Discussion
As shown in the fruits example, XML literals can contains Scala code in curly braces, and that code can include additional XML literal values, which can contain Scala code. This nesting of Scala and XML can continue to go deeper, as needed.
To explain how this works, let’s look at the code again:
val ul = <ul>{fruits.map(i => <li>{i}</li>)}</ul>
Here’s how this code works:
- The XML expression is enclosed in the matching
<ul>
tags. - The curly braces begin the
fruits.map
Scala expression. <li>
tags are embedded in the code block passed to themap
method.- The variable
i
is enclosed in curly braces inside the<li>
tags, where it will be replaced by its values as themap
method executes.
If you’ve used XML/HTML templating tools previously, you can appreciate the power of this approach.
NodeBuffer
The NodeBuffer
class provides another nice way to dynamically build XML. The following example shows how to build a set of <li>
tags as a NodeBuffer
, and then insert those elements into a final <ul>
tag:
scala> val x = new xml.NodeBuffer x: scala.xml.NodeBuffer = ArrayBuffer() scala> x += <li>apple</li> res0: x.type = ArrayBuffer(<li>apple</li>) scala> x += <li>banana</li> res1: x.type = ArrayBuffer(<li>apple</li>, <li>banana</li>) scala> val ul = <ul>{x}</ul> ul: scala.xml.Elem = <ul><li>apple</li><li>banana</li></ul>
NodeBuffer
is a simple convenience class that extends ArrayBuffer[Node]
. It adds one method named &+
that appends the given object to the buffer and returns a this reference for convenience. This lets you write a “fluent” style of code like this, if you prefer:
val nb = new xml.NodeBuffer val nb2 = nb &+ <li>apple</li> &+ <li>banana</li> &+ <li>cherry</li>