or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-compilation.mdcollections-utilities.mdconfig-data.mdcore-language.mddependency-management.mdindex.mdio-file-processing.mdjson-processing.mdsql-database.mdtemplate-engines.mdtesting-apis.mdtime-date.mdtransform-annotations.mdxml-processing.md

template-engines.mddocs/

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

```