0
# Template Engines
1
2
Comprehensive templating system with multiple engines for generating dynamic text output. Includes SimpleTemplateEngine for basic templating, GStringTemplateEngine for GString-based templates, and specialized engines for XML/HTML generation with streaming support.
3
4
## Capabilities
5
6
### Simple Template Engine
7
8
Basic templating engine using GString syntax for variable substitution and simple expressions.
9
10
```java { .api }
11
/**
12
* Simple template engine using GString syntax for basic templating
13
*/
14
class SimpleTemplateEngine extends TemplateEngine {
15
/**
16
* Create template engine with default configuration
17
*/
18
SimpleTemplateEngine();
19
20
/**
21
* Create template engine with custom ClassLoader
22
*/
23
SimpleTemplateEngine(ClassLoader parentLoader);
24
25
/**
26
* Create template from string
27
*/
28
Template createTemplate(String templateText) throws CompilationFailedException;
29
30
/**
31
* Create template from Reader
32
*/
33
Template createTemplate(Reader reader) throws CompilationFailedException;
34
35
/**
36
* Create template from File
37
*/
38
Template createTemplate(File file) throws CompilationFailedException;
39
40
/**
41
* Create template from URL
42
*/
43
Template createTemplate(URL url) throws CompilationFailedException;
44
}
45
46
/**
47
* Compiled template that can be applied to binding data
48
*/
49
interface Template {
50
/**
51
* Apply template with binding data
52
*/
53
Writable make(Map binding);
54
55
/**
56
* Apply template with empty binding
57
*/
58
Writable make();
59
}
60
61
/**
62
* Template output that can be written to various destinations
63
*/
64
interface Writable {
65
/**
66
* Write template output to Writer
67
*/
68
Writer writeTo(Writer out) throws IOException;
69
70
/**
71
* Get template output as String
72
*/
73
String toString();
74
}
75
```
76
77
**Usage Examples:**
78
79
```groovy
80
import groovy.text.SimpleTemplateEngine
81
82
def engine = new SimpleTemplateEngine()
83
84
// Basic variable substitution
85
def template = engine.createTemplate('Hello $name, welcome to $location!')
86
def binding = [name: 'John', location: 'New York']
87
def result = template.make(binding)
88
println result.toString()
89
// Output: Hello John, welcome to New York!
90
91
// Template with expressions
92
def emailTemplate = engine.createTemplate('''
93
Dear $customer.name,
94
95
Your order #${order.id} for $${order.total} has been ${order.status.toLowerCase()}.
96
97
Order Details:
98
<% order.items.each { item -> %>
99
- ${item.name}: $${item.price} x ${item.quantity}
100
<% } %>
101
102
Total: $${order.total}
103
104
Thank you for your business!
105
''')
106
107
def orderData = [
108
customer: [name: 'Alice Johnson'],
109
order: [
110
id: 12345,
111
total: 89.97,
112
status: 'SHIPPED',
113
items: [
114
[name: 'Widget A', price: 29.99, quantity: 2],
115
[name: 'Widget B', price: 29.99, quantity: 1]
116
]
117
]
118
]
119
120
def email = emailTemplate.make(orderData)
121
println email.toString()
122
123
// Template from file
124
def fileTemplate = engine.createTemplate(new File('invoice.template'))
125
def invoice = fileTemplate.make([
126
invoiceNumber: 'INV-2023-001',
127
date: new Date(),
128
customer: 'ACME Corp',
129
items: [
130
[description: 'Consulting', hours: 40, rate: 150],
131
[description: 'Development', hours: 80, rate: 125]
132
]
133
])
134
135
// Write to file
136
new File('invoice.html').withWriter { writer ->
137
invoice.writeTo(writer)
138
}
139
```
140
141
### GString Template Engine
142
143
Template engine that treats the entire template as a GString for more natural Groovy syntax.
144
145
```java { .api }
146
/**
147
* Template engine using GString evaluation for natural Groovy syntax
148
*/
149
class GStringTemplateEngine extends TemplateEngine {
150
/**
151
* Create GString template engine
152
*/
153
GStringTemplateEngine();
154
155
/**
156
* Create GString template engine with custom ClassLoader
157
*/
158
GStringTemplateEngine(ClassLoader parentLoader);
159
160
/**
161
* Create template from string
162
*/
163
Template createTemplate(String templateText) throws CompilationFailedException;
164
165
/**
166
* Create template from Reader
167
*/
168
Template createTemplate(Reader reader) throws CompilationFailedException;
169
}
170
```
171
172
**Usage Examples:**
173
174
```groovy
175
import groovy.text.GStringTemplateEngine
176
177
def engine = new GStringTemplateEngine()
178
179
// More flexible expression syntax
180
def template = engine.createTemplate('''
181
Report Generated: ${new Date().format('yyyy-MM-dd HH:mm')}
182
183
Summary for ${period}:
184
- Total Users: ${stats.totalUsers}
185
- Active Users: ${stats.activeUsers} (${(stats.activeUsers/stats.totalUsers*100).round(1)}%)
186
- Revenue: $${stats.revenue.round(2)}
187
188
Top Products:
189
${products.take(5).collect { "- ${it.name}: ${it.sales} sales" }.join('\\n')}
190
''')
191
192
def reportData = [
193
period: 'Q4 2023',
194
stats: [
195
totalUsers: 10000,
196
activeUsers: 7500,
197
revenue: 125000.50
198
],
199
products: [
200
[name: 'Product A', sales: 450],
201
[name: 'Product B', sales: 380],
202
[name: 'Product C', sales: 295],
203
[name: 'Product D', sales: 210],
204
[name: 'Product E', sales: 185]
205
]
206
]
207
208
def report = template.make(reportData)
209
println report.toString()
210
```
211
212
### Streaming Template Engine
213
214
Memory-efficient template engine for generating large documents without loading everything into memory.
215
216
```java { .api }
217
/**
218
* Memory-efficient streaming template engine for large documents
219
*/
220
class StreamingTemplateEngine extends TemplateEngine {
221
/**
222
* Create streaming template engine
223
*/
224
StreamingTemplateEngine();
225
226
/**
227
* Create streaming template engine with custom ClassLoader
228
*/
229
StreamingTemplateEngine(ClassLoader parentLoader);
230
231
/**
232
* Create template from string
233
*/
234
Template createTemplate(String templateText) throws CompilationFailedException;
235
236
/**
237
* Create template from Reader
238
*/
239
Template createTemplate(Reader reader) throws CompilationFailedException;
240
}
241
```
242
243
**Usage Examples:**
244
245
```groovy
246
import groovy.text.StreamingTemplateEngine
247
248
def engine = new StreamingTemplateEngine()
249
250
// Large report template
251
def template = engine.createTemplate('''
252
<html>
253
<head><title>Large Data Report</title></head>
254
<body>
255
<h1>Data Export - ${title}</h1>
256
<table>
257
<tr><th>ID</th><th>Name</th><th>Value</th><th>Status</th></tr>
258
<% data.each { row -> %>
259
<tr>
260
<td>${row.id}</td>
261
<td>${row.name}</td>
262
<td>${row.value}</td>
263
<td>${row.status}</td>
264
</tr>
265
<% } %>
266
</table>
267
</body>
268
</html>
269
''')
270
271
// Generate large dataset
272
def largeDataset = (1..100000).collect { id ->
273
[
274
id: id,
275
name: "Item $id",
276
value: Math.random() * 1000,
277
status: ['Active', 'Inactive', 'Pending'][id % 3]
278
]
279
}
280
281
def binding = [
282
title: 'Complete Data Export',
283
data: largeDataset
284
]
285
286
// Stream directly to file to avoid memory issues
287
new File('large_report.html').withWriter { writer ->
288
def result = template.make(binding)
289
result.writeTo(writer) // Streams output without loading all in memory
290
}
291
```
292
293
### XML Template Engine
294
295
Specialized template engine for generating well-formed XML with namespace support and XML-aware features.
296
297
```java { .api }
298
/**
299
* XML-aware template engine with namespace and validation support
300
*/
301
class XmlTemplateEngine extends TemplateEngine {
302
/**
303
* Create XML template engine
304
*/
305
XmlTemplateEngine();
306
307
/**
308
* Create XML template engine with custom ClassLoader
309
*/
310
XmlTemplateEngine(ClassLoader parentLoader);
311
312
/**
313
* Create XML template engine with validation
314
*/
315
XmlTemplateEngine(boolean validating);
316
317
/**
318
* Create template from string
319
*/
320
Template createTemplate(String templateText) throws CompilationFailedException;
321
}
322
```
323
324
**Usage Examples:**
325
326
```groovy
327
import groovy.text.XmlTemplateEngine
328
329
def engine = new XmlTemplateEngine()
330
331
// XML configuration template
332
def template = engine.createTemplate('''
333
<?xml version="1.0" encoding="UTF-8"?>
334
<configuration xmlns="http://example.com/config" version="${version}">
335
<database>
336
<host>${db.host}</host>
337
<port>${db.port}</port>
338
<name>${db.name}</name>
339
</database>
340
<features>
341
<% features.each { feature -> %>
342
<feature name="${feature.name}" enabled="${feature.enabled}" />
343
<% } %>
344
</features>
345
<users>
346
<% users.each { user -> %>
347
<user id="${user.id}">
348
<name>${user.name}</name>
349
<email>${user.email}</email>
350
<roles>
351
<% user.roles.each { role -> %>
352
<role>${role}</role>
353
<% } %>
354
</roles>
355
</user>
356
<% } %>
357
</users>
358
</configuration>
359
''')
360
361
def configData = [
362
version: '2.1',
363
db: [
364
host: 'localhost',
365
port: 5432,
366
name: 'production'
367
],
368
features: [
369
[name: 'caching', enabled: true],
370
[name: 'logging', enabled: true],
371
[name: 'debugging', enabled: false]
372
],
373
users: [
374
[id: 1, name: 'Admin', email: 'admin@example.com', roles: ['admin', 'user']],
375
[id: 2, name: 'John', email: 'john@example.com', roles: ['user']]
376
]
377
]
378
379
def xmlConfig = template.make(configData)
380
println xmlConfig.toString()
381
```
382
383
### Markup Template Engine
384
385
Type-safe template engine for generating HTML/XML with compile-time validation and IDE support.
386
387
```java { .api }
388
/**
389
* Type-safe markup template engine with compile-time validation
390
*/
391
class MarkupTemplateEngine extends TemplateEngine {
392
/**
393
* Create markup template engine with configuration
394
*/
395
MarkupTemplateEngine(TemplateConfiguration configuration);
396
397
/**
398
* Create template from string
399
*/
400
Template createTemplate(String templateText) throws CompilationFailedException;
401
402
/**
403
* Create template from File
404
*/
405
Template createTemplate(File templateFile) throws CompilationFailedException;
406
407
/**
408
* Create type-checked template
409
*/
410
Template createTypeCheckedTemplate(String templateText) throws CompilationFailedException;
411
}
412
413
/**
414
* Configuration for markup template engine
415
*/
416
class TemplateConfiguration {
417
/**
418
* Set whether to cache templates
419
*/
420
void setCacheTemplates(boolean cache);
421
422
/**
423
* Set auto-indent for generated markup
424
*/
425
void setAutoIndent(boolean autoIndent);
426
427
/**
428
* Set auto-newline for generated markup
429
*/
430
void setAutoNewLine(boolean autoNewLine);
431
432
/**
433
* Set locale for template
434
*/
435
void setLocale(Locale locale);
436
437
/**
438
* Set base template class
439
*/
440
void setBaseTemplateClass(Class<?> baseTemplateClass);
441
}
442
```
443
444
**Usage Examples:**
445
446
```groovy
447
import groovy.text.markup.MarkupTemplateEngine
448
import groovy.text.markup.TemplateConfiguration
449
450
// Configure template engine
451
def config = new TemplateConfiguration()
452
config.autoIndent = true
453
config.autoNewLine = true
454
config.cacheTemplates = true
455
456
def engine = new MarkupTemplateEngine(config)
457
458
// Type-safe HTML template
459
def template = engine.createTemplate('''
460
html {
461
head {
462
title(pageTitle)
463
meta(charset: 'UTF-8')
464
link(rel: 'stylesheet', href: '/css/main.css')
465
}
466
body {
467
header {
468
h1(pageTitle)
469
nav {
470
ul {
471
menuItems.each { item ->
472
li {
473
a(href: item.url, item.text)
474
}
475
}
476
}
477
}
478
}
479
main {
480
articles.each { article ->
481
article {
482
h2(article.title)
483
p(class: 'meta', "Published: ${article.date}")
484
div(class: 'content') {
485
yieldUnescaped article.content
486
}
487
}
488
}
489
}
490
footer {
491
p("© ${new Date().year + 1900} My Website")
492
}
493
}
494
}
495
''')
496
497
def pageData = [
498
pageTitle: 'My Blog',
499
menuItems: [
500
[url: '/', text: 'Home'],
501
[url: '/about', text: 'About'],
502
[url: '/contact', text: 'Contact']
503
],
504
articles: [
505
[
506
title: 'First Post',
507
date: '2023-01-15',
508
content: '<p>This is my first blog post!</p>'
509
],
510
[
511
title: 'Second Post',
512
date: '2023-01-20',
513
content: '<p>Here is another post with <strong>bold text</strong>.</p>'
514
]
515
]
516
]
517
518
def html = template.make(pageData)
519
println html.toString()
520
521
// Email template with type checking
522
def emailTemplate = engine.createTypeCheckedTemplate('''
523
html {
524
body {
525
h1("Welcome ${user.name}!")
526
p("Thank you for signing up for our service.")
527
528
div(style: 'border: 1px solid #ccc; padding: 20px; margin: 20px 0;') {
529
h3("Account Details:")
530
ul {
531
li("Username: ${user.username}")
532
li("Email: ${user.email}")
533
li("Member since: ${user.joinDate}")
534
}
535
}
536
537
p {
538
yield "Click "
539
a(href: "${baseUrl}/activate?token=${user.activationToken}", "here")
540
yield " to activate your account."
541
}
542
543
hr()
544
545
p(style: 'color: #666; font-size: 12px;') {
546
yield "If you have any questions, contact us at "
547
a(href: "mailto:support@example.com", "support@example.com")
548
}
549
}
550
}
551
''')
552
```
553
554
### Template Caching and Performance
555
556
Optimize template performance with caching and compilation strategies.
557
558
**Usage Examples:**
559
560
```groovy
561
import groovy.text.SimpleTemplateEngine
562
import java.util.concurrent.ConcurrentHashMap
563
564
class CachedTemplateEngine {
565
private final SimpleTemplateEngine engine = new SimpleTemplateEngine()
566
private final Map<String, Template> templateCache = new ConcurrentHashMap<>()
567
568
Template getTemplate(String name, String templateText) {
569
return templateCache.computeIfAbsent(name) { key ->
570
engine.createTemplate(templateText)
571
}
572
}
573
574
Template getTemplate(String name, File templateFile) {
575
def lastModified = templateFile.lastModified()
576
def cacheKey = "${name}_${lastModified}"
577
578
return templateCache.computeIfAbsent(cacheKey) { key ->
579
// Remove old versions
580
templateCache.entrySet().removeIf { entry ->
581
entry.key.startsWith("${name}_") && entry.key != cacheKey
582
}
583
engine.createTemplate(templateFile)
584
}
585
}
586
587
void clearCache() {
588
templateCache.clear()
589
}
590
}
591
592
// Usage
593
def cachedEngine = new CachedTemplateEngine()
594
595
// Templates are compiled once and cached
596
def welcome = cachedEngine.getTemplate('welcome', 'Hello $name!')
597
def result1 = welcome.make([name: 'Alice'])
598
def result2 = welcome.make([name: 'Bob']) // Uses cached template
599
600
// File-based templates with modification checking
601
def fileTemplate = cachedEngine.getTemplate('invoice', new File('invoice.template'))
602
```
603
604
## Types
605
606
### Template Engine Types
607
608
```java { .api }
609
/**
610
* Base class for all template engines
611
*/
612
abstract class TemplateEngine {
613
/**
614
* Create template from string content
615
*/
616
abstract Template createTemplate(String templateText) throws CompilationFailedException;
617
618
/**
619
* Create template from Reader
620
*/
621
abstract Template createTemplate(Reader reader) throws CompilationFailedException;
622
}
623
624
/**
625
* Compiled template ready for execution
626
*/
627
interface Template {
628
/**
629
* Execute template with binding data
630
*/
631
Writable make(Map binding);
632
633
/**
634
* Execute template with empty binding
635
*/
636
Writable make();
637
}
638
639
/**
640
* Template output that can be written to various destinations
641
*/
642
interface Writable {
643
/**
644
* Write content to Writer
645
*/
646
Writer writeTo(Writer out) throws IOException;
647
648
/**
649
* Get content as String
650
*/
651
String toString();
652
}
653
```
654
655
### Configuration Types
656
657
```java { .api }
658
/**
659
* Configuration options for markup template engine
660
*/
661
class TemplateConfiguration {
662
/**
663
* Enable/disable template caching
664
*/
665
boolean isCacheTemplates();
666
void setCacheTemplates(boolean cache);
667
668
/**
669
* Enable/disable automatic indentation
670
*/
671
boolean isAutoIndent();
672
void setAutoIndent(boolean autoIndent);
673
674
/**
675
* Enable/disable automatic newlines
676
*/
677
boolean isAutoNewLine();
678
void setAutoNewLine(boolean autoNewLine);
679
680
/**
681
* Get/set locale for templates
682
*/
683
Locale getLocale();
684
void setLocale(Locale locale);
685
686
/**
687
* Get/set base template class
688
*/
689
Class<?> getBaseTemplateClass();
690
void setBaseTemplateClass(Class<?> baseClass);
691
}
692
693
/**
694
* Exception thrown when template compilation fails
695
*/
696
class CompilationFailedException extends Exception {
697
CompilationFailedException(String message);
698
CompilationFailedException(String message, Throwable cause);
699
}
700
```