0
# XML Builders
1
2
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.
3
4
## MarkupBuilder
5
6
Creates formatted XML markup with proper indentation and various formatting options.
7
8
```java { .api }
9
public class MarkupBuilder extends BuilderSupport {
10
// Constructors
11
public MarkupBuilder();
12
public MarkupBuilder(PrintWriter pw);
13
public MarkupBuilder(Writer writer);
14
public MarkupBuilder(IndentPrinter out);
15
16
// Formatting options
17
public boolean getDoubleQuotes();
18
public void setDoubleQuotes(boolean useDoubleQuotes);
19
public boolean isOmitNullAttributes();
20
public void setOmitNullAttributes(boolean omitNullAttributes);
21
public boolean isOmitEmptyAttributes();
22
public void setOmitEmptyAttributes(boolean omitEmptyAttributes);
23
public boolean isExpandEmptyElements();
24
public void setExpandEmptyElements(boolean expandEmptyElements);
25
public boolean isEscapeAttributes();
26
public void setEscapeAttributes(boolean escapeAttributes);
27
28
// Helper access
29
public MarkupBuilderHelper getMkp();
30
}
31
```
32
33
### MarkupBuilder Usage
34
35
```groovy
36
// Basic usage with default formatting
37
def writer = new StringWriter()
38
def xml = new MarkupBuilder(writer)
39
xml.root {
40
person(id: '1', active: true) {
41
name('John Doe')
42
email('john@example.com')
43
tags {
44
tag('developer')
45
tag('groovy')
46
}
47
}
48
}
49
50
// With formatting options
51
def xml2 = new MarkupBuilder(writer)
52
xml2.setDoubleQuotes(true)
53
xml2.setOmitNullAttributes(true)
54
xml2.setExpandEmptyElements(false)
55
56
xml2.document {
57
metadata(version: '1.0', author: null) {
58
title('My Document')
59
description() // Will be <description/>
60
}
61
}
62
63
// Using mkp helper for special content
64
xml.root {
65
content {
66
mkp.yield('Some text content')
67
mkp.yieldUnescaped('<b>Bold text</b>')
68
mkp.comment('This is a comment')
69
}
70
}
71
```
72
73
## StreamingMarkupBuilder
74
75
Efficient streaming XML generation without creating intermediate DOM structures, ideal for large documents.
76
77
```groovy { .api }
78
class StreamingMarkupBuilder extends AbstractStreamingBuilder {
79
// Properties
80
boolean useDoubleQuotes
81
boolean expandEmptyElements
82
String encoding
83
84
// Methods
85
Writable bind(Closure closure)
86
Writable bindNode(Object node)
87
}
88
```
89
90
### StreamingMarkupBuilder Usage
91
92
```groovy
93
def smb = new StreamingMarkupBuilder()
94
smb.encoding = 'UTF-8'
95
smb.useDoubleQuotes = true
96
97
def result = smb.bind {
98
root {
99
// Generate large amount of data efficiently
100
(1..1000).each { i ->
101
record(id: i) {
102
name("Record ${i}")
103
value(Math.random())
104
}
105
}
106
}
107
}
108
109
// result is a Writable that can be written to streams
110
def output = new FileWriter('large-file.xml')
111
result.writeTo(output)
112
output.close()
113
114
// Or convert to string
115
println result.toString()
116
```
117
118
## DOMBuilder
119
120
Creates W3C DOM documents that can be manipulated using standard DOM APIs.
121
122
```java { .api }
123
public class DOMBuilder extends BuilderSupport {
124
// Static factory methods
125
public static DOMBuilder newInstance();
126
public static DOMBuilder newInstance(boolean validating, boolean namespaceAware);
127
public static Document parse(Reader reader) throws IOException, SAXException;
128
public static Document parse(Reader reader, boolean validating, boolean namespaceAware)
129
throws IOException, SAXException;
130
public static Document parse(Reader reader, boolean validating, boolean namespaceAware,
131
boolean allowDocTypeDeclaration) throws IOException, SAXException;
132
133
// Constructors
134
public DOMBuilder(Document document);
135
public DOMBuilder(DocumentBuilder documentBuilder);
136
137
// Parsing methods
138
public Document parseText(String text) throws SAXException, IOException;
139
}
140
```
141
142
### DOMBuilder Usage
143
144
```groovy
145
// Create DOM document using builder pattern
146
def builder = DOMBuilder.newInstance()
147
def doc = builder.root {
148
person(id: '1') {
149
name('John')
150
email('john@example.com')
151
}
152
}
153
154
// doc is now a standard W3C Document
155
assert doc instanceof Document
156
Element root = doc.documentElement
157
assert root.tagName == 'root'
158
159
// Parse existing XML into DOM
160
def xmlText = '<root><item>value</item></root>'
161
def parsedDoc = DOMBuilder.parse(new StringReader(xmlText))
162
163
// Can also parse with validation
164
def validatingDoc = DOMBuilder.parse(
165
new StringReader(xmlText),
166
true, // validating
167
true // namespace aware
168
)
169
```
170
171
## SAXBuilder
172
173
SAX-based XML building for event-driven XML generation.
174
175
```java { .api }
176
public class SAXBuilder extends BuilderSupport {
177
public SAXBuilder(SAXResult saxResult);
178
}
179
```
180
181
### SAXBuilder Usage
182
183
```groovy
184
// Create SAX result target
185
def transformer = TransformerFactory.newInstance().newTransformer()
186
def result = new StreamResult(new StringWriter())
187
def saxResult = new SAXResult()
188
189
// Set up SAX content handler chain
190
def handler = new MyCustomContentHandler()
191
saxResult.setHandler(handler)
192
193
def saxBuilder = new SAXBuilder(saxResult)
194
saxBuilder.root {
195
item(id: '1') {
196
value('content')
197
}
198
}
199
```
200
201
## StaxBuilder
202
203
StAX-based XML processing for streaming XML with pull parsing integration.
204
205
```groovy { .api }
206
class StaxBuilder extends BuilderSupport {
207
StaxBuilder(XMLStreamWriter xmlStreamWriter)
208
}
209
```
210
211
### StaxBuilder Usage
212
213
```groovy
214
def writer = new StringWriter()
215
def xmlWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(writer)
216
217
def stax = new StaxBuilder(xmlWriter)
218
stax.root {
219
metadata(version: '1.0') {
220
title('Document')
221
}
222
content {
223
(1..100).each { i ->
224
item(id: i, "Item ${i}")
225
}
226
}
227
}
228
229
xmlWriter.close()
230
println writer.toString()
231
```
232
233
## MarkupBuilderHelper
234
235
Provides special methods for MarkupBuilder through the `mkp` property.
236
237
```java { .api }
238
public class MarkupBuilderHelper {
239
// Content methods
240
public void yield(Object value);
241
public void yield(String value);
242
public void yieldUnescaped(Object value);
243
public void yieldUnescaped(String value);
244
245
// Special elements
246
public void comment(String value);
247
public void xmlDeclaration(Map<String, Object> args);
248
public void pi(Map<String, Map<String, Object>> args);
249
}
250
```
251
252
### MarkupBuilderHelper Usage
253
254
```groovy
255
def xml = new MarkupBuilder(writer)
256
xml.document {
257
mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8')
258
mkp.comment('Generated by Groovy XML')
259
260
root {
261
content {
262
mkp.yield('Plain text content')
263
mkp.yieldUnescaped('<em>Unescaped HTML</em>')
264
}
265
266
mkp.pi(target: [data: 'processing instruction'])
267
}
268
}
269
```
270
271
## Builder Configuration
272
273
All builders support various configuration options for customizing XML output:
274
275
```groovy
276
// Common patterns for builder configuration
277
def builder = new MarkupBuilder(writer)
278
279
// Quote style
280
builder.doubleQuotes = true // Use double quotes for attributes
281
builder.doubleQuotes = false // Use single quotes (default)
282
283
// Attribute handling
284
builder.omitNullAttributes = true // Skip attributes with null values
285
builder.omitEmptyAttributes = true // Skip attributes with empty string values
286
builder.escapeAttributes = true // Escape special characters in attributes
287
288
// Element formatting
289
builder.expandEmptyElements = true // Use <tag></tag> instead of <tag/>
290
builder.expandEmptyElements = false // Use self-closing tags when possible
291
292
// For StreamingMarkupBuilder
293
def streamBuilder = new StreamingMarkupBuilder()
294
streamBuilder.encoding = 'UTF-8'
295
streamBuilder.useDoubleQuotes = true
296
streamBuilder.expandEmptyElements = false
297
```
298
299
## DomToGroovy
300
301
Utility class for converting XML documents to equivalent Groovy builder code.
302
303
```java { .api }
304
public class DomToGroovy {
305
// Static methods for converting DOM elements and documents
306
public static void print(PrintWriter out, Element element);
307
public static void print(PrintWriter out, Document document);
308
public static void print(PrintWriter out, GPathResult node);
309
public static void print(PrintWriter out, Node node);
310
}
311
```
312
313
### DomToGroovy Usage
314
315
```groovy
316
import org.codehaus.groovy.tools.xml.DomToGroovy
317
318
// Convert existing XML to Groovy builder code
319
def xmlString = '''<?xml version="1.0" encoding="UTF-8"?>
320
<catalog>
321
<book id="1" category="fiction">
322
<title>The Great Gatsby</title>
323
<author>F. Scott Fitzgerald</author>
324
<price currency="USD">12.99</price>
325
</book>
326
<book id="2" category="science">
327
<title>A Brief History of Time</title>
328
<author>Stephen Hawking</author>
329
<price currency="USD">15.99</price>
330
</book>
331
</catalog>'''
332
333
// Parse and convert to Groovy
334
def parser = new XmlParser()
335
def rootNode = parser.parseText(xmlString)
336
337
def groovyCode = new StringWriter()
338
DomToGroovy.print(new PrintWriter(groovyCode), rootNode)
339
println groovyCode.toString()
340
341
// Output will be equivalent Groovy builder code:
342
// catalog([:]) {
343
// book(['id':'1', 'category':'fiction']) {
344
// title(['The Great Gatsby'])
345
// author(['F. Scott Fitzgerald'])
346
// price(['currency':'USD'], ['12.99'])
347
// }
348
// book(['id':'2', 'category':'science']) {
349
// title(['A Brief History of Time'])
350
// author(['Stephen Hawking'])
351
// price(['currency':'USD'], ['15.99'])
352
// }
353
// }
354
```
355
356
### Converting DOM Documents
357
358
```groovy
359
// Convert DOM document to Groovy
360
def domBuilder = DOMBuilder.newInstance()
361
def doc = domBuilder.parseText(xmlString)
362
363
def groovyOutput = new StringWriter()
364
DomToGroovy.print(new PrintWriter(groovyOutput), doc)
365
println groovyOutput.toString()
366
367
// Also works with DOM elements
368
def rootElement = doc.documentElement
369
def elementOutput = new StringWriter()
370
DomToGroovy.print(new PrintWriter(elementOutput), rootElement)
371
println elementOutput.toString()
372
```
373
374
### Converting GPathResult
375
376
```groovy
377
// Convert XmlSlurper results to Groovy
378
def slurper = new XmlSlurper()
379
def gpath = slurper.parseText(xmlString)
380
381
def gpathOutput = new StringWriter()
382
DomToGroovy.print(new PrintWriter(gpathOutput), gpath)
383
println gpathOutput.toString()
384
```
385
386
### Automated Code Generation Workflow
387
388
```groovy
389
def generateGroovyFromXml = { xmlFile, outputFile ->
390
// Parse the XML file
391
def parser = new XmlParser()
392
def xml = parser.parse(xmlFile)
393
394
// Generate Groovy builder code
395
def writer = new FileWriter(outputFile)
396
def printWriter = new PrintWriter(writer)
397
398
printWriter.println("// Generated Groovy XML builder code")
399
printWriter.println("// Source: ${xmlFile.name}")
400
printWriter.println()
401
printWriter.println("def xml = new MarkupBuilder()")
402
printWriter.print("xml.")
403
404
DomToGroovy.print(printWriter, xml)
405
406
printWriter.close()
407
writer.close()
408
}
409
410
// Usage
411
def xmlFile = new File('sample.xml')
412
def groovyFile = new File('generated-builder.groovy')
413
generateGroovyFromXml(xmlFile, groovyFile)
414
```
415
416
### Integration with Other Tools
417
418
```groovy
419
// Create a complete conversion utility
420
class XmlToGroovyConverter {
421
422
static String convertXmlString(String xmlString) {
423
def parser = new XmlParser()
424
def node = parser.parseText(xmlString)
425
426
def writer = new StringWriter()
427
DomToGroovy.print(new PrintWriter(writer), node)
428
return writer.toString()
429
}
430
431
static void convertFile(File xmlFile, File groovyFile) {
432
def xmlString = xmlFile.text
433
def groovyCode = convertXmlString(xmlString)
434
435
groovyFile.withWriter { writer ->
436
writer.println("// Generated from ${xmlFile.name}")
437
writer.println("import groovy.xml.MarkupBuilder")
438
writer.println()
439
writer.println("def writer = new StringWriter()")
440
writer.println("def xml = new MarkupBuilder(writer)")
441
writer.print("xml.")
442
writer.println(groovyCode)
443
writer.println()
444
writer.println("println writer.toString()")
445
}
446
}
447
448
static void convertDirectory(File xmlDir, File outputDir) {
449
xmlDir.eachFileMatch(~/.*\.xml/) { xmlFile ->
450
def baseName = xmlFile.name.replaceAll(/\.xml$/, '')
451
def groovyFile = new File(outputDir, "${baseName}.groovy")
452
convertFile(xmlFile, groovyFile)
453
println "Converted ${xmlFile.name} -> ${groovyFile.name}"
454
}
455
}
456
}
457
458
// Usage examples
459
def xmlString = '<root><item id="1">value</item></root>'
460
def groovyCode = XmlToGroovyConverter.convertXmlString(xmlString)
461
println groovyCode
462
463
// Convert single file
464
XmlToGroovyConverter.convertFile(
465
new File('input.xml'),
466
new File('output.groovy')
467
)
468
469
// Convert entire directory
470
XmlToGroovyConverter.convertDirectory(
471
new File('xml-files/'),
472
new File('groovy-builders/')
473
)
474
```