'How to mix Scala and XML to dynamically generate XML'에 해당되는 글 1건

  1. 2014.03.28 How to mix Scala and XML to dynamically generate XML
00.scala2014. 3. 28. 14:23
반응형

Problem: You want to dynamically generate XML from your 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 cards 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 the map method.
  • The variable i is enclosed in curly braces inside the <li> tags, where it will be replaced by its values as the map 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>

See Recipe 5.9 of the Scala Cookbook, “Supporting a Fluent Style of Programming,” for more information on supporting and using this coding style.

Posted by 1010