Apache Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities, for the Java platform aimed at improving developer productivity thanks to a concise, familiar and easy to learn syntax.
—
Comprehensive XML parsing, building, and manipulation with GPath expressions, builder patterns, and support for various XML processing approaches.
Parse XML into GPath expressions for easy navigation and manipulation.
/**
* Parser for XML into GPath expressions
*/
class XmlSlurper {
/** Create XmlSlurper with default configuration */
XmlSlurper()
/** Create XmlSlurper with validation enabled/disabled */
XmlSlurper(boolean validating)
/** Create XmlSlurper with custom XMLReader */
XmlSlurper(XMLReader reader)
/** Parse XML from string */
Object parseText(String text)
/** Parse XML from File */
Object parse(File file)
/** Parse XML from Reader */
Object parse(Reader reader)
/** Parse XML from InputStream */
Object parse(InputStream input)
/** Set feature on underlying XMLReader */
void setFeature(String feature, boolean value)
/** Set property on underlying XMLReader */
void setProperty(String property, Object value)
}Usage Examples:
import groovy.util.XmlSlurper
def xml = '''
<books>
<book id="1" category="fiction">
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<price currency="USD">12.99</price>
<tags>
<tag>classic</tag>
<tag>american</tag>
</tags>
</book>
<book id="2" category="science">
<title>Brief History of Time</title>
<author>Stephen Hawking</author>
<price currency="USD">15.99</price>
<tags>
<tag>physics</tag>
<tag>cosmology</tag>
</tags>
</book>
</books>
'''
def books = new XmlSlurper().parseText(xml)
// Access elements and attributes
println books.book[0].title.text() // "The Great Gatsby"
println books.book[0].@id // "1"
println books.book[0].@category // "fiction"
println books.book[0].price.@currency // "USD"
// Iterate over elements
books.book.each { book ->
println "${book.title} by ${book.author} - \$${book.price}"
}
// Find specific elements
def fictionBooks = books.book.findAll { it.@category == 'fiction' }
def physicsBooks = books.book.findAll { book ->
book.tags.tag.any { it.text() == 'physics' }
}
// Modify XML content (returns new structure)
def updatedBooks = books.replaceNode {
books {
books.book.each { book ->
book {
title(book.title.text())
author(book.author.text())
price(book.price.text().toDouble() * 0.9, currency: book.price.@currency)
discounted('true')
}
}
}
}Parse XML into Node objects for tree-based manipulation.
/**
* Parser for XML into Node objects
*/
class XmlParser {
/** Create XmlParser with default configuration */
XmlParser()
/** Create XmlParser with validation enabled/disabled */
XmlParser(boolean validating)
/** Create XmlParser with custom XMLReader */
XmlParser(XMLReader reader)
/** Parse XML from string and return Node */
Node parseText(String text)
/** Parse XML from File and return Node */
Node parse(File file)
/** Parse XML from Reader and return Node */
Node parse(Reader reader)
/** Parse XML from InputStream and return Node */
Node parse(InputStream input)
/** Set feature on underlying XMLReader */
void setFeature(String feature, boolean value)
/** Set property on underlying XMLReader */
void setProperty(String property, Object value)
}Usage Examples:
import groovy.util.XmlParser
def parser = new XmlParser()
def root = parser.parseText(xml)
// Navigate using Node methods
println root.name() // "books"
println root.book[0].title.text() // "The Great Gatsby"
println root.book[0].attribute('id') // "1"
// Modify nodes in place
root.book[0].appendNode('isbn', '978-0-7432-7356-5')
root.book[0].price.setValue('10.99')
// Add new book
root.appendNode('book', [id: '3', category: 'mystery']) {
title('The Murder of Roger Ackroyd')
author('Agatha Christie')
price('13.99', [currency: 'USD'])
}
// Remove nodes
def nodeToRemove = root.book.find { it.@id == '2' }
if (nodeToRemove) {
root.remove(nodeToRemove)
}Create XML/HTML markup using a fluent builder API.
/**
* Builder for creating XML/HTML markup
*/
class MarkupBuilder extends BuilderSupport {
/** Create MarkupBuilder writing to Writer */
MarkupBuilder(Writer writer)
/** Create MarkupBuilder writing to PrintWriter */
MarkupBuilder(PrintWriter writer)
/** Create MarkupBuilder with indentation */
MarkupBuilder(Writer writer, String indent)
/** Set XML declaration */
void setXmlDeclaration(boolean xmlDeclaration)
/** Set character encoding */
void setEncoding(String encoding)
/** Set whether to omit null attributes */
void setOmitNullAttributes(boolean omitNullAttributes)
/** Set whether to omit empty attributes */
void setOmitEmptyAttributes(boolean omitEmptyAttributes)
/** Set whether to expand empty elements */
void setExpandEmptyElements(boolean expandEmptyElements)
}Usage Examples:
import groovy.xml.MarkupBuilder
// Build XML to string
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.books {
book(id: '1', category: 'fiction') {
title('The Great Gatsby')
author('F. Scott Fitzgerald')
price('12.99', currency: 'USD')
tags {
tag('classic')
tag('american')
}
}
book(id: '2', category: 'science') {
title('Brief History of Time')
author('Stephen Hawking')
price('15.99', currency: 'USD')
tags {
tag('physics')
tag('cosmology')
}
}
}
println writer.toString()
// Build HTML
def htmlWriter = new StringWriter()
def html = new MarkupBuilder(htmlWriter)
html.html {
head {
title('My Page')
meta('http-equiv': 'Content-Type', content: 'text/html; charset=UTF-8')
}
body {
h1('Welcome to Groovy!')
div(class: 'content') {
p('This is a paragraph with ', {
a('a link', href: 'http://groovy-lang.org')
}, '.')
ul {
['Item 1', 'Item 2', 'Item 3'].each { item ->
li(item)
}
}
}
}
}
// Build XML with namespaces
def nsWriter = new StringWriter()
def nsXml = new MarkupBuilder(nsWriter)
nsXml.'soap:Envelope'('xmlns:soap': 'http://schemas.xmlsoap.org/soap/envelope/') {
'soap:Header' {
'auth:Authentication'('xmlns:auth': 'http://example.com/auth') {
'auth:username'('user123')
'auth:token'('abc123xyz')
}
}
'soap:Body' {
'req:GetUserRequest'('xmlns:req': 'http://example.com/requests') {
'req:userId'(12345)
}
}
}Create XML with streaming for large documents.
/**
* Streaming markup builder for large XML documents
*/
class StreamingMarkupBuilder {
/** Create streaming markup builder */
StreamingMarkupBuilder()
/** Set character encoding */
void setEncoding(String encoding)
/** Set whether to use double quotes for attributes */
void setUseDoubleQuotes(boolean useDoubleQuotes)
/** Bind closure and return writable */
Writable bind(Closure closure)
/** Bind closure with context */
Writable bind(Map context, Closure closure)
}Usage Examples:
import groovy.xml.StreamingMarkupBuilder
def builder = new StreamingMarkupBuilder()
builder.encoding = 'UTF-8'
def xml = builder.bind {
mkp.xmlDeclaration()
books {
largeDataSet.each { item ->
book(id: item.id) {
title(item.title)
author(item.author)
if (item.tags) {
tags {
item.tags.each { tag ->
tag(tag)
}
}
}
}
}
}
}
// Write to file
new File('large-books.xml').withWriter('UTF-8') { writer ->
writer << xml
}
// Write to HTTP response
response.contentType = 'application/xml'
response.characterEncoding = 'UTF-8'
response.writer << xmlUtility methods for XML processing and serialization.
/**
* XML utility methods
*/
class XmlUtil {
/** Serialize Node to string */
static String serialize(Node node)
/** Serialize Element to string */
static String serialize(Element element)
/** Serialize with custom properties */
static String serialize(Node node, Map<String, Object> outputProperties)
/** Pretty print XML string */
static String prettyPrint(String xml)
/** Escape XML text */
static String escapeXml(String text)
/** Escape XML attribute value */
static String escapeControlCharacters(String text)
}Usage Examples:
import groovy.xml.XmlUtil
import groovy.util.XmlParser
// Parse and serialize
def parser = new XmlParser()
def root = parser.parseText('<root><child>value</child></root>')
// Serialize node to string
def xmlString = XmlUtil.serialize(root)
println xmlString
// Pretty print XML
def prettyXml = XmlUtil.prettyPrint(xmlString)
println prettyXml
// Escape XML content
def userInput = "Data with <tags> & \"quotes\""
def safeXml = XmlUtil.escapeXml(userInput)
println safeXml // "Data with <tags> & "quotes""Support for XML namespaces in parsing and building.
/**
* Represents XML namespaces
*/
class Namespace {
/** Create namespace with URI */
Namespace(String uri)
/** Create namespace with URI and prefix */
Namespace(String uri, String prefix)
/** Get namespace URI */
String getUri()
/** Get namespace prefix */
String getPrefix()
/** Create qualified name */
QName getQName(String localName)
}
/**
* Builder supporting namespaces
*/
class NamespaceBuilder extends BuilderSupport {
/** Register namespace */
void registerNamespace(String prefix, String uri)
/** Set default namespace */
void setDefaultNamespace(String uri)
}Usage Examples:
import groovy.xml.Namespace
import groovy.xml.MarkupBuilder
// Working with namespaces in parsing
def nsXml = '''
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:auth="http://example.com/auth">
<soap:Header>
<auth:Authentication>
<auth:username>user123</auth:username>
</auth:Authentication>
</soap:Header>
<soap:Body>
<GetUserRequest>
<userId>12345</userId>
</GetUserRequest>
</soap:Body>
</soap:Envelope>
'''
def slurper = new XmlSlurper().parseText(nsXml)
def soapNS = new Namespace('http://schemas.xmlsoap.org/soap/envelope/', 'soap')
def authNS = new Namespace('http://example.com/auth', 'auth')
// Access namespaced elements
println slurper[soapNS.Header][authNS.Authentication][authNS.username].text()
// Building with namespaces
def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
def soap = new Namespace('http://schemas.xmlsoap.org/soap/envelope/', 'soap')
def auth = new Namespace('http://example.com/auth', 'auth')
builder."${soap.Envelope}"('xmlns:soap': soap.uri, 'xmlns:auth': auth.uri) {
"${soap.Header}" {
"${auth.Authentication}" {
"${auth.username}"('user123')
"${auth.token}"('abc123')
}
}
"${soap.Body}" {
GetUserRequest {
userId(12345)
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-apache-groovy--groovy