0
# XML Generation
1
2
Comprehensive XML building capabilities including markup builders for formatted output, DOM builders for W3C DOM integration, and streaming builders for memory-efficient large document generation.
3
4
## Capabilities
5
6
### MarkupBuilder
7
8
A powerful builder for creating XML and HTML markup with sophisticated formatting options and helper utilities. Extends Groovy's BuilderSupport to provide a DSL approach to XML generation.
9
10
```groovy { .api }
11
/**
12
* Default constructor writing to System.out
13
*/
14
MarkupBuilder()
15
16
/**
17
* Constructor with PrintWriter output
18
* @param pw - PrintWriter for output
19
*/
20
MarkupBuilder(PrintWriter pw)
21
22
/**
23
* Constructor with Writer output
24
* @param writer - Writer for output
25
*/
26
MarkupBuilder(Writer writer)
27
28
/**
29
* Constructor with IndentPrinter for formatted output
30
* @param out - IndentPrinter for formatted output
31
*/
32
MarkupBuilder(IndentPrinter out)
33
```
34
35
#### Configuration Methods
36
37
```groovy { .api }
38
/**
39
* Control quote style for attributes
40
* @param useDoubleQuotes - true for double quotes, false for single
41
*/
42
void setDoubleQuotes(boolean useDoubleQuotes)
43
boolean getDoubleQuotes()
44
45
/**
46
* Control handling of null attribute values
47
* @param omitNullAttributes - true to omit null valued attributes
48
*/
49
void setOmitNullAttributes(boolean omitNullAttributes)
50
boolean isOmitNullAttributes()
51
52
/**
53
* Control handling of empty attribute values
54
* @param omitEmptyAttributes - true to omit empty string attributes
55
*/
56
void setOmitEmptyAttributes(boolean omitEmptyAttributes)
57
boolean isOmitEmptyAttributes()
58
59
/**
60
* Control empty element formatting
61
* @param expandEmptyElements - true to expand empty elements with closing tags
62
*/
63
void setExpandEmptyElements(boolean expandEmptyElements)
64
boolean isExpandEmptyElements()
65
66
/**
67
* Control attribute value escaping
68
* @param escapeAttributes - true to escape attribute values
69
*/
70
void setEscapeAttributes(boolean escapeAttributes)
71
boolean isEscapeAttributes()
72
73
/**
74
* Get markup helper for advanced operations
75
* @return MarkupBuilderHelper instance
76
*/
77
MarkupBuilderHelper getMkp()
78
79
/**
80
* Set additional character filters for text content
81
* @param additionalFilters - List of character filter functions
82
*/
83
void setAdditionalFilters(List<Function<Character, Optional<String>>> additionalFilters)
84
85
/**
86
* Get additional character filters
87
* @return List of character filter functions
88
*/
89
List<Function<Character, Optional<String>>> getAdditionalFilters()
90
91
/**
92
* Get the underlying printer used for output
93
* @return IndentPrinter instance
94
*/
95
IndentPrinter getPrinter()
96
```
97
98
#### Character Filter Enum
99
100
```groovy { .api }
101
/**
102
* Character filtering options for MarkupBuilder
103
*/
104
enum CharFilter {
105
/** Strict XML character filtering */
106
XML_STRICT,
107
/** Filter all XML-related characters */
108
XML_ALL,
109
/** No character filtering */
110
NONE
111
}
112
```
113
114
**Usage Examples:**
115
116
```groovy
117
import groovy.xml.MarkupBuilder
118
119
// Basic XML generation
120
def writer = new StringWriter()
121
def xml = new MarkupBuilder(writer)
122
123
xml.books {
124
book(id: "1", title: "Groovy in Action") {
125
author("Dierk König")
126
price("49.99")
127
description {
128
mkp.yield("Comprehensive guide to ")
129
mkp.yieldUnescaped("<em>Groovy</em>")
130
mkp.yield(" programming")
131
}
132
}
133
book(id: "2", title: "Programming Groovy") {
134
author("Venkat Subramaniam")
135
price("45.99")
136
}
137
}
138
139
println writer.toString()
140
141
// Configuration example
142
def configuredXml = new MarkupBuilder(new StringWriter())
143
configuredXml.setDoubleQuotes(true)
144
configuredXml.setExpandEmptyElements(true)
145
configuredXml.setOmitNullAttributes(true)
146
147
configuredXml.catalog {
148
item(id: "123", category: null, title: "Sample") // category omitted
149
emptyItem() // Expanded as <emptyItem></emptyItem>
150
}
151
152
// Namespace example
153
xml.html("xmlns": "http://www.w3.org/1999/xhtml") {
154
head {
155
title("Sample Page")
156
}
157
body {
158
h1("Welcome")
159
p("This is a sample XHTML document")
160
}
161
}
162
```
163
164
---
165
166
### MarkupBuilderHelper
167
168
Helper class providing advanced markup operations including raw content insertion, comments, and XML declarations.
169
170
```groovy { .api }
171
/**
172
* Constructor (typically accessed via MarkupBuilder.getMkp())
173
* @param builder - Parent MarkupBuilder
174
*/
175
MarkupBuilderHelper(MarkupBuilder builder)
176
177
/**
178
* Yield escaped content
179
* @param value - Content to yield with escaping
180
*/
181
void yield(Object value)
182
void yield(String value)
183
184
/**
185
* Yield unescaped raw content
186
* @param value - Raw content to yield without escaping
187
*/
188
void yieldUnescaped(Object value)
189
void yieldUnescaped(String value)
190
191
/**
192
* Add XML comment
193
* @param value - Comment text
194
*/
195
void comment(String value)
196
197
/**
198
* Add XML declaration
199
* @param args - Declaration attributes (version, encoding, standalone)
200
*/
201
void xmlDeclaration(Map<String, Object> args)
202
203
/**
204
* Add processing instruction
205
* @param args - Map with PI target as key and attributes as value
206
*/
207
void pi(Map<String, Map<String, Object>> args)
208
```
209
210
**Usage Examples:**
211
212
```groovy
213
def writer = new StringWriter()
214
def xml = new MarkupBuilder(writer)
215
216
xml.document {
217
mkp.xmlDeclaration(version: "1.0", encoding: "UTF-8")
218
mkp.comment("Generated by Groovy XML")
219
220
root {
221
content {
222
mkp.yield("Safe content: ")
223
mkp.yield("<script>alert('safe')</script>") // Escaped
224
mkp.yieldUnescaped("<strong>Bold text</strong>") // Raw HTML
225
}
226
227
mkp.pi("xml-stylesheet": [type: "text/xsl", href: "style.xsl"])
228
}
229
}
230
```
231
232
---
233
234
### DOMBuilder
235
236
Builder for creating W3C DOM Document objects, providing integration with standard Java XML DOM APIs.
237
238
```groovy { .api }
239
/**
240
* Constructor with existing Document
241
* @param document - DOM Document to build upon
242
*/
243
DOMBuilder(Document document)
244
245
/**
246
* Constructor with DocumentBuilder
247
* @param documentBuilder - DocumentBuilder for document creation
248
*/
249
DOMBuilder(DocumentBuilder documentBuilder)
250
251
/**
252
* Create new DOMBuilder instance with default settings
253
* @return New DOMBuilder instance
254
*/
255
static DOMBuilder newInstance()
256
257
/**
258
* Create DOMBuilder with validation and namespace control
259
* @param validating - Enable DTD validation
260
* @param namespaceAware - Enable namespace processing
261
* @return New DOMBuilder instance
262
*/
263
static DOMBuilder newInstance(boolean validating, boolean namespaceAware)
264
265
/**
266
* Parse XML text into DOM Document
267
* @param text - XML text to parse
268
* @return DOM Document
269
*/
270
Document parseText(String text)
271
```
272
273
#### Static Parse Methods
274
275
```groovy { .api }
276
/**
277
* Parse XML from Reader into DOM Document
278
* @param reader - Reader containing XML
279
* @return DOM Document
280
*/
281
static Document parse(Reader reader)
282
283
/**
284
* Parse with validation and namespace control
285
* @param reader - Reader containing XML
286
* @param validating - Enable DTD validation
287
* @param namespaceAware - Enable namespace processing
288
* @return DOM Document
289
*/
290
static Document parse(Reader reader, boolean validating, boolean namespaceAware)
291
292
/**
293
* Parse with full control over processing
294
* @param reader - Reader containing XML
295
* @param validating - Enable DTD validation
296
* @param namespaceAware - Enable namespace processing
297
* @param allowDocTypeDeclaration - Allow DOCTYPE declarations
298
* @return DOM Document
299
*/
300
static Document parse(Reader reader, boolean validating, boolean namespaceAware, boolean allowDocTypeDeclaration)
301
```
302
303
**Usage Examples:**
304
305
```groovy
306
import groovy.xml.DOMBuilder
307
import org.w3c.dom.Document
308
309
// Create DOM using builder DSL
310
def builder = DOMBuilder.newInstance()
311
Document doc = builder.books {
312
book(id: "1") {
313
title("Groovy Programming")
314
author("John Doe")
315
}
316
book(id: "2") {
317
title("XML Processing")
318
author("Jane Smith")
319
}
320
}
321
322
// Access DOM elements
323
println doc.documentElement.tagName // "books"
324
def books = doc.getElementsByTagName("book")
325
println books.length // 2
326
327
// Parse existing XML into DOM
328
def xmlText = '<catalog><item>Sample</item></catalog>'
329
Document parsedDoc = builder.parseText(xmlText)
330
331
// Static parsing
332
Document staticDoc = DOMBuilder.parse(new StringReader(xmlText))
333
334
// Namespace-aware DOM building
335
def nsBuilder = DOMBuilder.newInstance(false, true)
336
Document nsDoc = nsBuilder.catalog("xmlns:lib": "http://library.org") {
337
"lib:book"(isbn: "123") {
338
"lib:title"("Advanced XML")
339
}
340
}
341
```
342
343
---
344
345
### StreamingMarkupBuilder
346
347
Memory-efficient builder for generating large XML documents using streaming output. Ideal for generating XML that doesn't fit in memory or when processing large datasets.
348
349
```groovy { .api }
350
/**
351
* Default constructor
352
*/
353
StreamingMarkupBuilder()
354
355
/**
356
* Bind closure to create streamable markup
357
* @param closure - Closure defining markup structure
358
* @return Writable object for streaming output
359
*/
360
def bind(Closure closure)
361
362
/**
363
* Bind Node object to create streamable markup
364
* @param node - Node to convert to streaming markup
365
* @return Writable object for streaming output
366
*/
367
def bindNode(Node node)
368
```
369
370
#### Configuration Properties
371
372
```groovy { .api }
373
/**
374
* Control quote style (default: false for single quotes)
375
*/
376
boolean useDoubleQuotes
377
378
/**
379
* Control empty element expansion (default: false)
380
*/
381
boolean expandEmptyElements
382
383
/**
384
* Set output encoding (default: null for platform default)
385
*/
386
def encoding
387
```
388
389
**Usage Examples:**
390
391
```groovy
392
import groovy.xml.StreamingMarkupBuilder
393
394
// Basic streaming markup
395
def builder = new StreamingMarkupBuilder()
396
def markup = builder.bind {
397
catalog {
398
(1..1000).each { i ->
399
book(id: i) {
400
title("Book ${i}")
401
price(Math.random() * 100)
402
}
403
}
404
}
405
}
406
407
// Write to file efficiently
408
new File("large-catalog.xml").withWriter { writer ->
409
markup.writeTo(writer)
410
}
411
412
// Configuration
413
builder.useDoubleQuotes = true
414
builder.expandEmptyElements = true
415
builder.encoding = "UTF-8"
416
417
// Streaming with XML declaration
418
def markupWithDecl = builder.bind {
419
mkp.xmlDeclaration(version: "1.0", encoding: "UTF-8")
420
mkp.comment("Generated streaming XML")
421
422
data {
423
records {
424
(1..10000).each { i ->
425
record(id: i, timestamp: new Date()) {
426
value(Math.random())
427
}
428
}
429
}
430
}
431
}
432
433
// Stream to OutputStream
434
new FileOutputStream("data.xml").withStream { stream ->
435
markupWithDecl.writeTo(new OutputStreamWriter(stream, "UTF-8"))
436
}
437
438
// Convert existing Node to streaming
439
def parser = new XmlParser()
440
def existingNode = parser.parseText('<sample><item>test</item></sample>')
441
def streamableNode = builder.bindNode(existingNode)
442
println streamableNode.toString()
443
```
444
445
---
446
447
### Additional Builders
448
449
#### StaxBuilder
450
451
```groovy { .api }
452
/**
453
* Builder using StAX XMLStreamWriter
454
* @param xmlStreamWriter - StAX XMLStreamWriter for output
455
*/
456
StaxBuilder(XMLStreamWriter xmlStreamWriter)
457
```
458
459
#### SAXBuilder
460
461
```groovy { .api }
462
/**
463
* Builder generating SAX events
464
* @param handler - ContentHandler for SAX events
465
*/
466
SAXBuilder(ContentHandler handler)
467
```
468
469
#### StreamingDOMBuilder and StreamingSAXBuilder
470
471
```groovy { .api }
472
// Streaming builders extending AbstractStreamingBuilder
473
class StreamingDOMBuilder extends AbstractStreamingBuilder
474
class StreamingSAXBuilder extends AbstractStreamingBuilder
475
```
476
477
**Usage Examples:**
478
479
```groovy
480
import groovy.xml.*
481
import javax.xml.stream.XMLOutputFactory
482
import javax.xml.transform.stream.StreamResult
483
484
// StAX builder example
485
def outputFactory = XMLOutputFactory.newInstance()
486
def stringWriter = new StringWriter()
487
def streamWriter = outputFactory.createXMLStreamWriter(stringWriter)
488
489
def staxBuilder = new StaxBuilder(streamWriter)
490
staxBuilder.library {
491
book(title: "StAX Processing") {
492
author("XML Expert")
493
}
494
}
495
streamWriter.close()
496
println stringWriter.toString()
497
498
// SAX builder example
499
def handler = new DefaultHandler() {
500
void startElement(String uri, String localName, String qName, Attributes attributes) {
501
println "Start: $qName"
502
}
503
}
504
505
def saxBuilder = new SAXBuilder(handler)
506
saxBuilder.catalog {
507
item("Test Item")
508
}
509
```
510
511
---
512
513
### Entity
514
515
Provides comprehensive XML entity constants for use in XML generation, offering all standard HTML and XML entities as static final constants.
516
517
```groovy { .api }
518
/**
519
* Constructor with entity name
520
* @param name - Entity name as string
521
*/
522
Entity(String name)
523
524
/**
525
* Constructor with entity code
526
* @param code - Entity code as integer
527
*/
528
Entity(int code)
529
```
530
531
#### Standard Entity Constants
532
533
```groovy { .api }
534
// Common entities
535
static final Entity nbsp, iexcl, cent, pound, curren, yen, brvbar, sect, uml, copy
536
static final Entity ordf, laquo, not, shy, reg, macr, deg, plusmn, sup2, sup3
537
static final Entity acute, micro, para, middot, cedil, sup1, ordm, raquo
538
static final Entity frac14, frac12, frac34, iquest
539
540
// Latin characters (uppercase)
541
static final Entity Agrave, Aacute, Acirc, Atilde, Auml, Aring, AElig, Ccedil
542
static final Entity Egrave, Eacute, Ecirc, Euml, Igrave, Iacute, Icirc, Iuml
543
static final Entity ETH, Ntilde, Ograve, Oacute, Ocirc, Otilde, Ouml, times
544
static final Entity Oslash, Ugrave, Uacute, Ucirc, Uuml, Yacute, THORN
545
546
// Latin characters (lowercase)
547
static final Entity szlig, agrave, aacute, acirc, atilde, auml, aring, aelig, ccedil
548
static final Entity egrave, eacute, ecirc, euml, igrave, iacute, icirc, iuml
549
static final Entity eth, ntilde, ograve, oacute, ocirc, otilde, ouml, divide
550
static final Entity oslash, ugrave, uacute, ucirc, uuml, yacute, thorn, yuml
551
552
// Special characters
553
static final Entity lt, gt, amp, apos, quot, OElig, oelig, Scaron, scaron, Yuml
554
static final Entity circ, tilde, ensp, emsp, thinsp, zwnj, zwj, lrm, rlm
555
static final Entity ndash, mdash, lsquo, rsquo, sbquo, ldquo, rdquo, bdquo
556
static final Entity dagger, Dagger, permil, lsaquo, rsaquo, euro
557
```
558
559
**Usage Examples:**
560
561
```groovy
562
import groovy.xml.MarkupBuilder
563
import groovy.xml.Entity
564
565
// Using entities in markup generation
566
def writer = new StringWriter()
567
def xml = new MarkupBuilder(writer)
568
569
xml.document {
570
title("Price: ${Entity.pound}25.99") // Price: £25.99
571
content {
572
p("Copyright ${Entity.copy} 2023") // Copyright © 2023
573
p("Temperature: 25${Entity.deg}C") // Temperature: 25°C
574
quote("${Entity.ldquo}Hello World${Entity.rdquo}") // "Hello World"
575
}
576
math {
577
formula("x${Entity.sup2} + y${Entity.sup2} = z${Entity.sup2}") // x² + y² = z²
578
fraction("${Entity.frac12} + ${Entity.frac14} = ${Entity.frac34}") // ½ + ¼ = ¾
579
}
580
}
581
582
println writer.toString()
583
584
// Using entities for safe XML generation
585
xml.data {
586
comparison("5 ${Entity.lt} 10 ${Entity.amp} 10 ${Entity.gt} 5") // 5 < 10 & 10 > 5
587
quoted("He said ${Entity.quot}Hello${Entity.quot}") // He said "Hello"
588
}
589
590
// Custom entity usage
591
def customEntity = new Entity("custom")
592
def codeEntity = new Entity(8364) // Euro symbol by code
593
594
xml.custom {
595
field(customEntity.toString())
596
symbol(codeEntity.toString())
597
}
598
599
// Build method for integration with builders
600
customEntity.build(xml) // Integrates entity with builder
601
```
602
603
---
604
605
### Additional Builder Classes
606
607
#### SAXBuilder
608
609
Builder for generating SAX events directly, useful for integration with SAX-based processing chains.
610
611
```groovy { .api }
612
/**
613
* Constructor with ContentHandler for SAX events
614
* @param handler - ContentHandler to receive SAX events
615
*/
616
SAXBuilder(ContentHandler handler)
617
```
618
619
#### StaxBuilder
620
621
Builder using StAX XMLStreamWriter for efficient streaming XML generation.
622
623
```groovy { .api }
624
/**
625
* Constructor with XMLStreamWriter
626
* @param xmlStreamWriter - StAX XMLStreamWriter for output
627
*/
628
StaxBuilder(XMLStreamWriter xmlStreamWriter)
629
```
630
631
#### StreamingDOMBuilder and StreamingSAXBuilder
632
633
Advanced streaming builders extending AbstractStreamingBuilder for specialized streaming scenarios.
634
635
```groovy { .api }
636
/**
637
* Streaming DOM builder for large document generation
638
*/
639
class StreamingDOMBuilder extends AbstractStreamingBuilder
640
641
/**
642
* Streaming SAX builder for event-based generation
643
*/
644
class StreamingSAXBuilder extends AbstractStreamingBuilder
645
```
646
647
**Usage Examples:**
648
649
```groovy
650
import groovy.xml.*
651
import javax.xml.stream.XMLOutputFactory
652
import javax.xml.transform.sax.SAXResult
653
import org.xml.sax.helpers.DefaultHandler
654
655
// StAX builder example
656
def outputFactory = XMLOutputFactory.newInstance()
657
def stringWriter = new StringWriter()
658
def streamWriter = outputFactory.createXMLStreamWriter(stringWriter)
659
660
def staxBuilder = new StaxBuilder(streamWriter)
661
staxBuilder.library {
662
book(title: "StAX Processing") {
663
author("XML Expert")
664
chapters {
665
chapter(number: "1", "Introduction to StAX")
666
chapter(number: "2", "Advanced StAX Features")
667
}
668
}
669
}
670
streamWriter.close()
671
println stringWriter.toString()
672
673
// SAX builder example
674
def handler = new DefaultHandler() {
675
void startElement(String uri, String localName, String qName, Attributes attributes) {
676
println "Start element: $qName"
677
if (attributes.length > 0) {
678
for (int i = 0; i < attributes.length; i++) {
679
println " Attribute: ${attributes.getQName(i)} = ${attributes.getValue(i)}"
680
}
681
}
682
}
683
684
void endElement(String uri, String localName, String qName) {
685
println "End element: $qName"
686
}
687
688
void characters(char[] ch, int start, int length) {
689
def text = new String(ch, start, length).trim()
690
if (text) {
691
println "Text content: $text"
692
}
693
}
694
}
695
696
def saxBuilder = new SAXBuilder(handler)
697
saxBuilder.catalog {
698
item(id: "1", "First Item")
699
item(id: "2", "Second Item")
700
}
701
```