TemplAT is a general-purpose text-file template engine, designed to be used as an API from Java applications or servlets. It is small (39K) and simple, yet surprisingly powerful. It does not have any external library dependencies.

This software is distributed under the GPLv3 license.

The source code is hosted at github: https://github.com/cmosher01/templat

Project Goals

Simple

The TemplAT language is very simple to learn. It contains only the most basic programming constructs: if-then-else, loop, and include (with parameters). It also allows calling Java methods and accessing Java arrays. That’s all there is to it. And yet, these few simple tools provide a powerful templating language.

Small

The TemplAT class library consists of a 39K jar file. And that’s it. It is designed to contain only what is necessary to provide its simple language, and nothing more. It is self-contained, and does not rely on any other external libraries.

Useful

TemplAT can be used for generating HTML pages by a Java servlet for a web server. It could just as easily be used for generating Java, C++, or SQL source code. It is useful for any text file where you need some kind of programming ability (loops, if-then-else, includes, method calls).

Reliable

The TemplAT source code’s correctness is backed by a comprehensive suite of unit tests. This ensures that each new release can add features and improvements while preventing any regression. It allows for the developers to refactor code and improve its internal state without introducing new bugs. The internal structure of the code is clean, simple, and straightforward.

Download

The easiest way to use TemplAT is via maven. Add this to your pom.xml file:

<repositories>
  <repository>
    <id>mosher.mine.nu</id>
    <url>http://mosher.mine.nu/maven</url>
  </repository>
</repositories>

...

<dependencies>
  <dependency>
    <groupId>net.sourceforge.templat</groupId>
    <artifactId>templat</artifactId>
    <version>1.2.1-SNAPSHOT</version>
  </dependency>
</dependencies>

Simple Example

Once you have downloaded the templat.jar file and put it into the classpath, you can make a simple example program to demonstrate how TemplAT works. For example, create a text file called displayBooks.tat; this will be our template.

displayBooks.tat

@template displayBooks(books)@
We have the following books:
@loop b : books.size()@
    @books.get(b).getTitle()@ by @books.get(b).getAuthor()@.
@end loop@

Tags are surrounded by at-signs (@). These regions will be parsed by the Templat class. The template tag defines this file as a template, and specifies its parameters. The loop tag starts a loop block, and identifies the loop counter variable and the number of times the loop block will be expanded. The expressions in the next line will be parsed by the Templat class, and the returned values expanded into the resulting text. The end loop tag ends the loop block.

Then create a Java program that renders the template (given a list of books), and prints the results.

PrintBooks.java

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.templat.Templat;
import net.sourceforge.templat.exception.TemplateLexingException;
import net.sourceforge.templat.exception.TemplateParsingException;

public class PrintBooks
{
    // A simplified structure that represents one book
    public static class Book
    {
        private final String author;
        private final String title;

        public Book(String a, String t) { author = a; title = t; }

        public String getAuthor() { return this.author;}
        public String getTitle() { return this.title;}
    }

    public static void main(String[] arg)
        throws TemplateLexingException, TemplateParsingException, IOException
    {
        // This is our inventory of books:
        List<Book> books = new ArrayList<Book>();
        books.add(new Book("Rudyard Kipling","The Jungle Book"));
        books.add(new Book("Mary Shelley","Frankenstein"));
        books.add(new Book("Oscar Wilde","The Picture of Dorian Gray"));

        // Get our displayBooks template:
        Templat tat = new Templat(PrintBooks.class.getResource("displayBooks.tat"));

        /*
         * Render the template, passing our array of books for
         * the argument, and put the result into the StringBuilder.
         */
        Appendable result = new StringBuilder();
        tat.render(result,books);

        // Print out the result
        System.out.println(result);
    }
}

Compiling and running the program produces the following output:

C:\> java -cp .;templat.jar PrintBooks
We have the following books:
    The Jungle Book by Rudyard Kipling.
    Frankenstein by Mary Shelley.
    The Picture of Dorian Gray by Oscar Wilde.

Cheat Sheet

Template File Syntax

