0
# XML Processing
1
2
Comprehensive XML parsing, navigation, and generation capabilities including both tree-based (XmlParser) and streaming (XmlSlurper) approaches with GPath expression support. These tools provide powerful XML manipulation and generation capabilities.
3
4
## Capabilities
5
6
### XML Parsing with XmlSlurper
7
8
Streaming XML parser that creates GPathResult objects for efficient navigation.
9
10
```java { .api }
11
class XmlSlurper {
12
/**
13
* Creates an XmlSlurper with default settings.
14
*/
15
XmlSlurper();
16
17
/**
18
* Creates an XmlSlurper with validation enabled/disabled.
19
*/
20
XmlSlurper(boolean validating);
21
22
/**
23
* Creates an XmlSlurper with validation and namespace awareness.
24
*/
25
XmlSlurper(boolean validating, boolean namespaceAware);
26
27
/**
28
* Creates an XmlSlurper with custom SAXParser.
29
*/
30
XmlSlurper(SAXParser parser);
31
32
/**
33
* Creates an XmlSlurper with custom XMLReader.
34
*/
35
XmlSlurper(XMLReader reader);
36
37
/**
38
* Parses XML from a string.
39
*/
40
GPathResult parseText(String text);
41
42
/**
43
* Parses XML from a file.
44
*/
45
GPathResult parse(File file);
46
47
/**
48
* Parses XML from a URL.
49
*/
50
GPathResult parse(URL url);
51
52
/**
53
* Parses XML from an InputStream.
54
*/
55
GPathResult parse(InputStream input);
56
57
/**
58
* Parses XML from a Reader.
59
*/
60
GPathResult parse(Reader reader);
61
62
/**
63
* Sets the XML parser to use.
64
*/
65
void setXMLReader(XMLReader reader);
66
67
/**
68
* Gets the XML parser being used.
69
*/
70
XMLReader getXMLReader();
71
72
/**
73
* Sets an entity resolver.
74
*/
75
void setEntityResolver(EntityResolver resolver);
76
77
/**
78
* Sets an error handler.
79
*/
80
void setErrorHandler(ErrorHandler handler);
81
82
/**
83
* Sets a DTD handler.
84
*/
85
void setDTDHandler(DTDHandler handler);
86
87
/**
88
* Sets whether to keep ignorable whitespace.
89
*/
90
void setKeepIgnorableWhitespace(boolean keepIgnorableWhitespace);
91
}
92
```
93
94
### GPath Navigation
95
96
GPathResult provides powerful XML navigation using GPath expressions.
97
98
```java { .api }
99
abstract class GPathResult implements Iterable<GPathResult>, Writable {
100
/**
101
* Gets the text content of this node.
102
*/
103
String text();
104
105
/**
106
* Gets the number of child nodes.
107
*/
108
int size();
109
110
/**
111
* Checks if this result is empty.
112
*/
113
boolean isEmpty();
114
115
/**
116
* Gets all child nodes.
117
*/
118
GPathResult children();
119
120
/**
121
* Gets the parent node.
122
*/
123
GPathResult parent();
124
125
/**
126
* Finds child nodes matching the closure condition.
127
*/
128
GPathResult find(Closure closure);
129
130
/**
131
* Finds all child nodes matching the closure condition.
132
*/
133
GPathResult findAll(Closure closure);
134
135
/**
136
* Collects values from child nodes using a closure.
137
*/
138
List<Object> collect(Closure closure);
139
140
/**
141
* Iterates over child nodes.
142
*/
143
GPathResult each(Closure closure);
144
145
/**
146
* Gets an attribute value.
147
*/
148
String attribute(String name);
149
150
/**
151
* Gets all attributes.
152
*/
153
Map<String, String> attributes();
154
155
/**
156
* Gets the local name of this node.
157
*/
158
String name();
159
160
/**
161
* Gets the namespace URI of this node.
162
*/
163
String namespaceURI();
164
165
/**
166
* Converts to a Node object.
167
*/
168
Node convertToNode();
169
170
/**
171
* Gets child by index.
172
*/
173
GPathResult getAt(int index);
174
175
/**
176
* Gets child by name.
177
*/
178
GPathResult getProperty(String name);
179
180
/**
181
* Sets a property value (for XML generation).
182
*/
183
void setProperty(String name, Object value);
184
185
/**
186
* Writes the XML representation to a Writer.
187
*/
188
Writer writeTo(Writer writer);
189
190
/**
191
* Returns an Iterator over child nodes.
192
*/
193
Iterator<GPathResult> iterator();
194
195
/**
196
* Returns a ListIterator over child nodes.
197
*/
198
ListIterator<GPathResult> listIterator();
199
200
/**
201
* Applies a closure to each child node and returns results.
202
*/
203
List<Object> list();
204
205
/**
206
* Gets the depth-first iterator.
207
*/
208
Iterator<GPathResult> depthFirst();
209
210
/**
211
* Gets the breadth-first iterator.
212
*/
213
Iterator<GPathResult> breadthFirst();
214
}
215
```
216
217
### Tree-based XML Parsing
218
219
XmlParser creates Node trees for XML processing with full DOM-like access.
220
221
```java { .api }
222
class XmlParser {
223
/**
224
* Creates an XmlParser with default settings.
225
*/
226
XmlParser();
227
228
/**
229
* Creates an XmlParser with validation enabled/disabled.
230
*/
231
XmlParser(boolean validating);
232
233
/**
234
* Creates an XmlParser with validation and namespace awareness.
235
*/
236
XmlParser(boolean validating, boolean namespaceAware);
237
238
/**
239
* Creates an XmlParser with custom SAXParser.
240
*/
241
XmlParser(SAXParser parser);
242
243
/**
244
* Creates an XmlParser with custom XMLReader.
245
*/
246
XmlParser(XMLReader reader);
247
248
/**
249
* Parses XML from a string.
250
*/
251
Node parseText(String text);
252
253
/**
254
* Parses XML from a file.
255
*/
256
Node parse(File file);
257
258
/**
259
* Parses XML from a URL.
260
*/
261
Node parse(URL url);
262
263
/**
264
* Parses XML from an InputStream.
265
*/
266
Node parse(InputStream input);
267
268
/**
269
* Parses XML from a Reader.
270
*/
271
Node parse(Reader reader);
272
273
/**
274
* Sets trimming of whitespace-only text nodes.
275
*/
276
void setTrimWhitespace(boolean trimWhitespace);
277
278
/**
279
* Gets whether whitespace-only text nodes are trimmed.
280
*/
281
boolean isTrimWhitespace();
282
283
/**
284
* Sets whether to keep ignorable whitespace.
285
*/
286
void setKeepIgnorableWhitespace(boolean keepIgnorableWhitespace);
287
288
/**
289
* Sets an entity resolver.
290
*/
291
void setEntityResolver(EntityResolver resolver);
292
293
/**
294
* Sets an error handler.
295
*/
296
void setErrorHandler(ErrorHandler handler);
297
298
/**
299
* Sets a DTD handler.
300
*/
301
void setDTDHandler(DTDHandler handler);
302
}
303
```
304
305
### XML Generation with MarkupBuilder
306
307
Builder for creating XML/HTML markup programmatically.
308
309
```java { .api }
310
class MarkupBuilder extends BuilderSupport {
311
/**
312
* Creates a MarkupBuilder that writes to a Writer.
313
*/
314
MarkupBuilder(Writer writer);
315
316
/**
317
* Creates a MarkupBuilder that writes to a PrintWriter.
318
*/
319
MarkupBuilder(PrintWriter writer);
320
321
/**
322
* Creates a MarkupBuilder with indenting.
323
*/
324
MarkupBuilder(IndentPrinter printer);
325
326
/**
327
* Gets whether to escape attributes.
328
*/
329
boolean getEscapeAttributes();
330
331
/**
332
* Sets whether to escape attributes.
333
*/
334
void setEscapeAttributes(boolean escapeAttributes);
335
336
/**
337
* Gets whether the output should be omitted.
338
*/
339
boolean isOmitEmptyAttributes();
340
341
/**
342
* Sets whether empty attributes should be omitted.
343
*/
344
void setOmitEmptyAttributes(boolean omitEmptyAttributes);
345
346
/**
347
* Gets whether null attributes should be omitted.
348
*/
349
boolean isOmitNullAttributes();
350
351
/**
352
* Sets whether null attributes should be omitted.
353
*/
354
void setOmitNullAttributes(boolean omitNullAttributes);
355
356
/**
357
* Creates a processing instruction.
358
*/
359
void processingInstruction(Map<String, Object> attributes);
360
361
/**
362
* Creates a comment.
363
*/
364
void comment(String comment);
365
366
/**
367
* Creates CDATA section.
368
*/
369
void cdata(String content);
370
371
/**
372
* Yields to allow mixed content.
373
*/
374
void yield(String value);
375
376
/**
377
* Yields to allow mixed content with escaping control.
378
*/
379
void yield(String value, boolean escapeXml);
380
381
/**
382
* Yields unescaped content.
383
*/
384
void yieldUnescaped(String value);
385
}
386
```
387
388
### Streaming XML Generation
389
390
StreamingMarkupBuilder for efficient generation of large XML documents.
391
392
```java { .api }
393
class StreamingMarkupBuilder {
394
/**
395
* Creates a StreamingMarkupBuilder.
396
*/
397
StreamingMarkupBuilder();
398
399
/**
400
* Gets the encoding to use.
401
*/
402
String getEncoding();
403
404
/**
405
* Sets the encoding to use.
406
*/
407
void setEncoding(String encoding);
408
409
/**
410
* Gets whether to use double quotes for attributes.
411
*/
412
boolean getUseDoubleQuotes();
413
414
/**
415
* Sets whether to use double quotes for attributes.
416
*/
417
void setUseDoubleQuotes(boolean useDoubleQuotes);
418
419
/**
420
* Binds a closure to create a Writable.
421
*/
422
Writable bind(Closure closure);
423
424
/**
425
* Binds a closure with custom binding.
426
*/
427
Writable bind(Map binding, Closure closure);
428
}
429
```
430
431
### XML Namespace Support
432
433
Classes for handling XML namespaces.
434
435
```java { .api }
436
class Namespace {
437
/**
438
* Creates a namespace with URI.
439
*/
440
Namespace(String uri);
441
442
/**
443
* Creates a namespace with URI and prefix.
444
*/
445
Namespace(String uri, String prefix);
446
447
/**
448
* Gets the namespace URI.
449
*/
450
String getUri();
451
452
/**
453
* Gets the namespace prefix.
454
*/
455
String getPrefix();
456
457
/**
458
* Creates a QName in this namespace.
459
*/
460
QName getName(String localName);
461
}
462
463
class QName {
464
/**
465
* Creates a QName with local name only.
466
*/
467
QName(String localName);
468
469
/**
470
* Creates a QName with namespace URI and local name.
471
*/
472
QName(String namespaceURI, String localName);
473
474
/**
475
* Creates a QName with namespace URI, local name, and prefix.
476
*/
477
QName(String namespaceURI, String localName, String prefix);
478
479
/**
480
* Gets the namespace URI.
481
*/
482
String getNamespaceURI();
483
484
/**
485
* Gets the local part.
486
*/
487
String getLocalPart();
488
489
/**
490
* Gets the prefix.
491
*/
492
String getPrefix();
493
494
/**
495
* Gets the qualified name.
496
*/
497
String getQualifiedName();
498
499
/**
500
* Checks if this QName matches another.
501
*/
502
boolean matches(Object object);
503
}
504
```
505
506
## Usage Examples
507
508
### XML Parsing with XmlSlurper
509
510
```java
511
import groovy.util.XmlSlurper;
512
import groovy.util.slurpersupport.GPathResult;
513
514
// Parse XML document
515
XmlSlurper slurper = new XmlSlurper();
516
String xml = """
517
<catalog xmlns:book="http://example.com/books">
518
<book:book id="1" category="fiction">
519
<book:title>The Great Gatsby</book:title>
520
<book:author>F. Scott Fitzgerald</book:author>
521
<book:price>12.99</book:price>
522
<book:available>true</book:available>
523
</book:book>
524
<book:book id="2" category="non-fiction">
525
<book:title>Sapiens</book:title>
526
<book:author>Yuval Noah Harari</book:author>
527
<book:price>15.99</book:price>
528
<book:available>false</book:available>
529
</book:book>
530
</catalog>
531
""";
532
533
GPathResult catalog = slurper.parseText(xml);
534
535
// Navigate and extract data using GPath
536
System.out.println("Total books: " + catalog.book.size());
537
538
// Access specific elements
539
GPathResult firstBook = catalog.book[0];
540
System.out.println("First book title: " + firstBook.title.text());
541
System.out.println("First book ID: " + firstBook.attribute("id"));
542
543
// Find books using closures
544
GPathResult fictionBooks = catalog.book.findAll { book ->
545
book.attribute("category").equals("fiction");
546
});
547
548
System.out.println("Fiction books: " + fictionBooks.size());
549
550
// Collect specific data
551
List<String> titles = catalog.book.collect { book ->
552
return book.title.text();
553
};
554
555
System.out.println("All titles: " + titles);
556
557
// Navigate with namespaces
558
GPathResult availableBooks = catalog.book.findAll { book ->
559
book.available.text().equals("true");
560
});
561
562
for (GPathResult book : availableBooks) {
563
System.out.println("Available: " + book.title.text() + " - $" + book.price.text());
564
}
565
```
566
567
### XML Generation with MarkupBuilder
568
569
```java
570
import groovy.xml.MarkupBuilder;
571
import java.io.StringWriter;
572
573
// Create XML using MarkupBuilder
574
StringWriter writer = new StringWriter();
575
MarkupBuilder builder = new MarkupBuilder(writer);
576
577
// Generate XML structure
578
builder.catalog(xmlns: "http://example.com/books") {
579
book(id: "1", category: "fiction") {
580
title("The Great Gatsby");
581
author("F. Scott Fitzgerald");
582
price("12.99");
583
available("true");
584
}
585
book(id: "2", category: "non-fiction") {
586
title("Sapiens");
587
author("Yuval Noah Harari");
588
price("15.99");
589
available("false");
590
description {
591
yieldUnescaped("<![CDATA[A fascinating look at human history]]>");
592
}
593
}
594
}
595
596
String generatedXml = writer.toString();
597
System.out.println(generatedXml);
598
599
// Using programmatic approach
600
StringWriter writer2 = new StringWriter();
601
MarkupBuilder builder2 = new MarkupBuilder(writer2);
602
603
List<Map<String, Object>> books = Arrays.asList(
604
Map.of("id", "1", "title", "Book One", "author", "Author One"),
605
Map.of("id", "2", "title", "Book Two", "author", "Author Two")
606
);
607
608
builder2.library() {
609
for (Map<String, Object> book : books) {
610
book(id: book.get("id")) {
611
title((String) book.get("title"));
612
author((String) book.get("author"));
613
}
614
}
615
}
616
```
617
618
### Streaming XML Generation
619
620
```java
621
import groovy.xml.StreamingMarkupBuilder;
622
import groovy.lang.Closure;
623
624
// Create large XML documents efficiently
625
StreamingMarkupBuilder builder = new StreamingMarkupBuilder();
626
builder.setEncoding("UTF-8");
627
628
Closure xmlClosure = new Closure(null) {
629
public Object doCall() {
630
// This would be dynamically constructed
631
return new Object() {
632
public Object methodMissing(String name, Object args) {
633
if ("catalog".equals(name)) {
634
return new Object() {
635
public Object methodMissing(String innerName, Object innerArgs) {
636
// Handle nested elements
637
return null;
638
}
639
};
640
}
641
return null;
642
}
643
};
644
}
645
};
646
647
Writable xml = builder.bind(xmlClosure);
648
649
// Write to output
650
StringWriter output = new StringWriter();
651
xml.writeTo(output);
652
System.out.println(output.toString());
653
```
654
655
### Tree-based XML Processing
656
657
```java
658
import groovy.util.XmlParser;
659
import groovy.util.Node;
660
import groovy.util.NodeList;
661
662
// Parse XML into Node tree
663
XmlParser parser = new XmlParser();
664
parser.setTrimWhitespace(true);
665
666
Node catalog = parser.parseText(xml);
667
668
// Navigate using Node API
669
System.out.println("Root element: " + catalog.name());
670
671
// Get all book nodes
672
NodeList bookNodes = catalog.get("book");
673
for (Node book : bookNodes) {
674
// Access attributes
675
Map<String, String> attributes = book.attributes();
676
String id = attributes.get("id");
677
String category = attributes.get("category");
678
679
// Access child elements
680
Node titleNode = (Node) book.get("title").get(0);
681
Node authorNode = (Node) book.get("author").get(0);
682
Node priceNode = (Node) book.get("price").get(0);
683
684
System.out.println("Book " + id + " (" + category + "):");
685
System.out.println(" Title: " + titleNode.text());
686
System.out.println(" Author: " + authorNode.text());
687
System.out.println(" Price: $" + priceNode.text());
688
}
689
690
// Modify the tree
691
Node newBook = new Node(catalog, "book",
692
Map.of("id", "3", "category", "science"));
693
new Node(newBook, "title", "Cosmos");
694
new Node(newBook, "author", "Carl Sagan");
695
new Node(newBook, "price", "14.99");
696
697
catalog.append(newBook);
698
```
699
700
### XML Transformation and Manipulation
701
702
```java
703
import groovy.util.XmlSlurper;
704
import groovy.util.XmlParser;
705
import groovy.xml.XmlUtil;
706
707
// Transform XML structure
708
XmlSlurper slurper = new XmlSlurper();
709
GPathResult catalog = slurper.parseText(originalXml);
710
711
// Filter and transform
712
GPathResult expensiveBooks = catalog.book.findAll { book ->
713
Double.parseDouble(book.price.text()) > 13.0;
714
};
715
716
// Convert GPathResult to Node for manipulation
717
Node catalogNode = catalog.convertToNode();
718
719
// Add new elements
720
for (Node book : catalogNode.get("book")) {
721
Node price = (Node) book.get("price").get(0);
722
double priceValue = Double.parseDouble(price.text());
723
724
// Add discount element
725
Node discount = new Node(book, "discount",
726
priceValue > 15.0 ? "10%" : "5%");
727
}
728
729
// Serialize back to XML
730
String transformedXml = XmlUtil.serialize(catalogNode);
731
System.out.println(transformedXml);
732
```
733
734
### Working with Namespaces
735
736
```java
737
import groovy.xml.Namespace;
738
import groovy.xml.QName;
739
import groovy.util.XmlSlurper;
740
741
// Define namespaces
742
Namespace bookNS = new Namespace("http://example.com/books", "book");
743
Namespace authorNS = new Namespace("http://example.com/authors", "auth");
744
745
// Parse namespaced XML
746
XmlSlurper slurper = new XmlSlurper();
747
slurper.setNamespaceAware(true);
748
749
String namespacedXml = """
750
<catalog
751
xmlns:book="http://example.com/books"
752
xmlns:auth="http://example.com/authors">
753
<book:item id="1">
754
<book:title>Sample Book</book:title>
755
<auth:writer>Sample Author</auth:writer>
756
</book:item>
757
</catalog>
758
""";
759
760
GPathResult catalog = slurper.parseText(namespacedXml);
761
762
// Access namespaced elements
763
QName itemQName = bookNS.getName("item");
764
QName titleQName = bookNS.getName("title");
765
QName writerQName = authorNS.getName("writer");
766
767
// Navigate with namespace awareness
768
GPathResult items = catalog.getProperty(itemQName.getLocalPart());
769
for (GPathResult item : items) {
770
String title = item.getProperty(titleQName.getLocalPart()).text();
771
String writer = item.getProperty(writerQName.getLocalPart()).text();
772
System.out.println("Book: " + title + " by " + writer);
773
}
774
```