or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

gstring-templates.mdindex.mdmarkup-templates.mdsimple-templates.mdstreaming-templates.mdxml-templates.md

markup-templates.mddocs/

0

# Markup Templates

1

2

The MarkupTemplateEngine provides the most advanced template processing capabilities, leveraging StreamingMarkupBuilder for highly optimized XML/XHTML generation. It includes compile-time type checking, extensive configuration options, template caching, and a rich base template class for markup generation.

3

4

## Capabilities

5

6

### Markup Template Engine Class

7

8

Advanced template engine with type checking, configuration, and optimization features.

9

10

```java { .api }

11

/**

12

* Advanced template engine leveraging StreamingMarkupBuilder for optimized XML/XHTML generation.

13

* Includes compile-time type checking, template caching, and extensive configuration options.

14

*/

15

public class MarkupTemplateEngine extends TemplateEngine {

16

/**

17

* Creates a new MarkupTemplateEngine with default configuration

18

*/

19

public MarkupTemplateEngine();

20

21

/**

22

* Creates a new MarkupTemplateEngine with custom configuration

23

* @param config TemplateConfiguration for engine settings

24

*/

25

public MarkupTemplateEngine(TemplateConfiguration config);

26

27

/**

28

* Creates a new MarkupTemplateEngine with custom class loader and configuration

29

* @param parentLoader ClassLoader for template compilation

30

* @param config TemplateConfiguration for engine settings

31

*/

32

public MarkupTemplateEngine(ClassLoader parentLoader, TemplateConfiguration config);

33

34

/**

35

* Creates a new MarkupTemplateEngine with full customization

36

* @param parentLoader ClassLoader for template compilation

37

* @param config TemplateConfiguration for engine settings

38

* @param resolver TemplateResolver for resolving template resources

39

*/

40

public MarkupTemplateEngine(ClassLoader parentLoader, TemplateConfiguration config, TemplateResolver resolver);

41

}

42

```

43

44

### Template Configuration Class

45

46

Comprehensive configuration options for markup template generation.

47

48

```java { .api }

49

/**

50

* Configuration options for MarkupTemplateEngine

51

*/

52

public class TemplateConfiguration {

53

/**

54

* Creates a new TemplateConfiguration with default settings

55

*/

56

public TemplateConfiguration();

57

58

/**

59

* Creates a copy of an existing TemplateConfiguration

60

* @param that configuration to copy

61

*/

62

public TemplateConfiguration(TemplateConfiguration that);

63

64

// XML Declaration Configuration

65

public String getDeclarationEncoding();

66

public void setDeclarationEncoding(String declarationEncoding);

67

68

// Element Formatting

69

public boolean isExpandEmptyElements();

70

public void setExpandEmptyElements(boolean expandEmptyElements);

71

72

// Attribute Quoting

73

public boolean isUseDoubleQuotes();

74

public void setUseDoubleQuotes(boolean useDoubleQuotes);

75

76

// Line Handling

77

public String getNewLineString();

78

public void setNewLineString(String newLineString);

79

80

// Content Processing

81

public boolean isAutoEscape();

82

public void setAutoEscape(boolean autoEscape);

83

84

// Indentation Control

85

public boolean isAutoIndent();

86

public void setAutoIndent(boolean autoIndent);

87

public String getAutoIndentString();

88

public void setAutoIndentString(String autoIndentString);

89

90

// Newline Management

91

public boolean isAutoNewLine();

92

public void setAutoNewLine(boolean autoNewLine);

93

94

// Template Base Class

95

public Class<? extends BaseTemplate> getBaseTemplateClass();

96

public void setBaseTemplateClass(Class<? extends BaseTemplate> baseTemplateClass);

97

98

// Internationalization

99

public Locale getLocale();

100

public void setLocale(Locale locale);

101

102

// Performance

103

public boolean isCacheTemplates();

104

public void setCacheTemplates(boolean cacheTemplates);

105

}

106

```

107

108

### Base Template Class

109

110

Abstract base class providing utility methods for markup generation.

111

112

