0
# XML Template Engine
1
2
The XmlTemplateEngine is designed for scenarios where both the template source and expected output are XML. It provides special GSP (Groovy Server Pages) tags for embedding code and expressions while maintaining well-formed XML structure.
3
4
## API
5
6
```java { .api }
7
class XmlTemplateEngine extends TemplateEngine {
8
XmlTemplateEngine() throws SAXException, ParserConfigurationException;
9
XmlTemplateEngine(String indentation, boolean validating) throws SAXException, ParserConfigurationException;
10
XmlTemplateEngine(XmlParser xmlParser, ClassLoader parentLoader);
11
XmlTemplateEngine(XmlParser xmlParser, GroovyShell groovyShell);
12
13
Template createTemplate(Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException;
14
void setIndentation(String indentation);
15
String getIndentation();
16
void setConfigurePrinter(Closure configurePrinter);
17
18
// Constants
19
static final String DEFAULT_INDENTATION = " ";
20
}
21
```
22
23
## Template Syntax
24
25
### GSP Tags
26
27
- **`<gsp:scriptlet>...</gsp:scriptlet>`** - Execute Groovy code fragments
28
- **`<gsp:expression>...</gsp:expression>`** - Output expression results
29
- **GString expressions**: `${...}` and `$variable` - Variable interpolation within text content
30
31
### XML Processing Features
32
33
- **Comments and processing instructions removed** during processing
34
- **Special XML characters** (`<`, `>`, `"`, `'`) are automatically escaped
35
- **Output is automatically indented** using standard XML pretty printing
36
- **Namespace definitions for `gsp:` tags are removed** from output
37
- **Other namespace definitions are preserved** but may change position
38
39
## Usage Examples
40
41
### Basic XML Template
42
43
```java
44
import groovy.text.XmlTemplateEngine;
45
import groovy.text.Template;
46
import java.util.HashMap;
47
import java.util.Map;
48
49
XmlTemplateEngine engine = new XmlTemplateEngine();
50
51
String templateText = """
52
<?xml version="1.0" encoding="UTF-8"?>
53
<document xmlns:gsp='http://groovy.codehaus.org/2005/gsp' xmlns:foo='baz' type='letter'>
54
<gsp:scriptlet>def greeting = "${salutation}est"</gsp:scriptlet>
55
<gsp:expression>greeting</gsp:expression>
56
<foo:to>$firstname "$nickname" $lastname</foo:to>
57
How are you today?
58
</document>
59
""";
60
61
Template template = engine.createTemplate(templateText);
62
63
Map<String, Object> binding = new HashMap<>();
64
binding.put("firstname", "Jochen");
65
binding.put("lastname", "Theodorou");
66
binding.put("nickname", "blackdrag");
67
binding.put("salutation", "Dear");
68
69
String result = template.make(binding).toString();
70
```
71
72
Output:
73
```xml
74
<document type='letter'>
75
Dearest
76
<foo:to xmlns:foo='baz'>
77
Jochen "blackdrag" Theodorou
78
</foo:to>
79
How are you today?
80
</document>
81
```
82
83
### Custom Indentation
84
85
```java
86
// Custom indentation (4 spaces instead of default 2)
87
XmlTemplateEngine engine = new XmlTemplateEngine(" ", false);
88
89
// Or set indentation after creation
90
engine.setIndentation("\t"); // Use tabs
91
```
92
93
### Validating Parser
94
95
```java
96
// Enable XML validation during parsing
97
XmlTemplateEngine engine = new XmlTemplateEngine(" ", true);
98
```
99
100
### Custom XML Parser and Class Loader
101
102
```java
103
import groovy.xml.XmlParser;
104
105
XmlParser customParser = new XmlParser();
106
customParser.setTrimWhitespace(false); // Preserve whitespace
107
ClassLoader customLoader = MyClass.class.getClassLoader();
108
109
XmlTemplateEngine engine = new XmlTemplateEngine(customParser, customLoader);
110
```
111
112
### Custom Printer Configuration
113
114
```java
115
XmlTemplateEngine engine = new XmlTemplateEngine();
116
117
// Configure the XML printer
118
engine.setConfigurePrinter(new Closure<Void>(this) {
119
public void doCall(Object printer) {
120
// printer is a GspPrinter instance
121
((groovy.text.XmlTemplateEngine.GspPrinter) printer).setPreserveWhitespace(true);
122
}
123
});
124
```
125
126
### Complex Template with Conditional Logic
127
128
```java
129
String templateText = """
130
<?xml version="1.0" encoding="UTF-8"?>
131
<report xmlns:gsp='http://groovy.codehaus.org/2005/gsp'>
132
<header>
133
<title>$reportTitle</title>
134
<date><gsp:expression>new Date().format('yyyy-MM-dd')</gsp:expression></date>
135
</header>
136
<body>
137
<gsp:scriptlet>
138
def totalAmount = items.sum { it.price * it.quantity }
139
</gsp:scriptlet>
140
141
<items>
142
<gsp:scriptlet>
143
items.each { item ->
144
out.println("<item>")
145
out.println(" <name>${item.name}</name>")
146
out.println(" <price>${item.price}</price>")
147
out.println(" <quantity>${item.quantity}</quantity>")
148
out.println("</item>")
149
}
150
</gsp:scriptlet>
151
</items>
152
153
<summary>
154
<total>$totalAmount</total>
155
<gsp:scriptlet>
156
if (totalAmount > 1000) {
157
out.println("<discount>10%</discount>")
158
}
159
</gsp:scriptlet>
160
</summary>
161
</body>
162
</report>
163
""";
164
165
Map<String, Object> binding = new HashMap<>();
166
binding.put("reportTitle", "Sales Report");
167
binding.put("items", Arrays.asList(
168
Map.of("name", "Widget A", "price", 25.50, "quantity", 10),
169
Map.of("name", "Widget B", "price", 15.75, "quantity", 5)
170
));
171
```
172
173
### Error Handling
174
175
```java
176
import org.xml.sax.SAXException;
177
import javax.xml.parsers.ParserConfigurationException;
178
179
try {
180
XmlTemplateEngine engine = new XmlTemplateEngine();
181
Template template = engine.createTemplate(xmlTemplateSource);
182
String result = template.make(binding).toString();
183
} catch (SAXException e) {
184
// XML parsing error
185
System.err.println("XML parsing failed: " + e.getMessage());
186
} catch (ParserConfigurationException e) {
187
// XML parser configuration error
188
System.err.println("XML parser configuration error: " + e.getMessage());
189
} catch (RuntimeException e) {
190
// Unsupported GSP tag or other runtime error
191
if (e.getMessage().contains("Unsupported 'gsp:' tag")) {
192
System.err.println("Invalid GSP tag: " + e.getMessage());
193
} else {
194
throw e;
195
}
196
}
197
```
198
199
## Servlet Integration
200
201
The XmlTemplateEngine can be used with TemplateServlet for web applications:
202
203
```xml
204
<!-- web.xml -->
205
<servlet>
206
<servlet-name>XmlTemplate</servlet-name>
207
<servlet-class>groovy.servlet.TemplateServlet</servlet-class>
208
<init-param>
209
<param-name>template.engine</param-name>
210
<param-value>groovy.text.XmlTemplateEngine</param-value>
211
</init-param>
212
</servlet>
213
```
214
215
## Best Practices
216
217
### Template Structure
218
219
1. **Always include XML declaration** for proper encoding handling
220
2. **Use proper namespace declaration** for GSP tags: `xmlns:gsp='http://groovy.codehaus.org/2005/gsp'`
221
3. **Keep GSP tags minimal** - complex logic should be in scriptlets
222
4. **Use expressions for simple output** and scriptlets for complex logic
223
224
### Performance Considerations
225
226
1. **Reuse engine instances** when possible
227
2. **Cache compiled templates** for frequently used templates
228
3. **Use appropriate indentation settings** - simpler indentation is faster
229
4. **Disable validation** for templates you trust to improve performance
230
231
### XML Escaping
232
233
The engine automatically escapes special XML characters in text content, but not within GString expressions. If you need to output literal XML characters within expressions, handle escaping manually:
234
235
```java
236
String templateText = """
237
<message>
238
<content>User said: ${userInput}</content> <!-- Automatically escaped -->
239
<raw><gsp:expression>groovy.xml.XmlUtil.escapeXml(rawContent)</gsp:expression></raw> <!-- Manual escaping -->
240
</message>
241
""";
242
```