ST condensed -- Templates and expressions

Contents

Overview

This article attempts to cover and update (2009-06) all the material in the users guide Expressions article and the current Cheat-Sheet's Expressions section.

StringTemplate object, attributes, template text and expressions

As shown in the previous article, the StringTemplate object has the following features:

  • Attributes: Values, or references to data items in the calling program, which will be supplied to expressions during the template rendering process.
  • Template text: Consists of alternating:
    • Literal text: Text which will be copied directly to the result text
    • Expressions: which obtain values from the StringTemplate's attributes, and, with some processing, insert strings into the result text.

Expression delimiters: $...$ or <...>

StringTemplate can recognize a choice of different delimiters around expressions, with $...$ and <...> being the two built-in alternatives. (The choice must be set by the calling program before invoking a template.)  Be aware that documentation might show examples with either expression delimiter, $...$ or <...>.

Example template text with $..$ expression delimiters:

blah blah blah $an expression$ blah blah blah $an expression$
blah blah blah $an expression$ blah blah blah 

Example template text with <..> expression delimiters:

blah blah blah <an expression> blah blah blah <an expression>
blah blah blah <an expression> blah blah blah 

Where might you deal with template texts?

The same template text might come into play in several different places in an application that uses the StringTemplate library:

  • As a String in the calling language: Your application might create the template text as a string, and pass it to one of the StringTemplate constructors or StringTemplateGroup methods that create a StringTemplate.
  • In a template file -- xxx.st  You might provide templates in individual xxx.st files. The filename (minus ".st") provides the template name.
  • In a template group file -- xxx.stg: You might provide one or more xxx.stg files, which can define several templates. The template definitions in stg files use the same syntax for the template text per se, but add additional surrounding syntax to provide the template a name, and to declare formal arguments.
  • Within a template expression: The expression syntax includes the capability to define and invoke a (usually small) template on-the-spot within an expression. Once again the same syntax is used within the template text itself, but there is additional expression syntax around it, including the ability to specify arguments.

Simple templates

The following example illustrates a couple of simple templates. Note use of alternative expression delimiters.

 

Example: Apply html bold-italic to a string

Example: Format some personal info

Template
text:

<b><i>$sometext$</i><b>
Name: <personname>
Address: <addr>
Phone: <phonenum>

Attributes supplied:

sometext = "Hello"

personname = "Fred Smith"
addr = "123 First St."
phonenum = "123-4567"

Result from
toString()

<b><i>Hello</i><b>

Name: Fred Smith
Address: 123 First St.
Phone: 123-4567

The template texts shown here could be provided as a string when creating a StringTemplate calling a StringTemplate constructor. Alternatively, the template text could be provided from a file, perhaps bold-italic.st, or personalinfo.st, for the examples here.

Templates defined in a string template group file

This example shows a snippet from a string template group file (xxx.stg). It's the definition of a template called personalinfo(), which has the same template text as the preceding example, but declares three formal arguments.

personalinfo(personname,addr,phonenum) ::= <<
Name: <personname>
Address: <addr>
Phone: <phonenum>
>>

Here again either <...> or $...$ can be used for the expression delimiters within the template text (matching whatever the corresponding StringTemplate object is set to recognize). Note that this is a separate issue from the <<...>> delimiters around the overall template text -- there is no alternative for these. The formal arguments and the <<...>>> delimiters are syntax particular to xxx.stg files, and are not allowed in individual xxx.st files.

Expressions Overview

The basic idea

Expressions:

  • make use of some input data, ultimately from attributes supplied to the StringTemplate object by the calling program
  • perform some processing
  • always return a string (or nothing)

It is possible to create very elaborate expressions, but at heart an expression has the following basic structure.

There are three basic parts, and they are each optional. By using or not using each part, expressions can serve various purposes. It is useful to distinguish two main varieties of expression:

  • Expressions with no template section
  • Expressions with a template section

The following sections give a general overview of these varieties of expressions. The syntax is spelled out in detail in a section "Table of Template Expressions and Statements" below.

Expressions containing no template section

This category covers the forms of expression like the following:

  • <attribname>
  • <attribname.propname>
  • <attribname; options>
  • ... and similar.

These are the forms of expression where an attribute is actually read from the calling program and turned into a string, as sketched in the following diagram.

Note that in StringTemplate there are no local variables, nor any calculations based on attribute values, except for map lookup. Consequently, all values come directly from attributes or maps, positioned in the flow of result text by these no-template expressions.