```java { .api }

113

/**

114

* Base class for all markup templates providing utility methods for markup generation.

115

* Thread-safe when using distinct instances per thread/document.

116

*/

117

public abstract class BaseTemplate implements Writable {

118

/**

119

* Constructor for base template

120

* @param templateEngine the markup template engine

121

* @param model data model for template

122

* @param modelTypes type information for model properties

123

* @param configuration template configuration

124

*/

125

public BaseTemplate(MarkupTemplateEngine templateEngine, Map model, Map<String,String> modelTypes, TemplateConfiguration configuration);

126

127

/**

128

* Get the template data model

129

* @return Map containing template data

130

*/

131

public Map getModel();

132

133

/**

134

* Execute the template logic

135

* @return result of template execution

136

*/

137

public abstract Object run();

138

139

/**

140

* Render object with XML escaping for safe output

141

* @param obj object to render

142

* @return this template instance for chaining

143

* @throws IOException if output fails

144

*/

145

public BaseTemplate yield(Object obj) throws IOException;

146

147

/**

148

* Render object without escaping (raw output)

149

* @param obj object to render unescaped

150

* @return this template instance for chaining

151

* @throws IOException if output fails

152

*/

153

public BaseTemplate yieldUnescaped(Object obj) throws IOException;

154

155

/**

156

* Create string representation of closure output

157

* @param cl closure to execute and capture output

158

* @return string representation of closure output

159

* @throws IOException if output fails

160

*/

161

public String stringOf(Closure cl) throws IOException;

162

163

/**

164

* Render XML comment

165

* @param cs comment content

166

* @return this template instance for chaining

167

* @throws IOException if output fails

168

*/

169

public BaseTemplate comment(Object cs) throws IOException;

170

171

/**

172

* Render XML declaration

173

* @return this template instance for chaining

174

* @throws IOException if output fails

175

*/

176

public BaseTemplate xmlDeclaration() throws IOException;

177

178

/**

179

* Render processing instruction

180

* @param attrs attributes for processing instruction

181

* @return this template instance for chaining

182

* @throws IOException if output fails

183

*/

184

public BaseTemplate pi(Map<?, ?> attrs) throws IOException;

185

186

/**

187

* Handle dynamic method calls for tag generation

188

* @param tagName name of the tag

189

* @param args tag arguments

190

* @return tag output

191

* @throws IOException if output fails

192

*/

193

public Object methodMissing(String tagName, Object args) throws IOException;

194

195

/**

196

* Include another Groovy template

197

* @param templatePath path to template to include

198

* @throws IOException if template loading or rendering fails

199

* @throws ClassNotFoundException if template class cannot be found

200

*/

201

public void includeGroovy(String templatePath) throws IOException, ClassNotFoundException;

202

203

/**

204

* Include template with escaped output

205

* @param templatePath path to template to include

206

* @throws IOException if template loading or rendering fails

207

*/

208

public void includeEscaped(String templatePath) throws IOException;

209

210

/**

211

* Include template with unescaped output

212

* @param templatePath path to template to include

213

* @throws IOException if template loading or rendering fails

214

*/

215

public void includeUnescaped(String templatePath) throws IOException;

216

217

/**

218

* Try to escape content if auto-escape is enabled

219

* @param contents content to potentially escape

220

* @return escaped or original content

221

*/

222

public Object tryEscape(Object contents);

223

224

/**

225

* Get the output writer

226

* @return the writer for template output

227

*/

228

public Writer getOut();

229

230

/**

231

* Write a newline to output

232

* @throws IOException if write fails

233

*/

234

public void newLine() throws IOException;

235

236

/**

237

* Create template fragment from inline template text

238

* @param model data model for fragment

239

* @param templateText template source text

240

* @return fragment output

241

* @throws IOException if rendering fails

242

* @throws ClassNotFoundException if template class cannot be found

243

*/

244

public Object fragment(Map model, String templateText) throws IOException, ClassNotFoundException;

245

246

/**

247

* Apply layout template

248

* @param model data model for layout

249

* @param templateName name of layout template

250

* @return layout output

251

* @throws IOException if rendering fails

252

* @throws ClassNotFoundException if template class cannot be found

253

*/

254

public Object layout(Map model, String templateName) throws IOException, ClassNotFoundException;

255

256

/**

257

* Apply layout template with optional model inheritance

258

* @param model data model for layout

259

* @param templateName name of layout template

260

* @param inheritModel whether to inherit current model

261

* @return layout output

262

* @throws IOException if rendering fails

263

* @throws ClassNotFoundException if template class cannot be found

264

*/

265

public Object layout(Map model, String templateName, boolean inheritModel) throws IOException, ClassNotFoundException;

266

267

/**

268

* Define content section for layout

269

* @param cl closure defining content

270

* @return content closure

271

*/

272

public Closure contents(Closure cl);

273

}

274

```

275

276

**Usage Examples:**

277

278

