Module org.klojang.templates


module org.klojang.templates

Klojang Templates is a templating API written with two goals in mind:

◆ Writing templates should be so simple that there is essentially no learning curve.
◆ Provide a rich en flexible API for populating the templates that compensates for their simplicity.

In short: leverage the skills of Java programmers, rather than make them learn what, in effect, amounts to a whole new language.

Syntax

A Klojang template consists of the following elements:

Boilerplate Text
This could be HTML, but it could equally well be anything else. Klojang Templates is not biased towards any particular output format. However, Klojang Templates does provide some extra help when writing HTML templates, notable in the form of a few predefined variable groups.

Template Variables
Template variables look like this: ~%city%. The variable name can optionally be prefixed with the name of a variable group: ~%html:city%. When populating a template through RenderSession.insert() or RenderSession.populate(), a variable name may be a path through the source data object passed to these methods. For example: ~%employee.address.city%. Since you may be populating your templates with hash maps, in which case variable names would correspond to map keys, there are hardly any constraints on what constitutes a valid variable name (or path segment):
◆ it must contain at least one character
◆ it must not contain any of the following characters: ~%.:\r\n\0.
Obviously, when using records or JavaBeans as source data, you will be more constrained in your choice of variable names: they must be valid Java identifiers.

Nested Templates
In Klojang Templates templates can be nested inside other templates. Syntactically, this happens either either via inline templates or via included templates.

Within an HTML template, inline templates would look like this:


 <html>
 <body>
   ~%%begin:employees%
     <p>First name: ~%firstName%</p>
     <p>Last name: ~%lastName%</p>
   ~%%end:employees%
 </body>
 </html>
 

Included templates look like this:


 <html>
 <body>
   ~%%include:/static/views/employees.html%%
 </body>
 </html>
 

And the contents of employees.html would then be something like this:


   <p>First name: ~%firstName%</p>
   <p>Last name: ~%lastName%</p>
 

The name of an included template by default is the basename of the include path ("employees" in the example above). However, you can also use the following syntax:


 ~%%include:employees:/static/views/employees-2023-01-01.html%%
 

Placeholders
A placeholder is a block of text inside a pair of <!--%--> tokens. The tokens and the text are removed when the template is rendered. However, since <!--%--> is a self-closed HTML comment, the placeholder text between a pair of these tokens will be visible when viewing the raw template in a browser. A nested template may contain placeholders, but it is not allowed to place a pair of <!--%--> tokens around a nested template — it will result in a ParseException. Placeholders are meant to be used in a development process aimed at keeping the raw, unprocessed well-formed, valid and intelligible. They allow you to provide placeholder values for template variables. However, they can also be used to specify a default value for a template variable. See VarGroup.DEF.

Ditch Blocks
A ditch block is a block of text inside a pair of <!--%%--> tokens. The tokens and the text are removed when the template is rendered. Ditch blocks really are comments, comparable to slash-star comments in Java. You can place <!--%%--> tokens around variables or nested templates, causing them to be "commented out", but you cannot place <!--%%--> tokens inside any of the other syntax elements listed here.

HTML Comment Wrapping

(NB This section is only relevant if your goal is to create templates that will render flawlessly in a browser in their raw, unprocessed state.)

Variables, inline templates and included templates can all be placed in HTML comments without this making a difference in how the template is rendered. For example <!-- ~%city% --> renders just like ~%city%. If city is set to "Paris", then the entire string "<!-- ~%city% -->" is replaced with "Paris" when the template is rendered. You can have either one space character on either side of the variable, or none at all (<!--~%city%-->). Multiple spaces or other characters are not allowed. The same applies when wrapping inline templates and included templates in HTML comments.

For included templates, HTML comment wrapping would look like this: <!-- ~%%include:/path/to/foo.html%% -->.

For inline templates you can either wrap just the begin and and tags of the inline template, or you can wrap the entire inline template in HTML comments:


 <table>
     <!-- ~%%begin:employee% -->
     <tr><td>~%firstName%</td><td>~%lastName%</td></tr>
     <!-- ~%%end:employee% -->
 </table>
 

Versus:


 <table>
     <!-- ~%%begin:employee%
     <tr><td>~%firstName%</td><td>~%lastName%</td></tr>
     ~%%end:employee% -->
 </table>
 

Using the API

Here are two fairly typical examples of using Klojang Templates within JAX-RS. They produce the same result by different means.


 public class EmployeeResource {

  EmployeeDao dao;

  @GET
  @Path("/{id}")
  public String find(@PathParam("id") int id) {
    Employee emp = dao.find(id);
    Template template = Template.fromResource(getClass(), "/views/employee.html");
    RenderSession session = template.newRenderSession();
    return session
      .set("firstName", emp.getFirstName())
      .set("lastName", emp.getLastName())
      .render();
  }
 }
 

 public class EmployeeResource {

  EmployeeDao dao;

  @GET
  @Path("/{id}")
  public StreamingOutput find(@PathParam("id") int id) {
    Employee employee = dao.find(id);
    Template template = Template.fromResource(getClass(), "/views/employee.html");
    RenderSession session = template.newRenderSession()
    session.insert(employee);
    return session::render;
  }
 }