Defining Templates

Defining Templates

Creating Templates With Code

Here is a simple example that creates and uses a template on the fly:

Java

StringTemplate query = new StringTemplate("SELECT $column$ FROM $table$;");
query.setAttribute("column", "name");
query.setAttribute("table", "User");

C#

StringTemplate query = new StringTemplate("SELECT $column$ FROM $table$;");
query.SetAttribute("column", "name");
query.SetAttribute("table", "User");

Python

query = stringtemplate3.StringTemplate("SELECT $column$ FROM $table$;")
query["column"] = "name"
query["table"] = "User"

where StringTemplate considers anything in $...$ to be something it needs to pay attention to. By setting attributes, you are "pushing" values into the template for use when the template is printed out. The attribute values are set by referencing their names. Invoking toString() on query would yield

SELECT name FROM User;

You can set an attribute multiple times, which simply means that the attribute is multi-valued. For example, adding another value to the attribute named column as shown below makes the attribute multi-valued:

Java

StringTemplate query = new StringTemplate("SELECT $column$ FROM $table$;");
query.setAttribute("column", "name");
query.setAttribute("column", "email");
query.setAttribute("table", "User");

C#

StringTemplate query = new StringTemplate("SELECT $column$ FROM $table$;");
query.SetAttribute("column", "name");
query.SetAttribute("column", "email");
query.SetAttribute("table", "User");

Python

query = stringtemplate3.StringTemplate("SELECT $column$ FROM $table$;")
query["column"] = "name"
query["column"] = "email"
query["table"] = "User"

Invoking toString() on query would now yield

SELECT nameemail FROM User;

Ooops...there is no separator between the multiple values. If you want a comma, say, between the column names, then change the template to record that formatting information:

Java

StringTemplate query = new StringTemplate("SELECT $column; separator=\",\"$ FROM $table$;");
query.setAttribute("column", "name");
query.setAttribute("column", "email");
query.setAttribute("table", "User");

C#

StringTemplate query = new StringTemplate("SELECT $column; separator=\",\"$ FROM $table$;");
query.SetAttribute("column", "name");
query.SetAttribute("column", "email");
query.SetAttribute("table", "User");

Python

query = stringtemplate3.StringTemplate("SELECT $column; separator=\",\"$ FROM $table$;")
query["column"] = "name"
query["column"] = "email"
query["table"] = "User"

Note that the right-hand-side of the separator specification in this case is a string literal; therefore, we have escaped the double-quotes as the template is specified in a string. In general, the right-hand-side can be any attribute expression. Invoking toString() on query would now yield

SELECT name,email FROM User;

Attributes can be any object at all. StringTemplate calls toString() on each object as it writes the template out. The separator is not used unless the attribute is multi-valued.

Loading Templates From Files

The rest of this article discusses StringTemplateGroups, but only covers the case of groups of individual template files. You may also be interested in string template group files (xxx.stg) which provide more functionality for many scenarios. See separate Group Files article.

To load a template from the disk you must use a StringTemplateGroup that will manage all the templates you load, caching them so you do not waste time talking to the disk for each template fetch request (you can change it to not cache; see below). You may have multiple template groups. Here is a simple example that loads the previous SQL template from a file /tmp/theQuery.st:

SELECT $column; separator=","$ FROM $table$;

The code below creates a StringTemplateGroup called myGroup rooted at /tmp so that requests for template theQuery forces a load of file /tmp/theQuery.st.

Java

StringTemplateGroup group = new StringTemplateGroup("myGroup", "/tmp");
StringTemplate query = group.getInstanceOf("theQuery");
query.setAttribute("column", "name");
query.setAttribute("column", "email");
query.setAttribute("table", "User");

C#

StringTemplateGroup group = new StringTemplateGroup("myGroup", "/tmp");
StringTemplate query = group.GetInstanceOf("theQuery");
query.SetAttribute("column", "name");
query.SetAttribute("column", "email");
query.SetAttribute("table", "User");

Python

group = stringtemplate3.StringTemplateGroup("myGroup", "/tmp")
query = group.getInstanceOf("theQuery")
query["column"] = "name"
query["column"] = "email"
query["table"] = "User"

If you have a directory hierarchy of templates such as file /tmp/jguru/bullet.st, you would reference them relative to the root; in this case, you would ask for template jguru/bullet().

Note

StringTemplate strips whitespace from the front and back of all loaded template files. You can add, for example, <\n> at the end of the file to get an extra carriage return.

Loading Templates relative to an implementation specific location

Java

Loading Templates from CLASSPATH

When deploying applications or providing a library for use by other programmers, you will not know where your templates files live specifically on the disk. You will, however, know relative to the classpath where your templates reside. For example, if your code is in package com.mycompany.server you might put your templates in a templates subdirectory of server. If you do not specify an absolute directory with the StringTemplateGroup constructor, future loads via that group will happen relative to the CLASSPATH. For example, to load template file page.st you would do the following:

// Look for templates in CLASSPATH as resources
StringTemplateGroup group = new StringTemplateGroup("mygroup");
StringTemplate st = group.getInstanceOf("com/mycompany/server/templates/page");


C#

Loading Templates relative to the Assembly's Location

When deploying applications or providing a library for use by other programmers, you will not know in advance where your templates files will be located live in the file system. You will, however, often know the location of your templates relative to the where the application assembly is deployed. For example, if your code is in the an assembly named com.mycompany.server.exe you might put your templates in a templates subdirectory of the directory containing com.mycompany.server.exe. If you do not specify an absolute directory with the StringTemplateGroup constructor, future loads via that group will happen relative to the location of com.mycompany.server.exe. For example, to load template file page.st you would do the following:

// Look for templates relative to assembly location
StringTemplateGroup group = new StringTemplateGroup("mygroup", (string)null);
StringTemplate st = group.GetInstanceOf("templates/page");


Python

Loading Templates from sys.path

FIXME: there was an implementation, test&document it!

If page.st references, say, searchbox template, it must be fully qualified as:
<font size=2>SEARCH</font>: $com/mycompany/server/templates/page/searchbox()$

This is inconvenient and ST may add the invoking template's path prefix automatically in the future.

Caching

By default templates are loaded from disk just once. During development, however, it is convenient to turn caching off. Also, you may want to turn off caching so that you can quickly update a running site. You can set a simple refresh interval using StringTemplateGroup.setRefreshInterval(...). When the interval is reached, all templates are thrown out. Set interval to 0 to refresh constantly (no caching). Set the interval to a huge number like Integer.MAX_INT or Int32.MaxValue to have no refreshing at all.

Java

StringTemplateGroup group = new StringTemplateGroup("myGroup", "/tmp");
group.setRefreshInterval(0);  // no caching
group.setRefreshInterval(Integer.MAX_INT);  // no refreshing

C#

The C# version of StringTemplate does not implement the StringGroup.setRefreshInterval() method. Template files that have been successfully opened are monitored using FileSystemWatcher.

Python

group = stringtemplate3.StringTemplateGroup("myGroup", "/tmp")
group.refreshInterval = 0  # no caching
group.refreshInterval = sys.maxint # no refreshing