Xml in Groovy

Our first program will demonstrate XML processing in Groovy. Here’s the full source code:

import groovy.xml.XmlSlurper
import groovy.xml.MarkupBuilder

// Plant will be mapped to XML. We use Groovy's @Canonical annotation
// to automatically generate toString, equals, and hashCode methods.
@groovy.transform.Canonical
class Plant {
    int id
    String name
    List<String> origin

    // Custom XML serialization
    String toXml() {
        def writer = new StringWriter()
        def xml = new MarkupBuilder(writer)
        xml.plant(id: id) {
            name(name)
            origin.each { o ->
                origin(o)
            }
        }
        return writer.toString()
    }
}

// Main function
static void main(String[] args) {
    def coffee = new Plant(id: 27, name: "Coffee", origin: ["Ethiopia", "Brazil"])

    // Emit XML representing our plant
    println coffee.toXml()

    // To add a generic XML header to the output, prepend it explicitly
    println '<?xml version="1.0" encoding="UTF-8"?>\n' + coffee.toXml()

    // Use XmlSlurper to parse a string of XML into a data structure
    def xmlString = coffee.toXml()
    def parsedXml = new XmlSlurper().parseText(xmlString)
    
    def p = new Plant(
        id: parsedXml.@id.toInteger(),
        name: parsedXml.name.text(),
        origin: parsedXml.origin.collect { it.text() }
    )
    println p

    def tomato = new Plant(id: 81, name: "Tomato", origin: ["Mexico", "California"])

    // Demonstrate nesting of XML elements
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)
    xml.nesting {
        parent {
            child {
                plant(coffee.toXml())
                plant(tomato.toXml())
            }
        }
    }
    println writer.toString()
}

To run the program, save it as XmlExample.groovy and use the groovy command:

$ groovy XmlExample.groovy
<plant id='27'>
  <name>Coffee</name>
  <origin>Ethiopia</origin>
  <origin>Brazil</origin>
</plant>

<?xml version="1.0" encoding="UTF-8"?>
<plant id='27'>
  <name>Coffee</name>
  <origin>Ethiopia</origin>
  <origin>Brazil</origin>
</plant>

Plant(27, Coffee, [Ethiopia, Brazil])

<nesting>
  <parent>
    <child>
      <plant>
        <plant id='27'>
          <name>Coffee</name>
          <origin>Ethiopia</origin>
          <origin>Brazil</origin>
        </plant>
      </plant>
      <plant>
        <plant id='81'>
          <name>Tomato</name>
          <origin>Mexico</origin>
          <origin>California</origin>
        </plant>
      </plant>
    </child>
  </parent>
</nesting>

This example demonstrates XML processing in Groovy. We define a Plant class with custom XML serialization. We then create instances of this class, serialize them to XML, parse XML back into objects, and demonstrate nested XML structures.

Groovy provides powerful XML processing capabilities through classes like MarkupBuilder for creating XML and XmlSlurper for parsing XML. These make working with XML in Groovy quite straightforward and intuitive.

Note that unlike the original example, Groovy doesn’t have built-in XML annotations. Instead, we’ve implemented custom XML serialization in the toXml() method. For parsing, we use Groovy’s XmlSlurper which provides a convenient way to navigate XML structures.

The nesting example demonstrates how to create more complex XML structures using Groovy’s MarkupBuilder. This achieves a similar result to the original example, but uses Groovy’s syntax for creating nested structures.

Now that we’ve seen how to work with XML in Groovy, let’s explore more features of the language.