```java

279

import groovy.text.markup.MarkupTemplateEngine;

280

import groovy.text.markup.TemplateConfiguration;

281

import groovy.text.Template;

282

import java.util.Map;

283

import java.util.HashMap;

284

import java.util.Locale;

285

286

// Basic usage with default configuration

287

MarkupTemplateEngine engine = new MarkupTemplateEngine();

288

289

// Advanced configuration

290

TemplateConfiguration config = new TemplateConfiguration();

291

config.setAutoIndent(true);

292

config.setAutoIndentString(" "); // 4 spaces

293

config.setAutoNewLine(true);

294

config.setAutoEscape(true);

295

config.setUseDoubleQuotes(true);

296

config.setExpandEmptyElements(false);

297

config.setDeclarationEncoding("UTF-8");

298

config.setLocale(Locale.ENGLISH);

299

300

MarkupTemplateEngine configuredEngine = new MarkupTemplateEngine(config);

301

302

// Markup template using Groovy markup DSL

303

String template = """

304

html {

305

head {

306

title(pageTitle)

307

meta(charset: 'UTF-8')

308

}

309

body {

310

h1(pageTitle)

311

div(class: 'content') {

312

p("Welcome, \${user.name}!")

313

ul {

314

items.each { item ->

315

li(item.name)

316

}

317

}

318

}

319

}

320

}

321

""";

322

323

Template compiledTemplate = engine.createTemplate(template);

324

325

Map<String, Object> model = new HashMap<>();

326

model.put("pageTitle", "My Page");

327

328

Map<String, String> user = new HashMap<>();

329

user.put("name", "John Doe");

330

model.put("user", user);

331

332

List<Map<String, String>> items = Arrays.asList(

333

Collections.singletonMap("name", "Item 1"),

334

Collections.singletonMap("name", "Item 2"),

335

Collections.singletonMap("name", "Item 3")

336

);

337

model.put("items", items);

338

339

String result = compiledTemplate.make(model).toString();

340

```

341

342

### Markup DSL Syntax

343

344

MarkupTemplateEngine uses a Groovy-based DSL for generating markup:

345

346

#### Basic Element Creation

347

```groovy

348

// Template syntax

349

html {

350

head {

351

title('My Page')

352

}

353

body {

354

h1('Welcome')

355

p('This is a paragraph')

356

}

357

}

358

```

359

360

#### Elements with Attributes

361

```groovy

362

// Elements with attributes

363

div(class: 'container', id: 'main') {

364

img(src: '/images/logo.png', alt: 'Logo')

365

a(href: 'https://example.com', target: '_blank', 'Click here')

366

}

367

368

// Empty elements

369

input(type: 'text', name: 'username', placeholder: 'Enter username')

370

br()

371

hr()

372

```

373

374

#### Variable Substitution

375

```groovy

376

// Using variables from model

377

h1(pageTitle)

378

p("Welcome, ${user.name}!")

379

380

// Conditional content

381

if (user.isAdmin) {

382

div(class: 'admin-panel') {

383

p('Admin controls')

384

}

385

}

386

```

387

388

#### Loops and Iteration

389

```groovy

390

// Iterating over collections

391

ul {

392

items.each { item ->

393

li {

394

a(href: item.url, item.title)

395

}

396

}

397

}

398

399

// With index

400

ol {

401

products.eachWithIndex { product, index ->

402

li("${index + 1}. ${product.name} - \$${product.price}")

403

}

404

}

405

```

406

407

### Configuration Options

408

409

#### Auto-Indentation

410

```java

411

TemplateConfiguration config = new TemplateConfiguration();

412

config.setAutoIndent(true);

413

config.setAutoIndentString(" "); // 2 spaces (default)

414

// config.setAutoIndentString("\t"); // Use tabs

415

// config.setAutoIndentString(" "); // 4 spaces

416

```

417

418

#### Auto-Escaping

419

```java

420

config.setAutoEscape(true); // Automatically escape content for XML safety

421

```

422

423

#### Element Formatting

424

```java

425

// Control empty element format

426

config.setExpandEmptyElements(false); // <br/> (default)

427

config.setExpandEmptyElements(true); // <br></br>

428

429

// Control attribute quotes

430

config.setUseDoubleQuotes(false); // class='container' (default)

431

config.setUseDoubleQuotes(true); // class="container"

432

```

433

434

#### Line Handling

435

```java

436

config.setAutoNewLine(true); // Automatically add newlines

437

config.setNewLineString("\n"); // Unix line endings (default)

438

config.setNewLineString("\r\n"); // Windows line endings

439

```