The options section controls formatting of the string result.

  • If the attribute is already a string, it is returned as is (or as influenced by options) from this expression.
  • If the attribute is some other simple type, like integer, then its AsString() method is called to obtain a string
  • If the attribute refers to a list, then each of its items is individually turned into a string and concatenated to produce a result string. (An option can specify a separator to place between the items as they are concatenated).
  • If attribname refers to an object, and propname is also specified, then StringTemplate looks for a property corresponding to propname on the object supplied.
  • If attribname refers to a map object, then propname is used to "look up" that name in the map's key list, and return the corresponding value.

Expressions containing a template section

This category covers the forms of expression like the following:

<templatename()>
<attribname:other_template_name()>
<attribname:{template text}>
... and similar. (An option section may be present too.)

In these cases, the inner template obtains inputs either from the attribute specified by attribname, or from the surrounding template (or both). Where there is an attribname section, the template is said to be "applied to" this attribute. The following diagram summarizes:

Notes:

  • Attributes and Late stringification
    • The varieties of attributes/properties/maps which may be specified in the "select attrib(s)" section are as described above for the no-template expressions.
    • Attributes are passed into, or available to, the inner template without turning them into strings.
    • To make use of an attribute, ultimately, the inner template (or a template that it in turn invokes) has to have an expression of the no-template variety to convert the attribute to a string.
  • Iteration
    • If the attribute or property specifies a list, then the inner template is applied to each item in the list separately. That is to say, the inner template is invoked multiple times, each time supplying an item from the list. This will result in multiple returned strings from the inner template, which during render will be concatenated to form the outer template's result (possibly with a separator specified in options.)

Exact details of how attributes are passed to inner templates will be covered in sections below.

Variations for each part of an expression

The following table summarizes the variations available for each of the three sections of the expression. Remember that if the template part is present, the "specify attribute(s)" part supplies attributes to the template. If the template part is not present, the "specify attribute(s)" part selects attributes to be transformed and possibly concatenated into a single result string.

Select attribute(s) part

Template(s) part

Options part

  • Select an attribute (of the template)
  • Select a property of an object attribute
  • Select an attribute's property based on an expression
  • Select a value from a map
  • Look up an attribute value in a map
  • Select or create a list over which to iterate a template
  • Select or create multiple parallel lists over which to iterate a multi-argument template
  • Select or create a subset of a list (using operators)
  • Invoke a named template defined elsewhere in the group, or supergroup.
  • ... or define a template on-the-spot ("anonymous" template), and apply it.
  • Apply the template(s) to attributes from the "select attributes" part of the expression.
    • If the selected attributes are lists, invoke the template(s) for each item.
    • Selected attributes may be multiple parallel lists, with an item from each list supplied to each of multiple template arguments, for each iteration.
  • A template can also refer directly to attributes in the context of the containing template.
  • Multiple templates can be chained, passing results from one to the next (using colon syntax).
  • Multiple templates can be alternated, with a different template applied to successive items in a list (using comma syntax)

Mostly controls formatting of the string result of the template

  • Indent
  • Wrap
  • Separator between list items
  • What string to substitute for a value that's null
  • Passing options to a FormatRenderer

Examples

Template Expressions and Statements

Documentation conventions

One of the significant challenges in describing syntax is to clearly distinguish between the following:

  • Parts of the syntax you type in verbatim. These are in typewriter font, non-italic ("upright").
  • Parts that are to be replaced by your own attribute names and so on. These are in italic typewriter font.
  • Almost no symbolsthat are not part of the syntax. (Some authors might use square brackets to indicate optional syntax, for example). The only such syntax on this page is the elipsis "...", used to indicate "fill in the usual stuff here". (Except where the elipsis is actually part of expression syntax, which is clearly noted.)

Symbol guide

Symbol

Meaning

 

Symbol

Meaning

attrname

Attribute name

 

tmpname

