0
# Template Processing
1
2
Template engines for code generation, text processing, and dynamic content creation with support for various template formats and streaming capabilities.
3
4
## Capabilities
5
6
### Simple Template Engine
7
8
Basic template engine for string substitution and simple expression evaluation.
9
10
```groovy { .api }
11
/**
12
* Simple template engine for string substitution
13
*/
14
class SimpleTemplateEngine {
15
/** Create simple template engine */
16
SimpleTemplateEngine()
17
18
/** Create template from string */
19
Template createTemplate(String text)
20
21
/** Create template from Reader */
22
Template createTemplate(Reader reader)
23
24
/** Create template from File */
25
Template createTemplate(File file)
26
27
/** Create template from URL */
28
Template createTemplate(URL url)
29
}
30
31
/**
32
* Template interface for rendering with bindings
33
*/
34
interface Template {
35
/** Render template with binding */
36
Writable make(Map binding)
37
38
/** Render template with empty binding */
39
Writable make()
40
}
41
```
42
43
**Usage Examples:**
44
45
```groovy
46
import groovy.text.SimpleTemplateEngine
47
48
// Basic template
49
def engine = new SimpleTemplateEngine()
50
def templateText = '''
51
Hello $name,
52
53
Welcome to $company! Your account has been created with the following details:
54
- Username: $username
55
- Email: $email
56
- Department: ${department.toUpperCase()}
57
58
Best regards,
59
The $company Team
60
'''
61
62
def template = engine.createTemplate(templateText)
63
64
def binding = [
65
name: "Alice Johnson",
66
company: "Acme Corp",
67
username: "ajohnson",
68
email: "alice@acme.com",
69
department: "engineering"
70
]
71
72
def result = template.make(binding)
73
println result.toString()
74
75
// Template with expressions
76
def reportTemplate = '''
77
Report Generated: ${new Date()}
78
Total Users: $userCount
79
80
${users.collect { "- $it.name ($it.email)" }.join('\\n')}
81
82
Average Age: ${users.sum { it.age } / users.size()}
83
'''
84
85
def template2 = engine.createTemplate(reportTemplate)
86
def binding2 = [
87
userCount: 3,
88
users: [
89
[name: "Alice", email: "alice@example.com", age: 30],
90
[name: "Bob", email: "bob@example.com", age: 25],
91
[name: "Charlie", email: "charlie@example.com", age: 35]
92
]
93
]
94
95
println template2.make(binding2)
96
97
// Template from file
98
def fileTemplate = engine.createTemplate(new File("email-template.txt"))
99
def email = fileTemplate.make([
100
recipient: "customer@example.com",
101
subject: "Order Confirmation",
102
orderNumber: "12345"
103
])
104
```
105
106
### Streaming Template Engine
107
108
Template engine optimized for large templates with streaming output.
109
110
```groovy { .api }
111
/**
112
* Streaming template engine for large templates
113
*/
114
class StreamingTemplateEngine {
115
/** Create streaming template engine */
116
StreamingTemplateEngine()
117
118
/** Create template from string */
119
Template createTemplate(String text)
120
121
/** Create template from Reader */
122
Template createTemplate(Reader reader)
123
124
/** Create template from File */
125
Template createTemplate(File file)
126
127
/** Create template from URL */
128
Template createTemplate(URL url)
129
}
130
```
131
132
**Usage Examples:**
133
134
```groovy
135
import groovy.text.StreamingTemplateEngine
136
137
// Large data template
138
def engine = new StreamingTemplateEngine()
139
def csvTemplate = '''
140
"Name","Email","Department","Salary"
141
<% users.each { user -> %>
142
"${user.name}","${user.email}","${user.department}","${user.salary}"
143
<% } %>
144
'''
145
146
def template = engine.createTemplate(csvTemplate)
147
148
// Stream to file for large datasets
149
new File("users.csv").withWriter { writer ->
150
def result = template.make([users: largeUserList])
151
writer << result
152
}
153
154
// Stream to HTTP response
155
response.contentType = "text/csv"
156
response.setHeader("Content-Disposition", "attachment; filename=users.csv")
157
response.writer << template.make([users: userList])
158
```
159
160
### XML Template Engine
161
162
Template engine specifically designed for XML-based templates.
163
164
```groovy { .api }
165
/**
166
* Template engine for XML-based templates
167
*/
168
class XmlTemplateEngine {
169
/** Create XML template engine */
170
XmlTemplateEngine()
171
172
/** Create template from string */
173
Template createTemplate(String text)
174
175
/** Create template from Reader */
176
Template createTemplate(Reader reader)
177
178
/** Create template from File */
179
Template createTemplate(File file)
180
181
/** Create template from URL */
182
Template createTemplate(URL url)
183
}
184
```
185
186
**Usage Examples:**
187
188
```groovy
189
import groovy.text.XmlTemplateEngine
190
191
def engine = new XmlTemplateEngine()
192
def xmlTemplate = '''
193
<?xml version="1.0" encoding="UTF-8"?>
194
<users>
195
<% users.each { user -> %>
196
<user id="${user.id}">
197
<name>${user.name}</name>
198
<email>${user.email}</email>
199
<% if (user.active) { %>
200
<status>active</status>
201
<% } else { %>
202
<status>inactive</status>
203
<% } %>
204
<departments>
205
<% user.departments.each { dept -> %>
206
<department>${dept}</department>
207
<% } %>
208
</departments>
209
</user>
210
<% } %>
211
</users>
212
'''
213
214
def template = engine.createTemplate(xmlTemplate)
215
def binding = [
216
users: [
217
[id: 1, name: "Alice", email: "alice@example.com", active: true, departments: ["Engineering", "Research"]],
218
[id: 2, name: "Bob", email: "bob@example.com", active: false, departments: ["Sales"]],
219
[id: 3, name: "Charlie", email: "charlie@example.com", active: true, departments: ["Marketing", "Support"]]
220
]
221
]
222
223
def xmlResult = template.make(binding)
224
println xmlResult.toString()
225
```
226
227
### Markup Template Engine
228
229
Advanced template engine for creating structured markup with type checking.
230
231
```groovy { .api }
232
/**
233
* Advanced markup template engine
234
*/
235
class MarkupTemplateEngine {
236
/** Create with default configuration */
237
MarkupTemplateEngine()
238
239
/** Create with custom configuration */
240
MarkupTemplateEngine(TemplateConfiguration config)
241
242
/** Create template from string */
243
Template createTemplate(String templateText)
244
245
/** Create template from Reader */
246
Template createTemplate(Reader templateReader)
247
248
/** Create template from File */
249
Template createTemplate(File templateFile)
250
251
/** Create template from URL */
252
Template createTemplate(URL templateURL)
253
254
/** Create typed template */
255
Template createTypeCheckedTemplate(String templateText, Map<String, String> modelTypes)
256
}
257
258
/**
259
* Configuration for markup template engine
260
*/
261
class TemplateConfiguration {
262
/** Set whether to auto-escape XML */
263
TemplateConfiguration autoEscape(boolean autoEscape)
264
265
/** Set whether to auto-format output */
266
TemplateConfiguration autoFormat(boolean autoFormat)
267
268
/** Set whether to auto-newline */
269
TemplateConfiguration autoNewLine(boolean autoNewLine)
270
271
/** Set whether to auto-indent */
272
TemplateConfiguration autoIndent(boolean autoIndent)
273
274
/** Set base template class */
275
TemplateConfiguration baseTemplateClass(Class<?> baseTemplateClass)
276
277
/** Set cache templates */
278
TemplateConfiguration cacheTemplates(boolean cacheTemplates)
279
}
280
```
281
282
**Usage Examples:**
283
284
```groovy
285
import groovy.text.markup.*
286
287
// Create configured engine
288
def config = new TemplateConfiguration()
289
.autoEscape(true)
290
.autoFormat(true)
291
.autoIndent(true)
292
293
def engine = new MarkupTemplateEngine(config)
294
295
// HTML template
296
def htmlTemplate = '''
297
html {
298
head {
299
title(pageTitle)
300
meta(charset: 'UTF-8')
301
}
302
body {
303
h1(pageTitle)
304
div(class: 'content') {
305
p("Welcome, $userName!")
306
307
if (showUserList) {
308
ul {
309
users.each { user ->
310
li {
311
a(href: "/user/$user.id", user.name)
312
span(" (${user.email})")
313
}
314
}
315
}
316
}
317
318
div(class: 'footer') {
319
p("Generated on ${new Date()}")
320
}
321
}
322
}
323
}
324
'''
325
326
def template = engine.createTemplate(htmlTemplate)
327
def binding = [
328
pageTitle: "User Dashboard",
329
userName: "Alice",
330
showUserList: true,
331
users: [
332
[id: 1, name: "Bob", email: "bob@example.com"],
333
[id: 2, name: "Charlie", email: "charlie@example.com"]
334
]
335
]
336
337
def html = template.make(binding)
338
println html.toString()
339
340
// Type-checked template
341
def typedTemplate = engine.createTypeCheckedTemplate('''
342
html {
343
body {
344
h1(title)
345
p("User count: $users.size()")
346
users.each { user ->
347
div {
348
yield "Name: $user.name, Age: $user.age"
349
}
350
}
351
}
352
}
353
''', [
354
title: 'String',
355
users: 'List<Map<String,Object>>'
356
])
357
```
358
359
### Template Exceptions
360
361
Exception classes for template processing errors.
362
363
```groovy { .api }
364
/**
365
* Exception thrown during template execution
366
*/
367
class TemplateExecutionException extends RuntimeException {
368
TemplateExecutionException(String message)
369
TemplateExecutionException(String message, Throwable cause)
370
371
/** Get line number where error occurred */
372
int getLineNumber()
373
374
/** Get column number where error occurred */
375
int getColumnNumber()
376
377
/** Get template source name */
378
String getSourceName()
379
}
380
381
/**
382
* Exception thrown during template parsing
383
*/
384
class TemplateParseException extends RuntimeException {
385
TemplateParseException(String message)
386
TemplateParseException(String message, Throwable cause)
387
388
/** Get line number where error occurred */
389
int getLineNumber()
390
391
/** Get column number where error occurred */
392
int getColumnNumber()
393
}
394
```
395
396
**Usage Examples:**
397
398
```groovy
399
import groovy.text.*
400
401
def engine = new SimpleTemplateEngine()
402
403
try {
404
// Template with syntax error
405
def template = engine.createTemplate('Hello ${ invalid syntax }')
406
def result = template.make([:])
407
} catch (TemplateParseException e) {
408
println "Parse error at line ${e.lineNumber}, column ${e.columnNumber}: ${e.message}"
409
}
410
411
try {
412
// Template with runtime error
413
def template = engine.createTemplate('Hello $name.nonexistentMethod()')
414
def result = template.make([name: "Alice"])
415
println result.toString()
416
} catch (TemplateExecutionException e) {
417
println "Execution error: ${e.message}"
418
println "At line ${e.lineNumber} in ${e.sourceName}"
419
}
420
```
421
422
## Advanced Template Features
423
424
### Custom Template Base Classes
425
426
Create custom base classes for templates with additional functionality.
427
428
```groovy
429
// Custom base template class
430
abstract class CustomBaseTemplate extends Template {
431
// Helper methods available in all templates
432
String formatDate(Date date) {
433
return date.format('yyyy-MM-dd')
434
}
435
436
String formatCurrency(BigDecimal amount) {
437
return String.format('$%.2f', amount)
438
}
439
440
String truncate(String text, int length) {
441
return text.length() > length ? text[0..length-1] + '...' : text
442
}
443
}
444
445
// Use custom base class
446
def config = new TemplateConfiguration()
447
.baseTemplateClass(CustomBaseTemplate)
448
449
def engine = new MarkupTemplateEngine(config)
450
451
def template = engine.createTemplate('''
452
div {
453
p("Order Date: ${formatDate(order.date)}")
454
p("Total: ${formatCurrency(order.total)}")
455
p("Description: ${truncate(order.description, 50)}")
456
}
457
''')
458
```
459
460
### Template Includes and Layouts
461
462
```groovy
463
// Layout template
464
def layoutTemplate = '''
465
html {
466
head {
467
title(pageTitle)
468
meta(charset: 'UTF-8')
469
if (stylesheets) {
470
stylesheets.each { css ->
471
link(rel: 'stylesheet', href: css)
472
}
473
}
474
}
475
body {
476
header {
477
h1(pageTitle)
478
}
479
main {
480
yieldUnescaped content
481
}
482
footer {
483
p("© 2023 Company Name")
484
}
485
}
486
}
487
'''
488
489
// Content template
490
def contentTemplate = '''
491
div(class: 'user-profile') {
492
h2("User Profile")
493
p("Name: $user.name")
494
p("Email: $user.email")
495
496
if (user.projects) {
497
h3("Projects")
498
ul {
499
user.projects.each { project ->
500
li(project.name)
501
}
502
}
503
}
504
}
505
'''
506
507
// Render with layout
508
def layoutEngine = new MarkupTemplateEngine()
509
def layout = layoutEngine.createTemplate(layoutTemplate)
510
511
def contentEngine = new MarkupTemplateEngine()
512
def content = contentEngine.createTemplate(contentTemplate)
513
514
def contentResult = content.make([user: userData])
515
def finalResult = layout.make([
516
pageTitle: "User Profile",
517
stylesheets: ['/css/main.css', '/css/profile.css'],
518
content: contentResult.toString()
519
])
520
```