440

441

#### XML Declaration

442

```java

443

config.setDeclarationEncoding("UTF-8"); // Adds <?xml version="1.0" encoding="UTF-8"?>

444

```

445

446

### Template Caching

447

448

MarkupTemplateEngine supports template caching for improved performance:

449

450

```java

451

TemplateConfiguration config = new TemplateConfiguration();

452

config.setCacheTemplates(true); // Enable caching (default)

453

454

MarkupTemplateEngine engine = new MarkupTemplateEngine(config);

455

456

// Templates are automatically cached and reused

457

Template template1 = engine.createTemplate(templateSource);

458

Template template2 = engine.createTemplate(templateSource); // Returns cached version

459

```

460

461

### Custom Base Template

462

463

Extend BaseTemplate to add custom utility methods:

464

465

```java

466

public class MyCustomTemplate extends BaseTemplate {

467

public MyCustomTemplate(MarkupTemplateEngine engine, Map model,

468

Map<String,String> modelTypes, TemplateConfiguration config) {

469

super(engine, model, modelTypes, config);

470

}

471

472

// Custom helper method

473

public MyCustomTemplate formatCurrency(double amount) throws IOException {

474

yield(String.format("$%.2f", amount));

475

return this;

476

}

477

478

// Custom helper for dates

479

public MyCustomTemplate formatDate(Date date) throws IOException {

480

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

481

yield(formatter.format(date));

482

return this;

483

}

484

}

485

486

// Configure engine to use custom base template

487

TemplateConfiguration config = new TemplateConfiguration();

488

config.setBaseTemplateClass(MyCustomTemplate.class);

489

MarkupTemplateEngine engine = new MarkupTemplateEngine(config);

490

```

491

492

### Template Resolver

493

494

Interface for custom template path resolution.

495

496

```java { .api }

497

/**

498

* Interface for resolving template paths to URLs

499

*/

500

public interface TemplateResolver {

501

/**

502

* Configure the resolver with class loader and template configuration

503

* @param templateClassLoader class loader for template compilation

504

* @param configuration template configuration settings

505

*/

506

void configure(ClassLoader templateClassLoader, TemplateConfiguration configuration);

507

508

/**

509

* Resolve template path to URL

510

* @param templatePath path to resolve

511

* @return URL for the template resource

512

* @throws IOException if template cannot be found or accessed

513

*/

514

URL resolveTemplate(String templatePath) throws IOException;

515

}

516

```

517

518

**Built-in Resolvers:**

519

520

```java { .api }

521

/**

522

* Default template resolver that searches classpath

523

*/

524

public static class DefaultTemplateResolver implements TemplateResolver {

525

public DefaultTemplateResolver();

526

public void configure(ClassLoader templateClassLoader, TemplateConfiguration configuration);

527

public URL resolveTemplate(String templatePath) throws IOException;

528

}

529

530

/**

531

* Caching template resolver for improved performance

532

*/

533

public static class CachingTemplateResolver extends DefaultTemplateResolver {

534

public CachingTemplateResolver(Map<String, URL> cache);

535

public CachingTemplateResolver();

536

public void configure(ClassLoader templateClassLoader, TemplateConfiguration configuration);

537

public URL resolveTemplate(String templatePath) throws IOException;

538

}

539

```

540

541

**Usage Example:**

542

543

```java

544

public class MyTemplateResolver implements TemplateResolver {

545

@Override

546

public void configure(ClassLoader templateClassLoader, TemplateConfiguration configuration) {

547

// Initialize resolver with classloader and configuration

548

}

549

550

@Override

551

public URL resolveTemplate(String templatePath) throws IOException {

552

// Custom logic for resolving template paths

553

return getClass().getResource("/templates/" + templatePath);

554

}

555

}

556

557

MyTemplateResolver resolver = new MyTemplateResolver();

558

MarkupTemplateEngine engine = new MarkupTemplateEngine(

559

getClass().getClassLoader(),

560

new TemplateConfiguration(),

561

resolver

562

);

563

```

564

565

### Type Checking

566

567

MarkupTemplateEngine includes compile-time type checking:

568

569

```java

570

// Templates are type-checked at compile time

571

String template = """

572

html {

573

body {

574

// This would cause a compile-time error if 'user' is not defined in model

575

p("Hello \${user.name}")

576

}

577

}

578

""";

579

580

// Type information can be provided for better checking

581

Map<String, String> modelTypes = new HashMap<>();

582

modelTypes.put("user", "User"); // Specify that 'user' is of type 'User'

583

```

