The ETL template language provides a lightweight system for creating textual data, with facilities for substituting variables into text, filtering those variables through various transformations, conditional expressions, and loops, among other things. You create a template file, which contains various ETL directives, and then you process that file along with a set of variables to produce output.

ETL directives are set apart from the text of a template by the character sequences [% and %]. [% begins the directive and %] ends it. If you wish to include [% in the text of a template without signaling the start of a directive you can escape it with a backslash, if you want to include a backslash right before a directive simply escape the backslash with another backslash. Directives can span multiple lines, and whitespace between the tokens within a directive is ignored.

The first directive you're likely to encounter in an ETL template is 'print', which outputs the contents if the variable it's passed as text. For example:

[% print foo %]

This includes the contents of the variable foo in the output of the template. Since 'print' is used so often there is a shorthand for it, just start your directive with [%= instead of [% and it'll be interpreted as a 'print', so this is the shorthand version of the previous example:

[%= foo %]

Note that currently you can only print String and Integer variables, trying to print a Hash or an Array will result in an error.

It's probably worth mentioning that whenever we talk about variables in this document, what we really mean is an expression that evaluates to a variable. For example, it is possible to index into a Hash using a foo.blah syntax, like this:

[%= foo.bar %]

Assuming 'foo' is a Hash that contains the key 'bar', this will print the value associated with that key.

The foo.bar syntax for indexing into a Hash will only work for keys that don't have spaces in them, and that are known in advance, if you want to use a key with whitespace in it, or a variable key, you can use the following syntax.

[%= foo["bar"] %]

This can be extended to arbitrary levels...

[%= foo["bar"][baz]["zot"] %]

Note in that case the first and third indices were literal strings, but the second was a variable which will be looked up at runtime.

Identical syntax works for indexing into Arrays, just with Integers as the key instead of Strings.

[%= array[2] %]

Since a common use case for ETL is creating HTML or XML documents, there are some specialized filters available for escaping data for use in HTML, XML, and URLs. These filters are used like this:

[% print foo | html %]

If 'foo' contains the string "foo < bar" then that will end up outputing "foo &lt; bar". There are similar 'xml' and 'url' filters that do the required escaping for XML and URLs.

It's worth pointing out that while in the previous examples we've been printing and filtering variables, in reality these directives work on Expressions, an expression can be a variable, an index into a variable, a literal String or Integer, or even an arithmetic operation. For example, consider the following template:

[%= 2 + 5 %]

As you probably guessed, that will print out the number 7. All the usual operations are supported: +, -, *, /, and %, and they can be used whenever you would otherwise try to use a variable or literal.

Once you've mastered using variables in your templates, the next task before you is likely conditionals. ETL gives you two types of conditional expressions, 'if' and 'unless', which are just mirror images of each other.

[% if foo %]
  [% print bar %]
[% end %]

This will output the contents of 'bar' if the contents of 'foo' evaluate to true. The converse is:

[% unless foo %]
  [% print bar %]
[% end %]

That will print the contents of 'bar' if 'foo' evaluates to false.

As you probably expected, you can use the usual ==, !=, <, >, <=, and >= expressions with 'if' and 'unless'.

[% if foo == bar %]
  [% print baz %]
[% end %]

This will print the contents of 'baz' if 'foo' is equal to 'bar'.

The next bit of syntax ETL provides to you is the loop.

[% for e in entries %]
  [%= e | html %]
[% end %]

This will loop over the array 'entries', assigning each element in it to the variable 'e', then printing it out after filtering it for 'html' content.

To loop over the keys and values in a hash you can use similar syntax.

[% for k,v in hash %]
  [%= k %] : [%= v %]
[% end %]

This will loop over each key-value pair in the Hash 'hash' and print them out.

If you just want to loop a certain number of times and don't have a suitably sized Array or Hash you can loop from one integer to another, like this:

[% for idx in 1 to 20 %]
  [%= idx %]
[% end %]

That works pretty much like you expect it to.

Once you start messing around with loops and conditionals it's nice to be able to have directives in your template without introducing extra whitespace. You want whitespace around the directives in the template, for formatting reasons, but in the final output it would look ugly.

To deal with this problem ETL provides you with the [%- and -%] options for starting and ending directives. [%- is just like [%, but eats the whitespace before it, and -%] is just like %] but it eats whitespace after it. -%] also eats the following newline, since it turns out you basically always want to do that.

For example, if you had the following DDL:

array = [ "foo", "bar", "baz" ]

And fed it to this ETL:

<table>
  [%- for str in array -%]
  <tr>
    <td>[%= str %]</td>
  </tr>
  [%- end -%]
</table>

You'd get the following output:

<table>
  <tr>
    <td>foo</td>
  </tr>
  <tr>
    <td>bar</td>
  </tr>
  <tr>
    <td>baz</td>
  </tr>
</table>

The whitespace around the loop directives has been swallowed, which makes for much nicer output.

If you find yourself duplicating a lot of functionality, you may want to abstract some of it into macros. For example, here's a macro that creates a html link:

[% macro link(href, text) %]<a href="[%= href | url %]">[%= text | html %]</a>[% end -%]

Once the macro is defined you can use it like this: [% link("http://www.apache.org/", "Apache") %]. That will result in the following output: <a href="http://www.apache.org/">Apache<a>.

The last thing you're likely to want to do is to include one template in another. For example, when writing a web site it's common to have some common elements that show up in every page in the site. You can abstract those elements out into some helper templates, and then use the [% include "foo.etl" %] directive to pull them into your page.