Groovy XML
last modified October 15, 2026
Groovy treats XML as a native data type rather than a chore delegated to a
heavyweight parser API. The XmlSlurper class parses a document
into a tree that you navigate with GPath, a query language whose dots and stars
mirror Groovy's own property access. Combined with MarkupBuilder
for output, Groovy makes reading and writing XML remarkably concise. This
tutorial covers both directions with practical examples.
Parsing XML with XmlSlurper
Create an XmlSlurper and call parseText to turn an XML
string into a navigable tree. Child elements are reached by name, and their text
is obtained with text().
import groovy.xml.XmlSlurper
def xmlText = '''<book>
<title>Groovy in Action</title>
<author>Dierk Koenig</author>
<year>2015</year>
</book>'''
def book = new XmlSlurper().parseText(xmlText)
println book.title.text()
println book.author.text()
println book.year.text()
The parsed book behaves like an object whose elements are
properties. book.title.text() returns the enclosed string. The
result is a GPathResult, which supports many of the collection
methods you already know from lists.
$ groovy SimpleXmlSlurper.groovy Groovy in Action Dierk Koenig 2015
Parsing XML from a File
The parse method accepts a File, a Reader,
or an InputStream. This is the usual entry point when loading
configuration or data from disk.
import groovy.xml.XmlSlurper
def xmlFile = new File("books.xml")
def root = new XmlSlurper().parse(xmlFile)
root.book.each { book ->
println "${book.title.text()} (${book.year.text()})"
}
Assuming the root element is <books> containing several
<book> children, the each call iterates over
them. Each item is again a GPathResult, so the same navigation
rules apply at every level.
$ groovy XmlFromFile.groovy A (2001) B (2002)
Navigating with GPath
GPath descends the tree with dots. To iterate all descendants with a given name, prefix the name with a double dot, or use the spread-style double dot to reach any depth.
import groovy.xml.XmlSlurper
def xmlText = '''<catalog>
<book>
<title>Book One</title>
<prices><price currency="USD">29.99</price></prices>
</book>
<book>
<title>Book Two</title>
<prices><price currency="EUR">24.50</price></prices>
</book>
</catalog>'''
def catalog = new XmlSlurper().parseText(xmlText)
println catalog.book.title*.text()
println catalog.'**'.findAll { it.name() == 'price' }*.text()
The spread operator on title*.text() collects the text of every
title into a list. The double-star pattern ** matches descendants
at any depth, and findAll narrows them by tag name. GPath turns
tree queries into ordinary collection pipelines.
$ groovy GPathNavigation.groovy [Book One, Book Two] [29.99, 24.50]
Filtering with GPath
Because GPath nodes respond to findAll, find, and
other collection methods, you filter by attribute or text directly.
import groovy.xml.XmlSlurper
def xmlText = '''<books>
<book available="true"><title>Groovy</title></book>
<book available="false"><title>Java</title></book>
</books>'''
def books = new XmlSlurper().parseText(xmlText)
def available = books.book.findAll { it.@available == 'true' }
available.each { println it.title.text() }
The @ prefix reads an attribute, so it.@available
compares the attribute value. Only the available book is printed. Attribute
access composes naturally with closures and predicates.
$ groovy GPathFilter.groovy Groovy
Reading Attributes
Attributes are accessed with @name, while the attributes()
method returns them as a map when you need to enumerate them.
import groovy.xml.XmlSlurper def xmlText = '''<img src="logo.png" width="120" height="40" />''' def img = new XmlSlurper().parseText(xmlText) println img.@src println img.attributes()
img.@src yields logo.png, and
attributes() returns a map of every attribute. This is convenient
for generic processing where the attribute names are not known in advance.
$ groovy XmlAttributes.groovy logo.png [src:logo.png, width:120, height:40]
Working with Namespaces
Namespace-qualified elements are addressed by declaring a prefix with
declareNamespace and using that prefix in GPath expressions.
import groovy.xml.XmlSlurper
def xmlText = '''<root xmlns:h="http://example.com/hello">
<h:greeting>Hi there</h:greeting>
</root>'''
def root = new XmlSlurper().parseText(xmlText)
root.declareNamespace(h: 'http://example.com/hello')
println root.'h:greeting'.text()
Once the prefix is declared, h:greeting resolves against the URI.
Namespaces are common in SOAP, SVG, and Atom feeds, so this keeps navigation
readable without manual URI juggling.
$ groovy XmlNamespace.groovy Hi there
XmlParser vs XmlSlurper
XmlParser returns a tree of Node objects that can be
mutated and then serialized back to XML. XmlSlurper is read-only but
lazier and more memory-friendly. Choose the slurper for queries and the parser
when you need to edit the document.
import groovy.xml.XmlParser import groovy.xml.XmlNodePrinter def xmlText = '''<book><title>Old Title</title></book>''' def book = new XmlParser().parseText(xmlText) book.title[0].value = ['New Title'] new XmlNodePrinter().print(book)
The parsed node is a mutable structure, so assigning to value
replaces the title text. XmlNodePrinter then renders the updated
tree. This round trip is ideal for in-place transformations.
$ groovy XmlParserEdit.groovy
<book>
<title>
New Title
</title>
</book>
Building XML with MarkupBuilder
MarkupBuilder generates XML from a builder-style closure. Nested
closure calls become nested elements, and named arguments become attributes.
import groovy.xml.MarkupBuilder
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.books {
book(available: 'true') {
title('Groovy in Action')
year(2015)
}
book(available: 'false') {
title('Effective Java')
year(2018)
}
}
println writer.toString()
The books closure contains two book elements, each
carrying an available attribute and nested children. The
MarkupBuilder handles escaping and indentation, producing clean XML
without string concatenation.
$ groovy MarkupBuilderDemo.groovy
<books>
<book available='true'>
<title>Groovy in Action</title>
<year>2015</year>
</book>
<book available='false'>
<title>Effective Java</title>
<year>2018</year>
</book>
</books>
Writing XML to a File
Pass a FileWriter to MarkupBuilder to persist the
generated document directly, which is convenient for feeds and reports.
import groovy.xml.MarkupBuilder
def file = new File("catalog.xml")
file.withWriter('UTF-8') { writer ->
def xml = new MarkupBuilder(writer)
xml.catalog {
item(id: 1, name: 'Widget')
item(id: 2, name: 'Gadget')
}
}
println file.text
The withWriter block closes the stream automatically, then
file.text confirms the result. Writing XML this way avoids manual
resource management and keeps the document structure visible in code.
$ groovy WriteXmlFile.groovy <catalog> <item id='1' name='Widget' /> <item id='2' name='Gadget' /> </catalog>
Best Practices for Working with XML
- Prefer XmlSlurper for Queries: Its lazy evaluation and GPath support make read-only navigation concise and efficient.
- Use XmlParser for Edits: When you must modify and resave a document, the mutable node tree is the right choice.
- Declare Namespaces Once: Call
declareNamespacenear the top to keep GPath expressions short. - Close Streams: Use
withReaderandwithWriterso files are released even on error. - Validate Untrusted Input: Disable external entity resolution when parsing XML from unknown sources.
Source
Groovy XML Processing Documentation
In this tutorial, we parsed and navigated XML with XmlSlurper and
GPath, filtered by attributes, handled namespaces, edited documents with
XmlParser, and generated XML with MarkupBuilder.
Groovy's native XML support keeps both reading and writing close to the shape
of the data itself.
Author
List all Groovy tutorials.