Templates are documents that describe an output format such as HTML. They allow the ultimate representation of a data structure (or "data dictionary") to be specified independently of the data itself, promoting a clear separation of responsibility.
Template documents include "markers" that are replaced with values provided by the data dictionary when the template is processed:
- {{variable}} - injects a value from the data dictionary into the output
- {{?section}}...{{/section}} - defines a conditional section
- {{#section}}...{{/section}} - defines a repeating section
- {{^section}}...{{/section}} - defines an inverted section
- {{$resource}} - injects a value from the resource bundle into the output
- {{>include}} - imports content from another template
- {{!comment}} - provides non-rendered informational content
Each of these marker types is discussed in more detail below.
Variable markers inject a named value from the data dictionary into the output. For example:
<p>Count: {{count}}</p>
<p>Sum: {{sum}}</p>
<p>Average: {{average}}</p>
Variable names represent keys into the data dictionary. When the template is processed, the markers are replaced with the corresponding values from the dictionary. When traversing sections, dictionary values are recursively inherited. If a value is not provided by the current dictionary or any of its parents, it is excluded from the generated output.
Nested values can be referred to by path; e.g. "name/first". A literal slash or backslash character can be used in a variable or section name by escaping it with a leading backslash.
The reserved "~" and "." variable names represent key and value references, respectively, and are discussed in more detail below.
Modifiers are used to transform a variable's representation before it is written to the output stream. They are specified as shown below, and are invoked in declaration order (from left to right). An optional argument value may be included to provide additional information to the modifier:
{{variable:modifier1:modifier2:modifier3=argument:...}}
All templates support the format
modifier, which applies a format string:
{{value:format=0x%04x}}
Applications may also define their own custom modifiers.
In addition to printf()
-style formatting, the format
modifier also supports the following arguments for locale-specific formatting of numbers and dates/times:
currency
- applies a currency formatpercent
- applies a percentage formatshortDate
- applies a short date formatmediumDate
- applies a medium date formatlongDate
- applies a long date formatfullDate
- applies a full date formatisoDate
- applies an ISO date formatshortTime
- applies a short time formatmediumTime
- applies a medium time formatlongTime
- applies a long time formatfullTime
- applies a full time formatisoTime
- applies an ISO time formatshortDateTime
- applies a short date/time formatmediumDateTime
- applies a medium date/time formatlongDateTime
- applies a long date/time formatfullDateTime
- applies a full date/time formatisoDateTime
- applies an ISO date/time format
For example, this marker transforms a date value into a medium-length, localized date string:
{{date:format=mediumDate}}
Date/time values may be represented by one of the following:
- a numeric value representing epoch time in milliseconds
- an instance of
java.util.Date
- an instance of
java.util.time.TemporalAccessor
Conditional section markers define a section of content that is only rendered if the named value exists in the data dictionary. When the value exists, it is used as the data dictionary for the section. Additionally, for Iterable
content, the named sequence must contain at least one value. For booleans, the value must be true
.
For example, given the following data dictionary:
{
"name": {
"first": "John",
"last": "Smith"
}
}
the content of the "name" section in this template would be included in the generated output, but the content of the "age" section would not. The section markers are enclosed in comments so they will be ignored by syntax-aware text editors, and will simply resolve to empty comment blocks when the template is processed:
<!-- {{?name}} -->
<p>Name: {{last}}, {{first}}</p>
<!-- {{/name}} -->
<!-- {{?age}} -->
<p>Age: {{.}}</p>
<!-- {{/age}} -->
Repeating section markers define a section of content that is repeated once for every element in a sequence of values. The marker name must refer to an instance of either Iterable
or java.util.Map
in the data dictionary. The elements of the sequence provide the data dictionaries for successive iterations through the section.
For example, a data dictionary that contains information about homes for sale might look like this:
{
"properties": [
{
"streetAddress": "217 Botshabelo Place",
"listPrice": 695000,
"numberOfBedrooms": 3,
"numberOfBathrooms": 1
},
{
"streetAddress": "1531 Salé Drive",
"listPrice": 475000,
"numberOfBedrooms": 2,
"numberOfBathrooms": 1.5
},
...
]
}
A template to transform these results into HTML is shown below:
<table>
<!-- {{#properties}} -->
<tr>
<td>{{streetAddress}}</td>
<td>{{listPrice:format=currency}}</td>
<td>{{numberOfBedrooms}}</td>
<td>{{numberOfBathrooms}}</td>
</tr>
<!-- {{/properties}} -->
</table>
Section markers may specify an optional separator string that will be automatically injected between the section's elements. The separator text is enclosed in square brackets immediately following the section name.
For example, the elements of the "names" section specified below will be separated by a comma in the generated output:
{{#names[,]}}
...
{{/names}}
In most cases, variable names are used to refer to properties of the Map
instance representing the current data dictionary. However, when traversing the contents of a Map
sequence, the reserved "~" variable can be used to refer to the key associated with the current element.
Additionally, when traversing any type of sequence (whether Iterable
or Map
), if the current element is not a Map
(for example, a Number
, String
, or Iterable
), the reserved "." variable can be used to refer to the value of the element itself.
For example, the following data dictionary associates a set of number names with their corresponding numeric values:
{
"numbers": {
"one": 1,
"two": 2,
"three": 3
}
}
This template could be used to generate a comma-separated list of name/value pairs from the data dictionary:
{{#numbers[,]}}{{~}}:{{.}}{{/numbers}}
Inverted section markers define a section of content that is only rendered if the named value does not exist in the data dictionary. Additionally, for Iterable
content, the named sequence must be empty. For booleans, the value must be false
.
For example, given the following data dictionary:
{
"addresses": [
]
}
this template would produce the text "no addresses":
{{^addresses}}no addresses{{/addresses}}
Resource markers inject a named value from the resource bundle into the output. For example:
<p>{{$count}}: {{count}}</p>
<p>{{$sum}}: {{sum}}</p>
<p>{{$average}}: {{average}}</p>
When the template is processed, the markers are replaced with the corresponding values from the resource bundle; for example:
count = Count
sum = Sum
average = Average
Include markers import content defined by another template. They can be used to create reusable content modules, such as document headers or footers.
For example, the following template, hello.txt, includes another document named world.txt:
Hello, {{>world.txt}}!
When hello.txt is processed, the include marker will be replaced with the contents of world.txt. For example, if world.txt contains the text "World", the result of processing hello.txt would be the following:
Hello, World!
Includes inherit their context from the parent document, so they can refer to elements in the parent's data dictionary. This allows includes to be parameterized. Self-referencing includes can also be used to facilitate recursion.
Comment markers provide informational text about a template's content. They are not included in the final output.
For example, when the following template is processed, only the content between the <p>
tags will be included:
{{! Some placeholder text }}
<p>Lorem ipsum dolor sit amet.</p>