ST condensed -- Templates and groups

Contents

Overview

The StringTemplate library can be usefully applied in a range of more or less elaborate ways. At the modest end of the spectrum, an application program might just use StringTemplate as part of a structured process to insert a few values into short templates, in turn producing short output strings. The template texts might be provided as strings in the program itself, with no template files involved.  At a grander scale, an application defining famiies of related web pages might use dozens of lengthy templates, stored as a group of files in a directory.  Alternatively a code generator application might employ template-group files that each define a set of templates, with separate group files for different target languages.

In support of this variety of use cases, StringTemplate has features aligned to three somewhat distinct modes of operation.

Three modes of operation

Objects of the StringTemplate and StringTemplateGroup classes can be used in three different modes of operation.  Although most of StringTemplate's concepts are similar across all three modes, there is enough difference between them that it's important to be aware of the distinctions before plunging into the details. The features of the three modes are described below.

Single-template mode

In this mode you are free to define and use many templates from strings or single-template files, but each one operates independently of any others. In this mode, templates cannot refer to each other.

  • Create template,  supplying template text from file or string:  Use one of the StringTemplate constructors
  • Expression delimiters: Default is $...$. Switch to <...> by using the StringTemplate constructor that allows specifying a different lexer.
  • Preparing to invoke a template
    • Use the StringTemplate object returned by the constructor, OR use that template's getInstanceOf() method to make a separate copy.
    • Set attributes

Template-group-directory mode: many *.st files

This mode introduces the idea of a template group, revolving around a StringTemplateGroup object. In template-group directory mode you can define many templates from a collection of single-template files housed in a distinct group directory. These templates can invoke each other to build up complex output. Other features of this mode:

  • Single-template filename pattern: *.st
  • Template name = name of file containing the template text (minus the ".st" extension)
  • When your program explicitly calls for a particular template, StringTemplate automatically searches the group directory and loads  any other templates your template references.
  • Optional periodic automatic refresh of in-memory StringTemplate objects from any template files which have changed.
  • Inheritance: The calling application can set up an inheritance relationship between groups, such that one group can inherit from another group, overriding the inherited templates in various ways.
  • Maps: Your code can define a map, which template expressions can use to translate one set of strings to another.

Template-group-file mode: *.stg file(s)

In this mode, you can define many templates within a single template group file, and again these templates can refer to each other. (Single-template files are not involved.)  Besides the convenience (for some scenarios) of defining many templates within one file, the stg file format introduces more syntax supporting more rigorous processing of templates, and more powerful relationship between template groups:

  • String template group filename pattern: *.stg
  • Group name: defined in initial group statement in stg file. Conventionally this would match the name of the group file (minus the .stg extension)
  • Template name: Templates are named as part of the syntax in the STG file.
  • No automatic refresh: If your application cares about the stg file changing on disk, then it must take explicit steps to reload the stg file when convenient.
  • Template arguments: In stg files, templates are required to declare any attributes that they need to have passed to them. When a template is invoked, StringTemplate checks the template's expressions for invalid attempts to access attributes that were not declared.
    • Aside: Because of "dynamic scope", expressions in templates called by other templates may also get attributes from the calling template as an alternative to arguments. See article Template and attribute lookup rules for details.
  • Maps: Stg files can provide definitions for maps. Maps are useful for translating one list of strings to another.
  • Inheritance: An stg file can declare that this StringTemplateGroup inherits from another StringTemplateGroup. The subgroup STG can add additional templates and maps, and can also override features inherited from the supergroup as follows:
    • Override entire templates: The subgroup stg file can provide a replacement definition for a template that was defined in the supergroup.
    • Override part of a template: Using the "region" feature, the supergroup can mark locations or sections of a template, and the subgroup can override just these sections
    • Override a map
    • Interfaces and implements: An stg file can declare itself to define an interface: A set of template definitions which provide only the template name and argument lists. Another stg file can declare itself to implement that interface, which is a commitment to provide complete templates for each of the ones defined in the interface stg.
