# Template Syntax

This vignette describes the template syntax supported by jinjar, following the structure of the Jinja Template Designer Documentation. It is designed to act as a reference when writing templates.

The jinjar R package is powered by the inja C++ library. The syntax is very similar to that of the Jinja Python package, but there are also many differences. Unfortunately, this means jinjar is not a drop-in replacement for Jinja – you might need to adapt existing Jinja templates for the jinjar engine.

The most fundamental difference between jinjar and Jinja is:

- Jinja variables support direct interaction with the underlying Python objects.
- jinjar variables are simple JSON data types. The underlying R objects are translated to JSON.

This is described in more detail in the Variables section below.

Before starting, let’s create a few R objects for rendering example templates.

    library(jinjar)

    # length-1 vector
    title <- "My Webpage"

    # vector
    users <- c("User A", "User B", "User C")

    # list
    godzilla <- list(
      Name = "Godzilla",
      Born = 1952,
      Birthplace = "Japan"
    )

    # data frame
    navigation <- data.frame(
      caption = c("Home", "Blog"),
      href = c("index.html", "blog.html")
    )

    # HTML special characters
    name <- 'Dwayne "The Rock" Johnson'

## Synopsis

A jinjar template is simply a text file, and when rendered the output is also a text file (e.g. HTML, SQL, LaTeX).

A template contains variables and/or expressions, which get replaced with values when a template is rendered; and tags, which control the logic of the template.