Name of a template to be called from this one
(defined elsewhere in the current template's group)

expr

An expression. Do not surround with delimiters when expr appears directly within an expression (as opposed to within a template.)

 

argname

Name of an argument of a template to be called from this one

propname

Name of a property of an attribute

 

args

Shorthand for argname=expr, argname2=expr2

mapname

Name of a map

 

tmptext

Text of a template defined within an expression "on-the-spot" ("Anonymous" template.)

itemname

Name of an item in a map

 

 

 

Table of Template Expressions and Statements

_Wiki note: The following table is included from a separate html file as the many collisions between StringTemplate expression syntax and wiki markup syntax make editing in the wiki impractical.

Summary of expression options

The following table summarizes options that may be placed in an expression, following a semicolon:

<blahblah;option1,option2>.  Example: <SomeAttrib;separator=", ", null="blank">

Option

Description

separator="sep

If multi-values are emitted from this expression, catenate them with separator between

format="formatstr

String to pass to an AttributeRenderer as an argument specifying format details. (Specific formatstr strings are determined by whatever is recognized by the particular renderer.)

null="somestr

For each null element in the input attribute, insert this string in the result.

wrap 

Tell StringTemplate to wrap the output string if it exceeds the wrap length set in StringTemplate.toString(wraplen);.  (Note, no "=true", just the keyword wrap by itself.)

anchor="true" 

If wrapping, then cause wrapped lines to indent so that they align with beginning of the first line of this template's output.

More template details

Template calling behavior

The syntax for defining a template in a string template group file might suggest that when one template invokes another, data is passed only via the arguments, like calling a function in other languages such as Java.  However this is misleading.

In actuality, when one template invokes another, StringTemplate passes the context of the caller to the called template. That is to say, not only does the called template get its arguments "filled in", but also the called template's expressions can see and refer to the attributes or arguments that are in the scope of the caller template. This behavior is much more like C macros, or like closures in some other languages.

User guide article Template and attribute lookup rules has the details, but in summary, StringTemplate follows the order below in resolving attribute names in expressions:

  1. Look in this template's attribute table (applies if template is invoked directly by program code).
  2. Look in this template's arguments (applies if template is invoked by another template.)
  3. Look recursively up the chain of this template's calling templates for arguments/attributes that match
  4. Look recursively up the chain of this template's group / supergroup inheritance chain for a map

A further wrinkle is that a template's argument list normally "hides" any attribute or argument of the same name in the caller template's scope. For variations on how to subvert this, see the "..." expression syntax, and also StringTemplate.setPassThroughAttributes().

String Formatting

StringTemplate provides no built-in string formatting functions per se, such as string truncate, or left/right pad, or number formatting. Instead, the application must provide data to an attribute as an already-formatted string, or the calling program can attach AttributeRenderer objects to provide formatting capabilites to the template world. This is done through the AttributeRenderer features. An application may attach AttributeRenderers to a StringTemplate which apply to specific attribute datatypes or classes of objects. When an object of such a type or class is supplied as an attribute to a StringTemplate, the related AttributeRenderer will be invoked when the template gets rendered.

AttributeRenderers may be designed to accept arguments from the template expression: The template expression provides these through the format option. (See Expression sytax table).

The AttributeRenderer for the String type is special: This will be invoked not just for String attributes, but also for inner template results (which return a string).  You can consider creating and attaching an AttributeRenderer which provides generally-useful string functions. (Someone should write a how-to on this. There's an example in John Snyder's STST.)

Supplying attributes, revisited

When a template is prepared by an application, part of the process involves supplying Attributes (named values) using the StringTemplate.setAttribute() method (or related). There are several variants on that procedure, detailed here.

Simple String value

Example

MyTemplate.setAttribute("someattrname","somevalue");

... or...

String s = "Blah blah";
MyTemplate.setAttribute("someattrname",s);

Simple non-String value

Example

int x = 123;
MyTemplate.setAttribute("someattrname", x);

Any non-String is converted as need to a String, using that type's toString() method.

List of strings

Example

MyTemplate.setAttribute("names", "Fred");
MyTemplate.setAttribute("names", "Mary");
MyTemplate.setAttribute("names", "Chris");

Calling setAttribute multiple times with the same attribute name causes that attribute to hold a list.

Aggregate type

An object with multiple fields (properties) can be passed as an attribute.

user.setUname("fred");
user.setEmail("fred@jones.com");
...
MyTemplate.setAttribute("userinfo", user);

Template expressions that can access these properties:

User: $userinfo.uname$ has email $userinfo.email$

StringTemplate does this using reflection and following certain rules, depending on the source code language. See the full Expressions article for details.

Aggregate built by addAttribute()

If you want to present data to setAttribute in a structure, but don't already have a suitable aggregate data type, then you can create one in the call to setAttribute, like the following example. This shows how to set multiple properties at once. The values supplied here are string constants, but variables can be supplied too.

MyTemplate.setAttribute("userinfo.{uname, email}", "fred", "fred@jones.com");

Template expressions to access these properties:

User: $userinfo.uname$ has email $userinfo.email$

Map

Another type of attribute value your program can supply is an object that implements the Map interface. Example:

HashMap cust = new HashMap();
cust.put("custname", "fred");
cust.put("phone", "123-4567");
MyTemplate.setAttribute("custinfo", cust);

Template expressions to access these properties:

Customer: $custinfo.custname$ has phone $custinfo.phone$

Next: ST condensed -- File syntax