Loading of supergroup file

In general, the calling program specifies an explicit path for the stg file to be loaded. If that stg file declares that it's based on some supergroup, then where does StringTemplate find that supergroup?

  • Previously-loaded StringTemplateGroup: This means that the the calling program needs to be aware of which stg inherits from which other one, and load them in an appropriate order.
  • Search and load automatically: The StringTemplate library defines an interface (StringTemplateGroupLoader) for a class that could load referenced string template group files, however no specific implementation is provided. (Is this correct? -- [GW])

Mixing modes

Though the modes were described above separately, there's some leeway to combine them. For example, it's possible to add new individual StringTemplates to a StringTemplateGroup in either of the two TemplateGroup modes, and to have that template's expressions invoke named templates that are members of the group.

Preparation and Invocation in each mode

While reading this section you may wish to consult the StringTemplate API javadocs, or the annotated version here: ST condensed -- API annotated which highlights the most-needed methods.

Single-template mode

In this mode you are free to define and use many templates from strings or single-template files, but each one operates independently of any others. Templates cannot refer to each other.

  • Create StringTemplate,  supplying template text from file or string:  Use one of the StringTemplate constructors
  • Expression delimiters: Default is $...$. Switch to <...> by using the StringTemplate constructor that allows specifying a different lexer.
  • Preparing to invoke a StringTemplate
    • Use the StringTemplate object returned by the constructor, OR if you want to use a template multiple times with different attributes, use StringTemplate.getInstanceOf() to get copies.
    • Supply attributes (named values for the template's expressions), using StringTemplate.setAttribute
      • setAttribute(attrname, value);  Value can be an object of almost any class. A string, or something more complicated that has a toString method. Also it can be an aggregate object, and template expressions can read its properties.
      • Multivalued attributes: Calls setAttribute multiple times for the same attrname gives the attribute a list of values. Template syntax can perform various operations on a list of values.
  • Invocation: Usually using StringTemplate.toString()

Template-group-directory mode: *.st files

  • Create StringTemplateGroup: Use one of the set of StringTemplateGroup constructors whose argument list starts with "name", supplying the directory path that contains the group of string-template files.
    • There is also a constructor which causes the StringTemplateGroup to look for template files relative to the Java CLASSPATH.
  • Expression delimiters: Default is $...$. Switch to <...> by using the StringTemplateGroup constructor that allows specifying a different lexer.
  • Preparing to invoke a StringTemplate
    • Usually you want to treat a StringTemplateGroup as a library of available StringTemplates, to be used possibly several times. Consequently you usually use StringTemplateGroup.getInstanceOf() to get copies of the templates for actual "filling in" with specific attributes/values.
    • Supply attributes: as in Single-template mode, see above.
  • Invocation: Usually using StringTemplate.toString()

Template-group-file mode: *.stg file(s)

  • Create StringTemplateGroup: Use one of the set of StringTemplateGroup constructors whose argument list starts with "Reader r", supplying a FileReader object pointing to the stg file you want to load (Alternatively supply a StringReader with a String containing an stg-worth of text.)
    • Caution: If inheritance or interface implementation is involved, also load the relevant supergroup and interface stg files .
  • Expression delimiters: Default expression delimiter recognized by StringTemplate when reading from stg files is <...>. Switch to $...$ by using the StringTemplateGroup constructor that allows specifying a different lexer.
  • Preparing to invoke a StringTemplate
    • Basically, same as for the template-group-directory mode, except more-rigorous requirements on attributes.
    • Usually you want to treat a StringTemplateGroup as a library of available StringTemplates, to be used possibly several times. Consequently you usually use StringTemplateGroup.getInstanceOf() to get copies of the templates for actual "filling in" with specific attributes/values.
    • Supply attributes: as in Single-template mode, see above.
  • Invocation: Usually using StringTemplate.toString()

Examples: Single template mode

Single template from string

Code

Result

StringTemplate st = new StringTemplate("Hello, $name$");
st.setAttribute("name", "World");
String s = st.toString();

Hello, World

  • Default expression delimiter is $..$

Use an alternative expression delimiter

StringTemplate st = new StringTemplate("Hello, <name>", AngleBracketTemplateLexer.class);

Single template from string, and use an instance

Code

Result

StringTemplate st = new StringTemplate("Hello, $name$");
StringTemplate sti = st.getInstanceOf();
sti.setAttribute("name", "World");
String s = sti.toString();

Hello, World

... and st can be used to create more fresh instances

Single template from file

Same as above, but use usual Java methods to load the template text from a file into a string.

Simple template with multi-valued attribute

Code

Result

String tmpl = "Hello, $arg;separator=\", \"$";
StringTemplate st = new StringTemplate(tmpl);
st.setAttribute("arg", "One");
st.setAttribute("arg", "Two");
String s = st.toString();

Hello, One, Two

Examples: Template-group-directory mode

Insantiate and use a template from a group of files in a template group directory

StringTemplateGroup stg = new StringTemplateGroup("mygroup", "/somepath/mygroupdir");
StringTemplate st = stg.getInstanceOf("mytemplate");
st.setAttribute("arg1","Value1");
String s = st.toString();

/somepath/mygroupdir/mytemplate.st:

Hello, $arg1$

Result: Hello, Value1

Note that the template file did not have to be loaded explicitly. The call to getInstanceOf finds it in the group directory if it hasn't been loaded previously.

Adding a named template from a string

...
tmptext = "Hello, $name$";
newst = stg.defineTemplate("mynewtmp", tmptext);
...

Note: There is also a StringTemplate constructor with a StringTemplateGroup argument. However, there is no provision for a template name in that case. The new template created that way can refer to other templates in the group, but cannot be referred to by them.

Group directories with inheritance

StringTemplateGroup mysuper = new StringTemplateGroup("mysupergrp", "/somepath/master");
StringTemplateGroup mysub = new StringTemplateGroup("mysubgrp" , "/somepath/sub");
mysub.setSuperGroup(mysuper);
....

* A group's supergroup can be set to be set to some other group dynamically, if need be.

  • Contrast the method of setting supergroup shown here versus the inheritance syntax in stg files (below).

Examples: Template-group-file mode

Single stg file

StringTemplateGroup stg = new StringTemplateGroup( new FileReader("/somepath/mygroup.stg") );
StringTemplate st = stg.getInstanceOf("sometmp");
st.setAttribute("arg1","Value1");
String s = st.toString();

Notes:

  • See the separate ST condensed - File syntax article for the format of an stg file.
  • Can use a StringReader to supply stg-format text from a string.
  • Default expression delimiters recognized by StringTemplateGroup are <...>. Can instead invoke StringTemplateGroup constructor with a lexer class argument, and use DefaultTemplateLexer.class.

With supergroup file

StringTemplateGroup stgsuper = new StringTemplateGroup( new FileReader("/somepath/mysuper.stg") );
StringTemplateGroup stg = new StringTemplateGroup( new FileReader("/somepath/mygroup.stg") );
StringTemplate st = stg.getInstanceOf("sometmp");
st.setAttribute("arg1","Value1");
String s = st.toString();

/somepath/mygroup.stg:

group mygroup: mysuper; // inherit from mysuper

sometmp(arg1) ::= <<
Here is arg1: <arg1>
>>

Notes:

  • Inheritance connection is made by the group statement in the stg file of the sub-group. This provides the name of the super-group for StringTemplate to look for in the list of StringTemplateGroups currently loaded. (ie: there is no mechanism for automatically loading a mentioned super-group file (Is this correct? --GW), though there is an interface defined for this if you would like to implement one.)
  • See the separate ST condensed - File syntax article for the format of an stg file.

Next: ST condensed -- Templates and expressions