Below is a minimal template that illustrates a few basics using the default jinjar configuration. We will cover the details later in this document:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>{{ title }}</title>
    </head>
    <body>
        <ul id="navigation">
        {% for item in navigation -%}
            <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
        {% endfor -%}
        </ul>
        {# a comment #}
    </body>
    </html>

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>My Webpage</title>
    </head>
    <body>
        <ul id="navigation">
        <li><a href="index.html">Home</a></li>
        <li><a href="blog.html">Blog</a></li>
        </ul>

    </body>
    </html>

The following example shows the default configuration settings, but you can adjust the syntax configuration as desired using `jinjar_config()`.

There are a few kinds of delimiters. The default delimiters are configured as follows:

- `{% ... %}` for Statements
- `{{ ... }}` for Expressions to print to the template output
- `{# ... #}` for Comments not included in the template output

Line Statements are also possible, though they don’t have default prefix characters. To use them, set `line_statement` when creating the `jinjar_config()`.

## Variables

When writing a template, we refer to variables that act as data placeholders. We define their values when rendering the template.

Although we pass R objects to `render()`, it is helpful to understand that these are encoded as JSON objects before the template is rendered.

R object | JSON object | Template example
--- | --- | ---
Length-1 vector | Scalar | `{{ foo }}`
Vector | Array | `{{ foo.1 }}`
List | Object | `{{ foo.bar }}`
Data frame | Array of objects | `{{ foo.1.bar }}`

You can use dot (`.`) notation to access data nested within a variable. An array element is accessed by its numeric index (e.g. `foo.1`) and an object value is accessed by its key (e.g. `foo.bar`).

Note: In R, the dot is a valid character in an object name (e.g. `my.data`). However, this causes ambiguity when accessing nested data values. For this reason, each dot is replaced with an underscore when the data is encoded as JSON (e.g. `my.data` becomes `my_data`).

The double-brace syntax is used to print the value of the variable (e.g. `{{ foo }}`). To use the variable in other contexts (e.g. control structures), then these braces are omitted (e.g. `{% for bar in foo %}`).

If a template variable has not been defined, then an error occurs. However, you can use the `default(foo, bar)` function to specify a fallback value.

## Comments

To comment-out some lines, preventing them from appearing in the rendered document, use the comment syntax (default: `{# ... #}`). This is useful for debugging or documenting the template.

    Hello{# TODO: update this #}!

    Hello!

## Whitespace Control

In the default configuration, whitespace (e.g. spaces, tabs, newlines) is left unchanged in the rendered output. For example, in the default configuration we get:

    <div>
        {% if true %}
            yay
        {% endif %}
    </div>

    <div>

            yay

    </div>

By setting `trim_blocks = TRUE` when creating the `jinjar_config()`, the first newline after a control block is automatically removed. Setting `lstrip_blocks = TRUE` removes any whitespace from the beginning of the line until the start of each block. With both options enabled, the above example becomes:

    <div>
        {% if true %}
            yay
        {% endif %}
    </div>

    <div>
            yay
    </div>

Instead of changing the global configuration, you can manually trim whitespace at a more finegrained level.

- By putting a minus sign (`-`) after the opening delimiter, this removes any whitespace from the beginning of the line until the start of the block (i.e. the same as the `lstrip_blocks` feature).
- By putting a minus sign (`-`) before the closing delimiter, this removes any whitespace (including newlines) until the next non-whitespace character (i.e. slightly different from the `trim_blocks` feature).

This can be activated for control blocks, comments, or variable expressions:

    <div>
        {% if true -%}
            yay
        {%- endif -%}
    </div>

    <div>
        yay
    </div>

## Line Statements

If line statements are enabled (see `jinjar_config()`), it’s possible to mark a line as a statement. For example, if the line statement prefix is configured to `#`, you can do:

    <ul id="navigation">
    # for item in navigation
        <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
    # endfor
    </ul>

    <ul id="navigation">
        <li><a href="index.html">Home</a></li>
        <li><a href="blog.html">Blog</a></li>
    </ul>

## Control Structures

A control structure refers to all those things that control the flow of a program. With the default syntax, control structures appear inside `{% ... %}` blocks.

### For

A for-loop allows you to iterate over each element in a vector:

    {% for user in users -%}
    {{ loop.index1 }}. {{ user }}
    {%- endfor -%}

    1. User A
    2. User B
    3. User C

or loop over key-value pairs in a named list:

    <dl>
    {% for key, value in godzilla %}
      <dt>{{ key }}</dt>
      <dd>{{ value }}</dd>
    {% endfor -%}
    </dl>

    <dl>

      <dt>Birthplace</dt>
      <dd>Japan</dd>

      <dt>Born</dt>
      <dd>1952</dd>

      <dt>Name</dt>
      <dd>Godzilla</dd>
    </dl>

As described in Variables, a data frame is translated to an array of JSON objects. Therefore a nested combination of the above two loops could theoretically be used. In practice, it is much more common to iterate over rows and access the individual elements by their attributes:

    <ul id="navigation">
    {% for item in navigation -%}
    <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
    {% endfor -%}
    </ul>

    <ul id="navigation">
    <li><a href="index.html">Home</a></li>
    <li><a href="blog.html">Blog</a></li>
    </ul>

While inside a for-loop block, you can access some special variables:

Variable | Description
--- | ---
`loop.index` | The current iteration (0-based).
`loop.index1` | The current iteration (1-based).
`loop.is_first` | True if first iteration.
`loop.is_last` | True if last iteration.
`loop.parent` | In nested loops, the parent loop variable.

### If

Conditional branches are written using `if`, `else if` and `else` statements, which evaluate Expressions.

    {% if length(users) > 5 -%}
    {% for user in users -%}
    * {{ user }}
    {% endfor %}
    {% else if length(users) > 0 -%}
    {{ join(users, ", ") }}.
    {% else -%}
    No users found.
    {% endif %}

    User A, User B, User C.

### Assignments

Using the `set` statement, you can assign values to variables.

    {% set name="world" -%}
    Hello {{ name }}!

    Hello world!

### Extends

The `extends` tag can be used for template inheritance. See Template Inheritance in `vignette("auxiliary-templates")`.

### Include

The `include` tag inserts the rendered contents of an auxiliary template. See Template Inclusion in `vignette("auxiliary-templates")`.

## Expressions

Basic expressions are supported in templates.

### Literals

The simplest form of expressions are literals, which represent fixed values.

As described in Variables, the template is rendered using data stored in JSON format. For this reason, literals must also be specified in JSON format. The following types of literals are supported:

- String: characters between two double quotes.
- Integer: whole numbers without decimal part.
- Numeric: floating point numbers written in decimal or scientific format.
- Boolean: either `true` or `false` (lowercase).
- List: data between square brackets.
- Object: key-value data pairs between curly brackets (each key must be a string).
- NULL: missing data is represented by `null`.

Here is example usage for each type:

    String: {{ "A string" }}
    Integer: {{ 3 }}
    Numeric: {{ 3.14 }} or {{ 1.6e-19 }}
    Boolean: {{ true }} or {{ false }}
    List: {{ [1, 2, 3] }}
    Object: {{ {"a": 1, "b": 2} }}
    Null: {{ null }}

    String: A string
    Integer: 3
    Numeric: 3.14 or 1.6e-19
    Boolean: true or false
    List: [1,2,3]
    Object: {"a":1,"b":2}
    Null:

### Math

You can perform simple arithmetic using standard operators:

    1 + 1: {{ 1 + 1 }}
    3 - 2: {{ 3 - 2 }}
    2 * 2: {{ 2 * 2 }}
    1 / 2: {{ 1 / 2 }}
    2 ^ 3: {{ 2 ^ 3 }}
    7 % 3: {{ 7 % 3 }}

    1 + 1: 2
    3 - 2: 1
    2 * 2: 4
    1 / 2: 0.5
    2 ^ 3: 8
    7 % 3: 1

### Comparisons

You can perform comparisons:

    1 == 1: {{ 1 == 1 }}
    1 != 1: {{ 1 != 1 }}
    2 >  1: {{ 2 > 1 }}
    2 >= 1: {{ 2 >= 1 }}
    2 <  1: {{ 2 < 1 }}
    2 <= 1: {{ 2 <= 1 }}

    1 == 1: true
    1 != 1: false
    2 >  1: true
    2 >= 1: true
    2 <  1: false
    2 <= 1: false

### Logic

Within expressions and control structures, you can use the Boolean operators: `and`, `or`, and `not`.

    true and false: {{ true and false }}
    true or false: {{ true or false }}
    not false: {{ not false }}

    true and false: false
    true or false: true
    not false: true

You can also check if a value is contained within a list using `in`:

    {{ 1 in [1, 2, 3] }}

    true

## Functions

### Data Checks

You can check if a value exists by passing the variable name as a string:

    users does exist: {{ exists("users") }}
    abc doesn't exist: {{ exists("abc") }}

    users does exist: true
    abc doesn't exist: false

Similarly, you can check if a value exists within a JSON object, by passing the key as a string:

    Birthplace does exist: {{ existsIn(godzilla, "Birthplace") }}
    Weight doesn't exist: {{ existsIn(godzilla, "Weight") }}

    Birthplace does exist: true
    Weight doesn't exist: false

Concisely handle missing values using the `default()` function:

    {{ default(godzilla.Weight, 20000) }}

    20000

You can also check the data type of a variable or literal:

    {{ isString("a string") }}
    {{ isInteger(3) }}
    {{ isFloat(3.14) }}
    {{ isNumber(3) }} and {{ isNumber(3.14) }}
    {{ isBoolean(false) }}
    {{ isArray([1, 2, 3]) }}
    {{ isObject({"a": 1, "b": 2}) }}

    true
    true
    true
    true and true
    true
    true
    true

### Data Conversion

You can convert strings to numeric types, using the `int()` or `float()` functions:

    {{ int("2") }}
    {{ float("2.5") }}

    2
    2.5

### HTML Escaping

When generating HTML from templates, there’s always a risk that a variable will include characters that affect the resulting HTML. The special characters are: `<`, `>`, `&` and `"`.

In jinjar, it’s your responsibility to manually escape variables, using the `escape_html()` function. You should escape variables that might contain any of the special characters. But if a variable is trusted to contain well-formed HTML, then it should not be escaped (otherwise you could accidentally double-escape the content).

    <input type="text" value="{{ escape_html(name) }}">

    <input type="text" value="Dwayne &quot;The Rock&quot; Johnson">

### SQL Quoting

SQL databases expect string literals to be wrapped in single-quotes, while other types of literals (e.g., numbers) are not quoted. This is cumbersome to achieve when writing a template, so the `quote_sql()` function provides this functionality.

Important: `quote_sql()` does not provide any protection against SQL injection attacks.

    WHERE title = {{ quote_sql(title) }} AND year = {{ quote_sql(godzilla.Born) }}

    WHERE title = 'My Webpage' AND year = 1952

When passed an array, `quote_sql()` will quote each element and return a comma-separated list. This is particularly helpful when using the SQL `IN` operator.

    WHERE user IN ({{ quote_sql(users) }})

    WHERE user IN ('User A', 'User B', 'User C')

### Numeric Data

You can check if an integer is even or odd, or divisible by some other integer. This could be used to make alternating row colors.

    {{ even(42) }}
    {{ odd(42) }}
    {{ divisibleBy(42, 7) }}

    true
    false
    true

You can round floating point numbers to a specific precision:

    {{ round(3.1415, 0) }}
    {{ round(3.1415, 3) }}

    3
    3.142

### String Data

Translate a string to lower case or upper case:

    {{ lower("Hello") }}
    {{ upper("Hello") }}

    hello
    HELLO

Escape special characters for use in HTML content (see HTML Escaping):

    <input type="text" value="{{ escape_html(name) }}">

    <input type="text" value="Dwayne &quot;The Rock&quot; Johnson">

### JSON Lists

Get the number of list elements:

    length(): {{ length([3,1,2]) }}

    length(): 3

Get the first or last elements:

    first(): {{ first([3,1,2]) }}
    last():  {{ last([3,1,2]) }}

    first(): 3
    last():  2

Get the minimum or maximum elements:

    min(): {{ min([3,1,2]) }}
    max(): {{ max([3,1,2]) }}

    min(): 1
    max(): 3

Sort the list into ascending order:

    sort(): {{ sort([3,1,2]) }}

    sort(): [1,2,3]

Join a list with a separator:

    {{ join([1,2,3], " + ") }}
    {{ join(users, ", ") }}

    1 + 2 + 3
    User A, User B, User C

Generate a list as a range of integers:

    {% for i in range(4) %}{{ loop.index1 }}{% endfor %}

    1234

Access elements using a dynamic index with `at()`. Note that the index is zero-based.

    {% set x = [1,2,3] -%}
    {% set i = 2 -%}
    {{ x.2 }}
    {{ at(x, i) }}

    3
    3

### JSON Objects

Access values using a dynamic key with `at()`:

    {% set x = {"a": 1, "b": 2} -%}
    {% set key = "b" -%}
    {{ x.b }}
    {{ at(x, key) }}

    2
    2