584

585

### Advanced Features

586

587

#### Template Resource

588

589

Utility class for template path resolution with locale support.

590

591

```java { .api }

592

/**

593

* Represents a template resource with optional locale support

594

*/

595

public static class TemplateResource {

596

/**

597

* Parse a template path into a TemplateResource

598

* @param fullPath the full template path

599

* @return parsed TemplateResource

600

*/

601

public static TemplateResource parse(String fullPath);

602

603

/**

604

* Create variant with specific locale

605

* @param locale locale to use

606

* @return TemplateResource with locale

607

*/

608

public TemplateResource withLocale(String locale);

609

610

/**

611

* Check if this resource has a locale

612

* @return true if locale is specified

613

*/

614

public boolean hasLocale();

615

616

/**

617

* String representation of the resource path

618

* @return string representation

619

*/

620

public String toString();

621

}

622

```

623

624

#### Include Type Support

625

```java { .api }

626

/**

627

* Enumeration for different template inclusion types

628

*/

629

public enum IncludeType {

630

template("includeGroovy"),

631

escaped("includeEscaped"),

632

unescaped("includeUnescaped");

633

634

/**

635

* Get the method name for this include type

636

* @return method name

637

*/

638

public String getMethodName();

639

}

640

```

641

642

### Delegating Indent Writer

643

644

Writer that provides automatic indentation support for template output.

645

646

```java { .api }

647

/**

648

* Writer that delegates to another writer and provides indentation support

649

*/

650

public class DelegatingIndentWriter extends Writer {

651

public static final String SPACES = " ";

652

public static final String TAB = "\t";

653

654

/**

655

* Create indent writer with default spaces indentation

656

* @param delegate writer to delegate to

657

*/

658

public DelegatingIndentWriter(Writer delegate);

659

660

/**

661

* Create indent writer with custom indentation

662

* @param delegate writer to delegate to

663

* @param indentString string to use for indentation

664

*/

665

public DelegatingIndentWriter(Writer delegate, String indentString);

666

667

/**

668

* Increase indentation level

669

* @return new indentation level

670

*/

671

public int next();

672

673

/**

674

* Decrease indentation level

675

* @return new indentation level

676

*/

677

public int previous();

678

679

/**

680

* Write current indentation to output

681

* @throws IOException if write fails

682

*/

683

public void writeIndent() throws IOException;

684

685

// Writer methods (inherited)

686

public void write(int c) throws IOException;

687

public void write(char[] cbuf) throws IOException;

688

public void write(char[] cbuf, int off, int len) throws IOException;

689

public void write(String str) throws IOException;

690

public void write(String str, int off, int len) throws IOException;

691

public Writer append(CharSequence csq) throws IOException;

692

public Writer append(CharSequence csq, int start, int end) throws IOException;

693

public Writer append(char c) throws IOException;

694

public void flush() throws IOException;

695

public void close() throws IOException;

696

}

697

```

698

699

### Error Handling

700

701

MarkupTemplateEngine provides comprehensive error handling:

702

703

```java

704

try {

705

MarkupTemplateEngine engine = new MarkupTemplateEngine();

706

Template template = engine.createTemplate(templateSource);

707

String result = template.make(model).toString();

708

} catch (CompilationFailedException e) {

709

// Template compilation failed due to syntax errors

710

System.err.println("Compilation error: " + e.getMessage());

711

} catch (ClassNotFoundException e) {

712

// Missing dependencies or custom base template class

713

System.err.println("Class not found: " + e.getMessage());

714

} catch (IOException e) {

715

// I/O error reading template source

716

System.err.println("I/O error: " + e.getMessage());

717

} catch (Exception e) {

718

// Runtime errors during template execution

719

System.err.println("Runtime error: " + e.getMessage());

720

}

721

```

722

723

### Best Practices

724

725

1. **Configuration Reuse**: Create TemplateConfiguration once and reuse across engine instances

726

2. **Template Caching**: Enable caching for frequently used templates

727

3. **Thread Safety**: Use separate template instances per thread

728

4. **Custom Base Templates**: Extend BaseTemplate for application-specific helpers

729

5. **Type Safety**: Leverage compile-time type checking for robust templates

730

6. **Performance**: Use MarkupTemplateEngine for high-performance markup generation

731

7. **Memory Management**: Let unused templates be garbage collected