template

   @ template template-name( parameter1, parameter2, ... ) @
           template-body

expression

   @ expression @

if

   @ if ( boolean-expression ) @
           if-body
[  @ else @
           else-body  ]
   @ end if @

loop

   @ loop variable : count-expression @
           loop-body
   @ end loop @

include

   @ include template-path( argument1, argument2, ... ) @

Calling from Java

include net.sourceforge.templat.Templat;

Templat tat = new Templat( template-file-URL );

Appendable result = new StringBuilder();
tat.render(result, argument1, argument2, ... );

Template File

template

   @ template template-name( parameter1, parameter2, ... ) @
           template-body

The template tag defines the file as a template to be parsed by the Templat class. It must be at the start of every template file. template-name is the name of this template. This name must be the same as the name of the file containing this template, without the .tat filetype. Following the name, in parentheses, is an optional comma-delimited list of parameter s for this template. Following the template tag is the template-body (the rest of the file), which may contain other tags ( if s, loop s, include s, or expression s ).

expression

   @ expression @

Any tag that does not start with one of TemplAT’s keywords will be treated as a Java expression. An expression can be a variable name, a class name, or an integer literal. Classes or variables may futher have method calls or subscripts (for arrays or java.util.List objects).

if

   @ if ( boolean-expression ) @
           if-body
[  @ else @
           else-body  ]
   @ end if @

The if and end if tags, and optional else tag, define a conditional expansion. The boolean-expression is evaluated; if the result is true, the if-body is (parsed and) expanded to the output. Otherwise, the else-body, if it exists, is (parsed and) expanded to the output. Note that either body (or both) may contain template tags and/or plain text areas.

loop

   @ loop variable : count-expression @
           loop-body
   @ end loop @

The loop and end loop tags define a repeated expansion. The count-expression is evaluated as a Java expression that returns an integer, and the loop-body is (parsed and) expanded that many times to the output. If the count is less than or equal to zero, then the loop-body will not be expanded. Within the loop-body, the variable may be referenced within any expression in any tag. The variable will be a java.lang.Integer. It will hold the value zero on the first iteration of the loop, one on the next iteration, etc., up to count minus 1 on the final interation.

include

   @ include template-path( argument1, argument2, ... ) @

The include tag parses and expands another template file. template-path is the (optional path and) name of the template to be included. The path is interpreted relative to the including template. The file name of the included template will be the specified name followed by .tat filetype. Following the template-path, within parentheses, you must specify the arguments required by the included template. These arguments will be bound to the parameters defined by the included template when it is parsed.

text

Areas of the template that are not within any tag will be passed through verbatim to the output. The one exception is that text cannot contain an at-sign (@) by itself (because an at-sign defines the start of a tag). Use two at-signs in a row (@@) in text to indicate a single at-sign in the rendered output. For example, john@@example.com in text within a template would be rendered as john@example.com in the output. However, john@example.com in the text would result in a syntax error at render time.

TemplAT API

Parsing templates is accomplished by the developer writing a Java application (or servlet) and using the TemplAT API. The TemplAT API is very simple and straightforward, consisting of basically one class and one method. The class to use is:

net.sourceforge.templat.Templat

Create an instance of this class, and pass the template’s URL to the constructor:

Templat t = new Templat(urlOfTatFile);

To actually render the template, call the render method:

void render(Appendable result, Object... arguments)

Template File Grammar

 template : tmpldef body
  tmpldef : '@' 'template' '(' [param [',' param ...]] ')' '@'
     body : [text] [statement] ...
statement : if | include | loop | expr
       if : '@' 'if' '(' boolean-expr ')' '@' body '@' 'end if' '@'
  include : '@' 'include' template-path '(' [expr [',' expr ...]] ')' '@'
     loop : '@' 'loop' var ':' count-expr '@' body '@' 'end loop' '@'
     expr : '!' expr
            '(' expr ')'
            INTEGER
            name [selector...]
     name : [name '.'] IDENTIFIER
 selector : '.' IDENTIFIER '(' [expr...] ')'
            '[' expr ']'