Skip to content

Groovy Guide — XML: Parsing and Generating XML

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Groovy Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

Groovy XML processing uses XmlSlurper for lazy GPath-style Parsing, XmlParser for detailed DOM access, and MarkupBuilder for generation, covering all XML use cases.

What You'll Learn

  • XmlSlurper for parsing and navigation
  • XmlParser for detailed access
  • GPath queries on XML
  • XML generation with MarkupBuilder
  • XML namespaces

Why It Matters

XML remains common in configuration, Web Services, and data exchange. Groovy makes XML work feel like native object navigation. Durga Antivirus Pro uses XML for rule definitions.

Real-World Use

Parsing configuration files, web service responses, document processing, and data transformation.

flowchart LR
    A["XML"] --> B["XmlSlurper"]
    B --> C["XmlParser"]
    C --> D["GPath"]
    D --> E["Generation"]
    A:::current --> B
    style A fill:#2563eb,stroke:#2563eb,color:#fff
    style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b

XmlSlurper

def xml = '''
<books>
    <book id="1">
        <title>Groovy in Action</title>
        <price>49.99</price>
    </book>
    <book id="2">
        <title>Making Java Groovy</title>
        <price>39.99</price>
    </book>
</books>
'''

def books = new XmlSlurper().parseText(xml)

// GPath navigation
books.book.size()               // 2
books.book[0].title.text()      // "Groovy in Action"
books.book*.title*.text()       // ["Groovy in Action", "Making Java Groovy"]
books.book.findAll { it.@id == "1" }.title.text()

XmlParser

def root = new XmlParser().parseText(xml)

// Access nodes
def books = root.book
books.each { book ->
    println "ID: ${book.@id}"
    println "Title: ${book.title[0].text()}"
    println "Price: ${book.price[0].text()}"
}

// Depth-first search
def depths = root.depthFirst()
depths.each { node ->
    if (node.name() == "title") {
        println node.text()
    }
}

XmlSlurper vs XmlParser

// XmlSlurper: lazy, read-only, GPath
// Best for navigation and queries

// XmlParser: eager, mutable, DOM-like
// Best for modification and detailed access

// Slurper is more memory efficient for large XML
// Parser allows modification of the tree

Modifying XML with XmlParser

def root = new XmlParser().parseText(xml)

// Modify attribute
root.book[0].@id = "10"

// Add child
def newBook = new Node(root, "book", [id: "3"])
newBook.appendNode("title", "Groovy Recipes")
newBook.appendNode("price", "44.99")

// Remove node
root.remove(root.book[1])

// Serialize
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(root)
println writer.toString()

Generating XML

import groovy.xml.MarkupBuilder

def writer = new StringWriter()
def xml = new MarkupBuilder(writer)

xml.books() {
    book(id: "1") {
        title("Groovy in Action")
        price("49.99")
    }
    book(id: "2") {
        title("Making Java Groovy")
        price("39.99")
    }
}

println writer.toString()

XML Namespaces

def xml = '''
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <getUserResponse xmlns="http://example.com">
            <name>Alice</name>
        </getUserResponse>
    </soap:Body>
</soap:Envelope>
'''

def root = new XmlSlurper().parseText(xml)
root.declareNamespace(soap: "http://schemas.xmlsoap.org/soap/envelope/")

root.'soap:Body'.'getUserResponse'.name.text()
// "Alice"

Common Mistakes

1. Forgetting .text() on nodes

XmlSlurper nodes are not strings. Call .text() to get the string content.

2. Attribute access syntax

Use .@attr or .@['attr'] for attributes. Not .attribute().

3. Namespace handling

XML with namespaces requires declareNamespace() on the root element.

4. Slurper vs Parser choice

Use Slurper for reading, Parser for writing/modifying. They are not interchangeable for all cases.

5. Large XML memory

XmlSlurper is lazy but still loads enough to parse. For streaming, use XmlParser with InputStream.

Practice Questions

1. What is the difference between XmlSlurper and XmlParser? XmlSlurper is lazy and read-only with GPath. XmlParser is eager and mutable with DOM-style access.

2. How do you access XML attributes in Groovy? Use node.@attrname or node.@['attr-name'] for hyphenated attributes.

3. How do you handle XML namespaces? Call root.declareNamespace(prefix: uri) on the parsed document before navigation.

Challenge: Parse an XML RSS feed and extract article titles and links using XmlSlurper.

FAQ

{{< faq question="Is XmlSlurper thread-safe?" >} No. XmlSlurper documents are not thread-safe. Create a new instance per thread. {{< /faq >}}

{{< faq question="Can XmlSlurper handle malformed XML?" >} No. Both Slurper and Parser require well-formed XML. Use XmlUtil for cleanup. {{< /faq >}}

{{< faq question="What is GPathResult?" >} The return type of XmlSlurper navigation. It represents a set of nodes supporting iterative methods. {{< /faq >}}

{{< faq question="How do I pretty-print XML?" >} Use XmlUtil.serialize(yourXml). The XmlNodePrinter also handles formatting. {{< /faq >}}

{{< faq question="Can I validate XML against a schema?" >} Yes. Use standard javax.xml.validation APIs with your schema file. {{< /faq >}}

Mini Project

Parse and transform an XML document:

def xml = '''
<catalog>
    <product id="P1">
        <name>Widget</name>
        <price currency="USD">29.99</price>
        <category>Tools</category>
    </product>
    <product id="P2">
        <name>Gadget</name>
        <price currency="USD">49.99</price>
        <category>Electronics</category>
    </product>
</catalog>
'''

def catalog = new XmlSlurper().parseText(xml)

// Extract products grouped by category
def byCategory = catalog.product.groupBy { it.category.text() }
byCategory.each { category, products ->
    println "$category:"
    products.each { p ->
        println "  ${p.name.text()} - \$${p.price.text()}"
    }
}

What's Next

Now that you understand XML processing, explore JSON handling in Groovy.

Topic Description Link
Groovy JSON JSON processing {{< ref "11-json" >}}
Groovy File I/O File operations {{< ref "12-file-io" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro