XML processing utilities for Apache Groovy including markup builders, parsers, and navigation tools
—
XML builders in Groovy XML provide various approaches to creating XML documents using Groovy's builder pattern. Each builder is optimized for different use cases, from formatted output to streaming generation.
Creates formatted XML markup with proper indentation and various formatting options.
public class MarkupBuilder extends BuilderSupport {
// Constructors
public MarkupBuilder();
public MarkupBuilder(PrintWriter pw);
public MarkupBuilder(Writer writer);
public MarkupBuilder(IndentPrinter out);
// Formatting options
public boolean getDoubleQuotes();
public void setDoubleQuotes(boolean useDoubleQuotes);
public boolean isOmitNullAttributes();
public void setOmitNullAttributes(boolean omitNullAttributes);
public boolean isOmitEmptyAttributes();
public void setOmitEmptyAttributes(boolean omitEmptyAttributes);
public boolean isExpandEmptyElements();
public void setExpandEmptyElements(boolean expandEmptyElements);
public boolean isEscapeAttributes();
public void setEscapeAttributes(boolean escapeAttributes);
// Helper access
public MarkupBuilderHelper getMkp();
}// Basic usage with default formatting
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.root {
person(id: '1', active: true) {
name('John Doe')
email('john@example.com')
tags {
tag('developer')
tag('groovy')
}
}
}
// With formatting options
def xml2 = new MarkupBuilder(writer)
xml2.setDoubleQuotes(true)
xml2.setOmitNullAttributes(true)
xml2.setExpandEmptyElements(false)
xml2.document {
metadata(version: '1.0', author: null) {
title('My Document')
description() // Will be <description/>
}
}
// Using mkp helper for special content
xml.root {
content {
mkp.yield('Some text content')
mkp.yieldUnescaped('<b>Bold text</b>')
mkp.comment('This is a comment')
}
}Efficient streaming XML generation without creating intermediate DOM structures, ideal for large documents.
class StreamingMarkupBuilder extends AbstractStreamingBuilder {
// Properties
boolean useDoubleQuotes
boolean expandEmptyElements
String encoding
// Methods
Writable bind(Closure closure)
Writable bindNode(Object node)
}def smb = new StreamingMarkupBuilder()
smb.encoding = 'UTF-8'
smb.useDoubleQuotes = true
def result = smb.bind {
root {
// Generate large amount of data efficiently
(1..1000).each { i ->
record(id: i) {
name("Record ${i}")
value(Math.random())
}
}
}
}
// result is a Writable that can be written to streams
def output = new FileWriter('large-file.xml')
result.writeTo(output)
output.close()
// Or convert to string
println result.toString()Creates W3C DOM documents that can be manipulated using standard DOM APIs.
public class DOMBuilder extends BuilderSupport {
// Static factory methods
public static DOMBuilder newInstance();
public static DOMBuilder newInstance(boolean validating, boolean namespaceAware);
public static Document parse(Reader reader) throws IOException, SAXException;
public static Document parse(Reader reader, boolean validating, boolean namespaceAware)
throws IOException, SAXException;
public static Document parse(Reader reader, boolean validating, boolean namespaceAware,
boolean allowDocTypeDeclaration) throws IOException, SAXException;
// Constructors
public DOMBuilder(Document document);
public DOMBuilder(DocumentBuilder documentBuilder);
// Parsing methods
public Document parseText(String text) throws SAXException, IOException;
}// Create DOM document using builder pattern
def builder = DOMBuilder.newInstance()
def doc = builder.root {
person(id: '1') {
name('John')
email('john@example.com')
}
}
// doc is now a standard W3C Document
assert doc instanceof Document
Element root = doc.documentElement
assert root.tagName == 'root'
// Parse existing XML into DOM
def xmlText = '<root><item>value</item></root>'
def parsedDoc = DOMBuilder.parse(new StringReader(xmlText))
// Can also parse with validation
def validatingDoc = DOMBuilder.parse(
new StringReader(xmlText),
true, // validating
true // namespace aware
)SAX-based XML building for event-driven XML generation.
public class SAXBuilder extends BuilderSupport {
public SAXBuilder(SAXResult saxResult);
}// Create SAX result target
def transformer = TransformerFactory.newInstance().newTransformer()
def result = new StreamResult(new StringWriter())
def saxResult = new SAXResult()
// Set up SAX content handler chain
def handler = new MyCustomContentHandler()
saxResult.setHandler(handler)
def saxBuilder = new SAXBuilder(saxResult)
saxBuilder.root {
item(id: '1') {
value('content')
}
}StAX-based XML processing for streaming XML with pull parsing integration.
class StaxBuilder extends BuilderSupport {
StaxBuilder(XMLStreamWriter xmlStreamWriter)
}def writer = new StringWriter()
def xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(writer)
def stax = new StaxBuilder(xmlWriter)
stax.root {
metadata(version: '1.0') {
title('Document')
}
content {
(1..100).each { i ->
item(id: i, "Item ${i}")
}
}
}
xmlWriter.close()
println writer.toString()Provides special methods for MarkupBuilder through the mkp property.
public class MarkupBuilderHelper {
// Content methods
public void yield(Object value);
public void yield(String value);
public void yieldUnescaped(Object value);
public void yieldUnescaped(String value);
// Special elements
public void comment(String value);
public void xmlDeclaration(Map<String, Object> args);
public void pi(Map<String, Map<String, Object>> args);
}def xml = new MarkupBuilder(writer)
xml.document {
mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8')
mkp.comment('Generated by Groovy XML')
root {
content {
mkp.yield('Plain text content')
mkp.yieldUnescaped('<em>Unescaped HTML</em>')
}
mkp.pi(target: [data: 'processing instruction'])
}
}All builders support various configuration options for customizing XML output:
// Common patterns for builder configuration
def builder = new MarkupBuilder(writer)
// Quote style
builder.doubleQuotes = true // Use double quotes for attributes
builder.doubleQuotes = false // Use single quotes (default)
// Attribute handling
builder.omitNullAttributes = true // Skip attributes with null values
builder.omitEmptyAttributes = true // Skip attributes with empty string values
builder.escapeAttributes = true // Escape special characters in attributes
// Element formatting
builder.expandEmptyElements = true // Use <tag></tag> instead of <tag/>
builder.expandEmptyElements = false // Use self-closing tags when possible
// For StreamingMarkupBuilder
def streamBuilder = new StreamingMarkupBuilder()
streamBuilder.encoding = 'UTF-8'
streamBuilder.useDoubleQuotes = true
streamBuilder.expandEmptyElements = falseUtility class for converting XML documents to equivalent Groovy builder code.
public class DomToGroovy {
// Static methods for converting DOM elements and documents
public static void print(PrintWriter out, Element element);
public static void print(PrintWriter out, Document document);
public static void print(PrintWriter out, GPathResult node);
public static void print(PrintWriter out, Node node);
}import org.codehaus.groovy.tools.xml.DomToGroovy
// Convert existing XML to Groovy builder code
def xmlString = '''<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<book id="1" category="fiction">
<title>The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<price currency="USD">12.99</price>
</book>
<book id="2" category="science">
<title>A Brief History of Time</title>
<author>Stephen Hawking</author>
<price currency="USD">15.99</price>
</book>
</catalog>'''
// Parse and convert to Groovy
def parser = new XmlParser()
def rootNode = parser.parseText(xmlString)
def groovyCode = new StringWriter()
DomToGroovy.print(new PrintWriter(groovyCode), rootNode)
println groovyCode.toString()
// Output will be equivalent Groovy builder code:
// catalog([:]) {
// book(['id':'1', 'category':'fiction']) {
// title(['The Great Gatsby'])
// author(['F. Scott Fitzgerald'])
// price(['currency':'USD'], ['12.99'])
// }
// book(['id':'2', 'category':'science']) {
// title(['A Brief History of Time'])
// author(['Stephen Hawking'])
// price(['currency':'USD'], ['15.99'])
// }
// }// Convert DOM document to Groovy
def domBuilder = DOMBuilder.newInstance()
def doc = domBuilder.parseText(xmlString)
def groovyOutput = new StringWriter()
DomToGroovy.print(new PrintWriter(groovyOutput), doc)
println groovyOutput.toString()
// Also works with DOM elements
def rootElement = doc.documentElement
def elementOutput = new StringWriter()
DomToGroovy.print(new PrintWriter(elementOutput), rootElement)
println elementOutput.toString()// Convert XmlSlurper results to Groovy
def slurper = new XmlSlurper()
def gpath = slurper.parseText(xmlString)
def gpathOutput = new StringWriter()
DomToGroovy.print(new PrintWriter(gpathOutput), gpath)
println gpathOutput.toString()def generateGroovyFromXml = { xmlFile, outputFile ->
// Parse the XML file
def parser = new XmlParser()
def xml = parser.parse(xmlFile)
// Generate Groovy builder code
def writer = new FileWriter(outputFile)
def printWriter = new PrintWriter(writer)
printWriter.println("// Generated Groovy XML builder code")
printWriter.println("// Source: ${xmlFile.name}")
printWriter.println()
printWriter.println("def xml = new MarkupBuilder()")
printWriter.print("xml.")
DomToGroovy.print(printWriter, xml)
printWriter.close()
writer.close()
}
// Usage
def xmlFile = new File('sample.xml')
def groovyFile = new File('generated-builder.groovy')
generateGroovyFromXml(xmlFile, groovyFile)// Create a complete conversion utility
class XmlToGroovyConverter {
static String convertXmlString(String xmlString) {
def parser = new XmlParser()
def node = parser.parseText(xmlString)
def writer = new StringWriter()
DomToGroovy.print(new PrintWriter(writer), node)
return writer.toString()
}
static void convertFile(File xmlFile, File groovyFile) {
def xmlString = xmlFile.text
def groovyCode = convertXmlString(xmlString)
groovyFile.withWriter { writer ->
writer.println("// Generated from ${xmlFile.name}")
writer.println("import groovy.xml.MarkupBuilder")
writer.println()
writer.println("def writer = new StringWriter()")
writer.println("def xml = new MarkupBuilder(writer)")
writer.print("xml.")
writer.println(groovyCode)
writer.println()
writer.println("println writer.toString()")
}
}
static void convertDirectory(File xmlDir, File outputDir) {
xmlDir.eachFileMatch(~/.*\.xml/) { xmlFile ->
def baseName = xmlFile.name.replaceAll(/\.xml$/, '')
def groovyFile = new File(outputDir, "${baseName}.groovy")
convertFile(xmlFile, groovyFile)
println "Converted ${xmlFile.name} -> ${groovyFile.name}"
}
}
}
// Usage examples
def xmlString = '<root><item id="1">value</item></root>'
def groovyCode = XmlToGroovyConverter.convertXmlString(xmlString)
println groovyCode
// Convert single file
XmlToGroovyConverter.convertFile(
new File('input.xml'),
new File('output.groovy')
)
// Convert entire directory
XmlToGroovyConverter.convertDirectory(
new File('xml-files/'),
new File('groovy-builders/')
)Install with Tessl CLI
npx tessl i tessl/maven-org-codehaus-groovy--groovy-xml