0
# Template Processing
1
2
Groovy provides multiple template engines for generating dynamic content with variable substitution, embedded code execution, and flexible output formatting.
3
4
## Template Engines
5
6
### SimpleTemplateEngine
7
8
Basic template engine with GString-style variable substitution and embedded code support.
9
10
```groovy { .api }
11
class SimpleTemplateEngine extends TemplateEngine {
12
SimpleTemplateEngine()
13
SimpleTemplateEngine(ClassLoader parentLoader)
14
15
Template createTemplate(String templateText)
16
Template createTemplate(File templateFile)
17
Template createTemplate(URL templateURL)
18
Template createTemplate(Reader reader)
19
}
20
```
21
22
Usage examples:
23
```groovy
24
import groovy.text.SimpleTemplateEngine
25
26
def engine = new SimpleTemplateEngine()
27
28
// Simple variable substitution
29
def template = engine.createTemplate('Hello $name, you are $age years old.')
30
def binding = [name: 'John', age: 30]
31
def result = template.make(binding)
32
println result.toString() // "Hello John, you are 30 years old."
33
34
// Embedded expressions
35
def template2 = engine.createTemplate('''
36
Dear $name,
37
38
Your account balance is $${balance}.
39
${balance > 1000 ? 'You qualify for premium services.' : 'Consider upgrading your account.'}
40
41
Best regards,
42
The System
43
''')
44
45
def result2 = template2.make([name: 'Alice', balance: 1500])
46
println result2.toString()
47
48
// Embedded code blocks
49
def template3 = engine.createTemplate('''
50
<html>
51
<body>
52
<h1>User List</h1>
53
<ul>
54
<% users.each { user -> %>
55
<li>${user.name} (${user.email})</li>
56
<% } %>
57
</ul>
58
</body>
59
</html>
60
''')
61
62
def users = [
63
[name: 'John', email: 'john@example.com'],
64
[name: 'Jane', email: 'jane@example.com']
65
]
66
def html = template3.make([users: users])
67
println html.toString()
68
```
69
70
### GStringTemplateEngine
71
72
Template engine that treats the entire template as a GString for more flexible processing.
73
74
```groovy { .api }
75
class GStringTemplateEngine extends TemplateEngine {
76
GStringTemplateEngine()
77
GStringTemplateEngine(ClassLoader parentLoader)
78
79
Template createTemplate(String templateText)
80
Template createTemplate(File templateFile)
81
Template createTemplate(URL templateURL)
82
Template createTemplate(Reader reader)
83
}
84
```
85
86
Usage example:
87
```groovy
88
import groovy.text.GStringTemplateEngine
89
90
def engine = new GStringTemplateEngine()
91
92
def template = engine.createTemplate('''
93
Report for $title
94
Generated on ${new Date().format('yyyy-MM-dd')}
95
96
Summary:
97
- Total items: ${items.size()}
98
- Average value: ${items.sum { it.value } / items.size()}
99
- Maximum value: ${items.max { it.value }.value}
100
101
Details:
102
${items.collect { "- ${it.name}: ${it.value}" }.join('\\n')}
103
''')
104
105
def data = [
106
title: 'Monthly Sales',
107
items: [
108
[name: 'Product A', value: 100],
109
[name: 'Product B', value: 250],
110
[name: 'Product C', value: 175]
111
]
112
]
113
114
def report = template.make(data)
115
println report.toString()
116
```
117
118
### XmlTemplateEngine
119
120
Template engine specifically designed for XML generation with proper escaping.
121
122
```groovy { .api }
123
class XmlTemplateEngine extends TemplateEngine {
124
XmlTemplateEngine()
125
XmlTemplateEngine(ClassLoader parentLoader)
126
127
Template createTemplate(String templateText)
128
Template createTemplate(File templateFile)
129
Template createTemplate(URL templateURL)
130
Template createTemplate(Reader reader)
131
}
132
```
133
134
Usage example:
135
```groovy
136
import groovy.text.XmlTemplateEngine
137
138
def engine = new XmlTemplateEngine()
139
140
def template = engine.createTemplate('''
141
<catalog>
142
<title>$title</title>
143
<books>
144
<% books.each { book -> %>
145
<book id="$book.id">
146
<title>$book.title</title>
147
<author>$book.author</author>
148
<price currency="USD">$book.price</price>
149
<description>$book.description</description>
150
</book>
151
<% } %>
152
</books>
153
</catalog>
154
''')
155
156
def catalog = [
157
title: 'Programming Books',
158
books: [
159
[
160
id: 1,
161
title: 'Groovy in Action',
162
author: 'Dierk König',
163
price: 49.99,
164
description: 'Comprehensive guide to Groovy & dynamic languages'
165
],
166
[
167
id: 2,
168
title: 'Programming Groovy 2',
169
author: 'Venkat Subramaniam',
170
price: 44.99,
171
description: 'Practical guide with examples & best practices'
172
]
173
]
174
]
175
176
def xml = template.make(catalog)
177
println xml.toString()
178
```
179
180
### StreamingTemplateEngine
181
182
Memory-efficient template engine for generating large output using streaming.
183
184
```groovy { .api }
185
class StreamingTemplateEngine extends TemplateEngine {
186
StreamingTemplateEngine()
187
StreamingTemplateEngine(String staticText, String expressionText)
188
StreamingTemplateEngine(ClassLoader parentLoader)
189
190
Template createTemplate(String templateText)
191
Template createTemplate(File templateFile)
192
Template createTemplate(URL templateURL)
193
Template createTemplate(Reader reader)
194
}
195
```
196
197
Usage example:
198
```groovy
199
import groovy.text.StreamingTemplateEngine
200
201
def engine = new StreamingTemplateEngine()
202
203
def template = engine.createTemplate('''
204
<html>
205
<head><title>Large Report</title></head>
206
<body>
207
<h1>Data Report</h1>
208
<table>
209
<tr><th>ID</th><th>Name</th><th>Value</th></tr>
210
<% data.each { item -> %>
211
<tr><td>$item.id</td><td>$item.name</td><td>$item.value</td></tr>
212
<% } %>
213
</table>
214
</body>
215
</html>
216
''')
217
218
// Generate large dataset
219
def largeData = (1..10000).collect { i ->
220
[id: i, name: "Item $i", value: Math.random() * 1000]
221
}
222
223
// Stream output to file
224
new File('report.html').withWriter { writer ->
225
def result = template.make([data: largeData])
226
result.writeTo(writer)
227
}
228
```
229
230
## Template Interface
231
232
### Template
233
234
Base interface for all template implementations.
235
236
```groovy { .api }
237
interface Template {
238
Writable make()
239
Writable make(Map binding)
240
}
241
```
242
243
### Writable
244
245
Interface for objects that can write themselves to a Writer.
246
247
```groovy { .api }
248
interface Writable {
249
Writer writeTo(Writer out)
250
}
251
```
252
253
Usage example:
254
```groovy
255
def template = engine.createTemplate('Hello $name!')
256
def writable = template.make([name: 'World'])
257
258
// Write to different outputs
259
println writable.toString() // To string
260
writable.writeTo(System.out) // To console
261
new File('output.txt').withWriter { writer ->
262
writable.writeTo(writer) // To file
263
}
264
```
265
266
## Advanced Template Features
267
268
### Custom Delimiters
269
270
```groovy
271
import groovy.text.SimpleTemplateEngine
272
273
// Custom template with different delimiters
274
def engine = new SimpleTemplateEngine()
275
def customTemplate = '''
276
Report: <%=title%>
277
Date: <%=new Date().format('yyyy-MM-dd')%>
278
279
<% items.each { item -> %>
280
Item: <%=item.name%> - <%=item.value%>
281
<% } %>
282
'''
283
284
// Note: Use StreamingTemplateEngine for custom delimiters
285
def streamingEngine = new StreamingTemplateEngine('<%', '%>')
286
def template = streamingEngine.createTemplate(customTemplate)
287
def result = template.make([
288
title: 'Custom Report',
289
items: [[name: 'A', value: 100], [name: 'B', value: 200]]
290
])
291
println result.toString()
292
```
293
294
### Template Caching
295
296
```groovy
297
import groovy.text.SimpleTemplateEngine
298
299
class CachedTemplateEngine {
300
private final SimpleTemplateEngine engine = new SimpleTemplateEngine()
301
private final Map<String, Template> cache = [:]
302
303
Template getTemplate(String templateText) {
304
return cache.computeIfAbsent(templateText) { text ->
305
engine.createTemplate(text)
306
}
307
}
308
309
String process(String templateText, Map binding) {
310
return getTemplate(templateText).make(binding).toString()
311
}
312
}
313
314
def cachedEngine = new CachedTemplateEngine()
315
316
// Templates are cached for reuse
317
def template1 = 'Hello $name, today is ${new Date().format("yyyy-MM-dd")}'
318
println cachedEngine.process(template1, [name: 'Alice'])
319
println cachedEngine.process(template1, [name: 'Bob']) // Uses cached template
320
```
321
322
### Template Inheritance
323
324
```groovy
325
import groovy.text.SimpleTemplateEngine
326
327
// Base template
328
def baseTemplate = '''
329
<html>
330
<head>
331
<title>$title</title>
332
<style>
333
body { font-family: Arial, sans-serif; }
334
.content { margin: 20px; }
335
</style>
336
</head>
337
<body>
338
<div class="content">
339
$content
340
</div>
341
</body>
342
</html>
343
'''
344
345
// Content template
346
def contentTemplate = '''
347
<h1>$pageTitle</h1>
348
<p>$message</p>
349
<ul>
350
<% items.each { item -> %>
351
<li>$item</li>
352
<% } %>
353
</ul>
354
'''
355
356
def engine = new SimpleTemplateEngine()
357
358
// Generate content first
359
def content = engine.createTemplate(contentTemplate).make([
360
pageTitle: 'Welcome',
361
message: 'This is the main content.',
362
items: ['Feature 1', 'Feature 2', 'Feature 3']
363
]).toString()
364
365
// Apply to base template
366
def finalPage = engine.createTemplate(baseTemplate).make([
367
title: 'My Website',
368
content: content
369
]).toString()
370
371
println finalPage
372
```
373
374
### Template with Includes
375
376
```groovy
377
import groovy.text.SimpleTemplateEngine
378
379
class TemplateManager {
380
private final SimpleTemplateEngine engine = new SimpleTemplateEngine()
381
private final Map<String, String> templates = [:]
382
383
void defineTemplate(String name, String content) {
384
templates[name] = content
385
}
386
387
String include(String templateName, Map binding = [:]) {
388
def templateContent = templates[templateName]
389
if (!templateContent) {
390
throw new IllegalArgumentException("Template '$templateName' not found")
391
}
392
return engine.createTemplate(templateContent).make(binding).toString()
393
}
394
395
String process(String templateContent, Map binding) {
396
// Add include function to binding
397
binding.include = this.&include
398
return engine.createTemplate(templateContent).make(binding).toString()
399
}
400
}
401
402
def manager = new TemplateManager()
403
404
// Define reusable templates
405
manager.defineTemplate('header', '''
406
<header>
407
<h1>$title</h1>
408
<nav>
409
<a href="/home">Home</a>
410
<a href="/about">About</a>
411
</nav>
412
</header>
413
''')
414
415
manager.defineTemplate('footer', '''
416
<footer>
417
<p>© $year $company. All rights reserved.</p>
418
</footer>
419
''')
420
421
// Main template using includes
422
def mainTemplate = '''
423
<html>
424
<body>
425
${include('header', [title: pageTitle])}
426
427
<main>
428
<h2>$contentTitle</h2>
429
<p>$content</p>
430
</main>
431
432
${include('footer', [year: year, company: company])}
433
</body>
434
</html>
435
'''
436
437
def result = manager.process(mainTemplate, [
438
pageTitle: 'My Website',
439
contentTitle: 'Welcome',
440
content: 'This is the main content of the page.',
441
year: 2023,
442
company: 'My Company'
443
])
444
445
println result
446
```
447
448
## Error Handling
449
450
### Template Compilation Errors
451
452
```groovy
453
import groovy.text.SimpleTemplateEngine
454
455
try {
456
def engine = new SimpleTemplateEngine()
457
// Invalid template syntax
458
def template = engine.createTemplate('Hello $name, <% invalid groovy code %>')
459
} catch (Exception e) {
460
println "Template compilation error: ${e.message}"
461
// Handle compilation errors
462
}
463
```
464
465
### Runtime Template Errors
466
467
```groovy
468
try {
469
def engine = new SimpleTemplateEngine()
470
def template = engine.createTemplate('Hello $name.toUpperCase()!')
471
472
// This will fail if name is null
473
def result = template.make([name: null])
474
println result.toString()
475
476
} catch (Exception e) {
477
println "Template execution error: ${e.message}"
478
// Provide default values or error handling
479
def safeTemplate = engine.createTemplate('Hello ${name?.toUpperCase() ?: "Guest"}!')
480
def safeResult = safeTemplate.make([name: null])
481
println safeResult.toString() // "Hello Guest!"
482
}
483
```
484
485
## Integration Patterns
486
487
### Web Template Integration
488
489
```groovy
490
import groovy.text.SimpleTemplateEngine
491
import groovy.servlet.TemplateServlet
492
493
// Example servlet integration
494
class MyTemplateServlet extends TemplateServlet {
495
496
@Override
497
protected void service(HttpServletRequest request, HttpServletResponse response) {
498
def engine = new SimpleTemplateEngine()
499
def template = engine.createTemplate(getTemplate('user-profile'))
500
501
def user = getUserFromSession(request)
502
def binding = [
503
user: user,
504
currentDate: new Date(),
505
contextPath: request.contextPath
506
]
507
508
response.contentType = 'text/html'
509
template.make(binding).writeTo(response.writer)
510
}
511
}
512
```
513
514
### File-based Template System
515
516
```groovy
517
import groovy.text.SimpleTemplateEngine
518
519
class FileTemplateSystem {
520
private final File templateDir
521
private final SimpleTemplateEngine engine = new SimpleTemplateEngine()
522
523
FileTemplateSystem(String templateDirectory) {
524
this.templateDir = new File(templateDirectory)
525
}
526
527
String render(String templateName, Map binding = [:]) {
528
def templateFile = new File(templateDir, "${templateName}.gtpl")
529
if (!templateFile.exists()) {
530
throw new FileNotFoundException("Template not found: $templateName")
531
}
532
533
def template = engine.createTemplate(templateFile)
534
return template.make(binding).toString()
535
}
536
537
void renderToFile(String templateName, String outputPath, Map binding = [:]) {
538
def content = render(templateName, binding)
539
new File(outputPath).text = content
540
}
541
}
542
543
// Usage
544
def templateSystem = new FileTemplateSystem('src/main/templates')
545
546
def emailContent = templateSystem.render('welcome-email', [
547
userName: 'John Doe',
548
activationLink: 'https://example.com/activate/123'
549
])
550
551
templateSystem.renderToFile('report', 'output/monthly-report.html', [
552
reportDate: new Date(),
553
data: getReportData()
554
])
555
```