Java Minimal Template Engine

tinyMediaManger uses the Java Minimal Template Engine (JMTE) to perform “object to text” transformations which are used in

  • the renamer (movies & TV shows)
  • export templates

JMTE has a flexible syntax to achieve almost everything you like. The language is really simple and can be learned in no time. It is all about having a text with small island of expressions that expand to text or control the expansion of text fragments. Those expressions are enclosed in special characters which are freely configurable but are by default

  • ${ for the start of an expression and
  • } for its end

Replacing variables

The simplest form of an expression is to expand an entry contained in the model to a string: ${title}

If your model contains complex objects and you want to expand a certain property or field you can use the “.” notation to navigate to it like e.g. ${movie.title}.

Renderer information

How a variable is eventually converted to a string is determined by renderers. There are renderers which are automatically called based on the type of the variable. However, there are also so called “named renderers” which you can address by passing their name along with the name of the variable. You do this by adding a semicolon and the name of the renderer to the variable name. You can even pass format information in brackets.

For example this

${movie.releaseDate;date(yyyy-MM-dd)}

would cause the variable called movie.releaseDate to be formatted with a renderer named date. This named renderer would then be passed the format yyyy-MM-dd along with the variable to be rendered. Named renderers know which types they support and are responsible to do the necessary conversion for them.

Conditional expansion

Sometimes you might want to display certain text or expand certain expression only when certain conditions hold. The minimal template engine provides you with an if-statement to do so.

${if condition}
  text displayed if condition holds
${else}
  text displayed if condition does not hold
${end}

The else-part is optional and the whole conditional block has to be terminated by the end-expression. If-expressions can be nested and conditions can be negated using the “!”-operator. You can also compare to a string constant using the “=”-operator.

${if ! media.type = "VIDEO"}
  text displayed if media.type is NOT "VIDEO"
${else}
  text displayed if media.type is "VIDEO"
${end}

There are no other logical operators, i.e. you can not combine conditions using and or or. The reason is that this is a minimal language, expressions can be complex and conditions can be constructed in the Java model. You can either have a condition directly inside the model or you can build a processor that computes it and add it to the model.

The condition can be any object. It evaluates using these rules

  • if the object is null or calling toString on the object returns the empty string or false the condition evaluates to false
  • if the object is a boolean, the condition evaluates to the value of that boolean
  • if the object is a map, a collection, an array or any iterable the condition evaluates to true if they contain any elements
  • otherwise the condition evaluates to true

Conditional shortcuts

For convenience reasons there are some shortcuts for the most commonly used conditional statements. The first shortcut works by supplying a default constant value which will be used in case the variable is undefined. You can specify such a default value in brackets. E.g.

${movie.title(unknown)}

would be equivalent to

${if movie.title}
  ${movie.title}
${else}
  unknown
${end}

The second shortcut works by wrapping a value, but only if it is defined. You can wrap a value by adding a prefix and a suffix separated by commas. This means

${<h1>,movie.title,</h1>}

is essentially the same as

${if movie.title}
  <h1>${movie.title}</h1>
${end}

To avoid ambiguities, both prefix and suffix must be supplied or none at all, but they can also be the empty string.

Loops (expanding more than one item)

If you want to expand all elements of a container you can use the foreach-expression.

${foreach container item}
  ${item}
${end}

In this example variable item is set to each element of the container and the body - i.e. the part between the foreach- and the end-expression - is expanded for each item in the container. The container can be anything that implements java.lang.Iterable or anything that implements java.util.Map or any array. If the container is a map we iterate over its entry set and the items will be of type Map.Entry. This means you can access its parts using ${item.key} and ${item.value}.

Loops can be nested and can also contain all kinds of other expressions. You are not able to specify a step or a start of end index.

Special variables

In certain cases you might want to change the way an item in a container shall be displayed depending on its position inside the container. One example is to have the rows in a table be displayed having an alternating format depending whether their row number is even or odd.

Current list of special variables

  • first
  • last
  • odd
  • even
  • index

Special variables are suffixed by a _ followed by the name of the item variable. This means inside a foreach loop that has item as the item name there will be the variable first_item.

Example:

${foreach items item}
  ${if first_item}
    <em>${item}</em>
  ${else}
    ${item}
  ${end}
${end}

Separators

When displaying a list of items you might want to have a separator between each item. This will not work using a normal body as there shall be no additional separator after the last item. You can either solve this using special variables - explained in the previous section - or more easily using a separator. Such a separator is added into the foreach expression like this

${foreach container item , }${item}${end}

Suppose the container contains the items item1 and item2 then the formatted output looks like item1, item2.

Escaping

When you want to use the special character sequences literally you will have to escape them using a the backslash \. You can also escape the backslash by adding a second. In Java this would be

  • \${
  • \}
  • \\

and if you read your template from a file

  • ${
  • }
  • \