Skip to content
This documentation is currently in preview, therefore subject to change.

Word Template Syntax

Word templates use a simple templating language and data sources to generate Word documents. Templates look like regular documents with embedded template expressions.

The example below shows the generated output from a word template and a data source:

Name: <<[Person.FirstName]>> <<[Person.LastName]>>
Address:
<<[Person.Address.Number]>>, <<[Person.Address.Street]>>
<<[Person.Address.City]>>
<<[Person.Address.Postcode]>>

An expression is <<, some contents, followed by >>. When the template is executed, these expressions are replaced with values from a data source.

Language features

Simple expressions

The following template defines two template expressions. If applied to the input object, the expressions will be replaced by the corresponding properties. The result is then:

<<[FirstName]>> <<[LastName]>>

Nested input objects

Sometimes, the input objects contain other objects or arrays. In such a case, you can use dot-notation to gain access to nested properties. For example:

<<[Person.FirstName]>> <<[Person.LastName]>>

Some built-in helpers allow you to change the current context to a nested object. You can then access this object as if it were the root object.

Conditionals

You can use the if helper to conditionally render a block. If its argument returns false, undefined, null, "", 0, or [], the block will not be rendered.

A conditional expression must return a Boolean value (‘true’ or ‘false’). If none of the conditional expressions equate to true, and no fallback template is provided, the entire conditional block will be removed.

The first expression that returns true will trigger the corresponding template option to be used.

<<if [conditional_expression1]>>
template_option1
<<elseif [conditional_expression2]>>
template_option2
<<else>>
default_template_option
<</if>>

For example

<<if [Author]>>
<<[FirstName]>> <<[LastName]>>
<<else>>
Unknown author
<</if>>

If the input is an empty JSON object {}, then Author will become undefined and the if condition will fail, resulting in:

Unknown author

Operators

Build a Doc supports a number of operators to assist with template creation.

Operators are special symbols or keywords that tell the template engine how to manipulate values: whether it’s accessing data, performing mathematical operations, making decisions, or combining pieces of text. They are the “verbs” of your template expressions: they act on your data to produce the final output.

Primary Operators

Operators that let you access data and call functions. The expressions should be written using this syntax template: <<[x]>>

OperatorDescriptionExample
x.yAccess member/property y on object x.person.Name → “Alice”
x?.ySafely access y on x; returns null if x is null.user?.Emailnull
x.f()Call helper or method f on variable x.name.ToUpper() → “ALICE”
a[x]Retrieve element at index position x from array or list a.colors[0] → “Red”
a?[x]Safely access item at index positon x in a; returns null if a is null.items?[2]null
new T(...)Create a new instance of type T with the given constructor arguments.new DateTime(2025,1,1) → date obj
Unary Operators

Operators that work on a single value. The expressions should be written using this syntax template: <<[-x]>>

OperatorDescriptionExample
-xNegate a number: if amount is 5, then -amount yields -5; if total is -3, then -total yields 3-amount-5
!xLogical NOT: flips a boolean (truefalse)!isActive
~xBitwise NOT: flips each single bit in the number - swaps all the 0s for 1s and all the 1s for 0s. Applies it to 0 (which is all zeros in binary) turns every bit into a 1, producing -1~0-1
(T)xCast value x to type T(int)3.143
Binary Operators
Arithmetic

Operators that perform basic mathematical calculations (addition, subtraction, multiplication, division, remainder). The expressions should be written using this syntax template: <<[x * y]>>

OperatorDescriptionExample
x * yMultiply2 * 36
x / yDivide6 / 23
x % yRemainder7 % 43
x + yAdd numbers or concatenate strings"A" + "B" → “AB”
x - ySubtract5 - 23
Bitwise

Operators that manipulate individual bits of integer values (shift, AND, OR, XOR, NOT). The expressions should be written using this syntax template: <<[x << y]>>

OperatorDescriptionExample
x << yShift bits of x left by y positions1 << 24
x >> yShift bits of x right by y positions4 >> 12
x & yBitwise AND3 & 11
x ^ yBitwise XOR5 ^ 36
x | yBitwise OR5 | 27
Relational

Operators that compare two values and return a boolean (true/false) result. The expressions should be written using this syntax template: <<[x < y]>>

OperatorDescriptionExample
x < yTrue if x is less than y.2 < 3true
x > yTrue if x is greater than y.3 > 2true
x <= yTrue if x is ≤ y.2 <= 2true
x >= yTrue if x is ≥ y.3 >= 4false
x == yTrue if x equals y.5 == 5true
x != yTrue if x does not equal y.5 != 4true
Logical

Operators that combine boolean values to form more complex conditions. The expressions should be written using this syntax template: <<[(x && y)]>>

OperatorDescriptionExample
x && yTrue only if both x and y are true.true && falsefalse
x || yTrue if either x or y is true.true || falsetrue
Null-Coalescing

Operators that provides a default when a value is null. The expressions should be written using this syntax template: <<[(x ?? y)]>>

OperatorDescriptionExample
x ?? yReturn x if not null; otherwise return y.name ?? "Unknown"

Loops

You can iterate over a list using the built-in foreach helper. Inside the block, you can use variable name to reference the element being iterated over.

<<foreach [variable_name in sequence_expression]>>
data_band_body
<</foreach>>

For example:

<<foreach [person in people]>>
<<[person]>>
<</foreach>>

Reference item position

When looping through items in a foreach statement, you can reference the position of each item using the IndexOf() and NumberOf() extension methods.

  • IndexOf() returns a zero‑based index (0 for the first item, 1 for the second, etc.).

  • NumberOf() returns a one‑based index (1 for the first item, 2 for the second, etc.).

IndexOf() Example: Comma-Separated List

To manipulate the data source to turn it into a comma-separated list, the below method can be applied, utilising the IndexOf() method:

The fruits are:
<<foreach [fruit in items]>>
<<[ IndexOf() > 0 ? ", " : "" ]>><<[fruit]>>
<</foreach>>.

The example uses the foreach loop, applying the ternary rule ‘if the item’s index is greater than 0, add a comma before the item, else do nothing’ to each item from the data source.

  • First pass: IndexOf() = 0 → no comma

  • Later passes: IndexOf() > 0 → insert ", "

This results in a comma-separated list, with a comma after each item except the first.

NumberOf() Example: Simple Numbered List

When looping through items in foreach, you can optionally reference the current loop index via the IndexOf() function.

You can use this function to distinguish sequence items with different indexes and then handle them in different ways. For example, given that items is a list of the strings “apples”, “bananas”, and “oranges”, you can use the following template to enumerate them, prefixing all but the first with commas. This is useful when producing lists.

No. - Item
<<foreach [item in items]>>
<<[ NumberOf() ]>> - <<[item]>>
<</foreach>>

Force move to next Item

You can instruct the engine to force movement to the next item within a loop using a next tag.

This feature is useful in label-print-like scenarios when you need to output data about a fixed number of items in a single table row, like in the following example.

Given that Clients is a list having a field named “Name”, you can use the following template to output three client names per row while outputting names of all clients. The next tag forces an increment in the loop, ‘jumping’ to the next item and allowing access to it before the next pass of the loop. As this moves the count of the loop on one place, the next pass of the loop will continue from the next sequential position.

In this case, the engine produces a document as follows:

<<foreach [c in Clients]>><<[c.Name]>>
<<next>><<[c.Name]>>
<<next>><<[c.Name]>><</foreach>>

Formatting values

Expression tags let you control how raw data appears in your document - whether as dates, numbers, or styled text. You insert a format directive directly into your placeholder, and the engine applies it at run time.

You can format values using expression tags. An expression tag serves as a placeholder for an expression result within a template, and allows you to specify a format for the output.

An expression tag has no name and consists of the following elements:

  • An expression enclosed by brackets
  • An optional format string enclosed by double quotes and preceded by the ”:” character
  • An optional html switch
<<[expression]:"format" -html>>
Format string

The format string can be used to format numeric values or strings, and must correspond to the expected format described in the context provided: a string method can only be applied to a string, and a dateTime method can only be applied to a dateTime etc.

If you have a string or numeric value and you want to format it into a specific pattern, you can do so by using the format string within the expression tag. In the below example, the string is formatted to upper case.

<<[string]:upper>>
HTML Switch

Values can be formatted using an optional HTML switch when outputting expression results. This allows you to insert HTML content dynamically into your reports while maintaining the formatting of the template document.

When using an expression tag, you can include the HTML switch to treat the expression result as an HTML block.

You can use the following syntax for an expression tag with a HTML switch:

<<[htmlString] -html>>

Dates and Times

Dates from an data source property can be formatted using the following syntax.

<<[expression]:"pattern">>

For example:

<<[person.DateOfBirth]:"dd/MM/yyyy">>

Numbers

Provides several additional number formats that can not be specified using format strings. The following table describes these formats.

Number FormatDescription
alphabeticFormats an integer number as an upper-case letter (A, B, C, …)
romanFormats an integer number as an upper-case Roman numeral (I, II, III, …)
ordinalAppends an ordinal suffix to an integer number (1st, 2nd, 3rd, …)
ordinalTextConverts an integer number to its ordinal text representation (First, Second, Third, …)
cardinalConverts an integer number to its text representation (One, Two, Three, …)
hexFormats an integer number as hexadecimal (8, 9, A, B, C, D, E, F, 10, 11, …)
arabicDashEncloses an integer number with dashes (- 1 -, - 2 -, - 3 -, …)

The following is an example of how you can use one of these additional number formats, instead of a format string. Given that i is an integer number, you can format i as an upper-case letter (1 = A, 2 = B, 3 = C, …).

<<[i]:alphabetic>>

Strings

The following table describes these formats.

String FormatDescription
lowerConverts a string to lower case (“the string”)
upperConverts a string to upper case (“THE STRING”)
capsCapitalises a first letter of every word in a string (“The String”)
firstCapCapitalises the first letter of the first word in a string (“The string”)

The following is an example of how you can specify an additional string format. Given that s is a string, you can capitalise the first letter of every word in s using the following template.

<<[s]:caps>>

Combine formatters

You can also combine expression formatters like in the following examples. Given that d is a DateTime value, you can convert its textual month representation to upper case using the following template.

<<[d]:"MMMM":upper>>
<<[i]:roman:lower>>

Using Variables

Templates enable you to use variables in template documents. Use variables to store expensive calculations once and reuse the result throughout your template. This is particularly useful for complex calculations, such as running totals.

You can declare a variable in a template using a var tag:

<<var [variable_type variable_name = variable_value]>>

If you do not specify the type explicitly, it is determined implicitly from the specified variable value.

Each new variable must have a unique identifier. After a variable is declared in a template, its value can be accessed using its name, just like any other variable.

<<var [s = "Hello!"]>><<[s]>>

You can redefine the value of a variable using a var tag against the name of this variable. For example, the following template outputs string “Hello, World!”

<<var [s = "Hello, "]>><<[s]>><<var [s = "World!"]>><<[s]>>

Variables come with the following restrictions:

  • You can not redefine the type of a variable.
  • Using a var tag, you can not redefine the value of an iteration variable or a data source.

External Documents

You can insert contents from other documents into your document dynamically using doc tag. A doc tag denotes a placeholder within a template for a document to be inserted.

Syntax of a doc tag is defined as follows.

<<doc [document_expression]>>

An expression declared within a doc tag must return a base64 encoded document.

By default, a document being inserted is not checked against template syntax and is not populated with data. However, you can enable this by using a build switch:

<<doc [document_expression] -build>>

When you use a build switch, the template will treat the inserted document like its own mini-template, and so long as it is available at the scope of a corresponding doc tag, it can use:

  • Any data sources you’ve set up

  • Any variables you’ve defined

Report Title: <<[ReportTitle]>>
<<doc [CustomerInfoDocument] -build>>
Summary:
<<[Summary]>>

Images

You can insert images into your document dynamically using an image tag, via the following steps:

  1. Add a Textbox: Place a textbox in your template where you want the image to be inserted.

  2. Set Image Attributes: Configure common image attributes for the textbox, such as frame and size, so that it visually appears as a blank image placeholder.

  3. Specify an Image Tag: Within the textbox, use the following syntax to declare an image tag:

    <<image [image_template_expression]>>

The template expression must return a value of one of the following types:

  • Base64 encoded
  • String containing an image URI

an example template

By default, the engine stretches an image filling a textbox to the size of the textbox. However, you can change this behavior in the following ways:

  • To keep the width of the textbox and change its height preserving the ratio of the image, use the fitHeight switch as follows.

    <<image [image_expression] -fitHeight>>
  • To keep the height of the textbox and change its width preserving the ratio of the image, use the fitWidth switch as follows.

    <<image [image_expression] -fitWidth>>
  • To change the size of the textbox according to the size of the image, use the fitSize switch as follows.

    <<image [image_expression] -fitSize>>
  • To change the size of the textbox according to the size of the image without increasing the size of the textbox, use the fitSizeLim switch as follows.

    <<image [image_expression] -fitSizeLim>>

You can insert hyperlinks into your spreadsheets using link tags. Syntax of a link tag is defined as follows.

<<link [uri_or_bookmark_template_expression][display_text_template_expression]>>

Here, uri_or_bookmark_template_expression defines a URI or the name of a bookmark within the same document for a hyperlink to be inserted dynamically. This expression is mandatory and must return a non-empty value.

In turn, display_text_template_expression defines text to be displayed for the hyperlink. This expression is optional. If it is omitted or returns an empty value, then during runtime, a value of uri_or_bookmark_template_expression is used as display text as well.

<<link [uri][display text]>>

The expression color_expression must return a value of one of the following types:

  • A string containing the name of a known colour, that is, the case-insensitive name of a member of the KnownColor enumeration:

    <<textColor [“red”]>>text with red font<</textColor>>
  • A string containing an HTML colour code:

    <<textColor [“#F08080”]>>text with light coral font<</textColor>>
  • An integer value defining RGB (red, green, blue) components of the colour:

    <<textColor [0xFFFF00]>>text with yellow font<</textColor>>

You can use textColor tags nested into each other, and can typically use textColor tags within tables and conditional blocks.

Background Colour

You can set text background colour for document contents dynamically using backColor tags. Syntax of a backColor tag is defined as follows.

<<backColor [color_expression]>>
content_to_be_coloured
<</backColor>>

An expression declared within an opening backColor tag defines a text background colour to be applied during build. The expression must return a value of one of the following types:

  • A string containing the name of a known colour, that is, the case-insensitive name of a member of the KnownColor enumeration like in the following example.

    <<backColor [“red”]>>text with red background<</backColor>>
  • An integer value defining RGB (red, green, blue) components of the colour like in the following example.

    <<backColor [0xFFFF00]>>text with yellow background<</backColor>>
  • A value of the Color type.

You can nest backColor tags to layer multiple background effects. You can also place backColor tags inside data bands and conditional blocks—for example, to wrap each item in its own paragraph whose background colour is set dynamically.

<<foreach [item in items]>><<backColor [item.Color]>><<[item.Name]>><</backColor>>
<</foreach>>

You can also use a backColor tag to dynamically apply a solid fill colour to a shape by following these steps:

  1. Add the shape to your template.

  2. Set the shape’s fill option to “No fill.”

  3. In the shape’s textbox, insert opening and closing backColor tags so they wrap around all the text inside the box (if any), like in the example below.

    <<backColor [“red”]>>text inside shape<</backColor>>

Lists

Within a list, you can dynamically reset numbering back to 1 using the restartNum tag. This feature is particularly useful when working with a nested numbered list within a data band, as shown in the example below.

By placing a restartNum tag before the corresponding foreach tag in your template, you can ensure that the list numbering restarts for each item.

When used in a list, the restartNum tag will reset the numbering.

<<foreach [order in orders]>>
<<[order.ClientName]>> (<<[order.ClientAddress]>>)
<<restartNum>>
1. <<foreach [service in order.Services]>>
<<[service.Name]>>
<</foreach>>
<</foreach>>

Tables

You can dynamically populate tables using Build a Doc template expressions.

A table‑row body can span one or more rows of a document table. Its band begins at the start of the first occupied row and ends at the close of the last occupied row:

<<foreach ...>>
<</foreach>>

For example, to populate a document table given the data source.

ClientManagerContract Price
<<foreach [c in Contracts]>><<[c.Clients.Name]>><<[c.Managers.Name]>><<[c.Price]>><</foreach>>
Total:<<[Contracts.Sum(c=>c.Price)]>>

Manager/ClientContract Price
<<foreach [m in Managers]>><<[m.Name]>><<[Contracts.Where(c => c.ManagerID==m.ID).Sum(c => c.Price)]>>
<<foreach [c in Contracts.Where(c => c.ManagerID==m.ID)]» «[c.Clients.Name]>><<[c.Price]>><</foreach>><</foreach>>
Total:<<[Contracts.Sum(c=>c.Price)]>>

ManagerClients
<<foreach [m in Managers]>><<[m.Name]>><<foreach [c in m.Contracts]>><<[c.Clients.Name]>><</foreach>><</foreach>>

Single Column Tables

Single‑column tables are treated differently: when the opening and closing foreach tags are both placed in the same cell, the engine treats that band as a standard data band rather than a table‑row band by default. This displays the content as a basic block of repeated content, similar to a single line of text, rather than as a table row band, which spreads the content across multiple rows. The examples below demonstrate this behaviour.

Example 1: Table-Row Band

Managers Table (Table-Row Band)

Name
<<foreach [m in Managers]>>
<<[m.Name]>>
<</foreach>>

Example 2: Standard Data Band:

Managers List (Standard Data Band)

Managers
<<foreach [m in Managers]>><<[m.Name]>> <</foreach>>

-greedy Switch

The -greedy switch is used to influence how tags are processed, particularly when using nested tags.

When the -greedy switch is applied to a tag, the engine captures as much content as possible for that tag, including any nested tags. This can be particularly useful if you need to ensure that all relevant data is included, even if there are multiple nested instances of the same tag type; the -greedy switch will help ensure that all iterations of the inner tag are captured effectively without being prematurely terminated by the outer tag.

<<foreach [items] -greedy>>
Item: <<[Name]>>
<<foreach [subItems]>>
Sub-item: <<[SubItemName]>>
<</foreach>>
<</foreach>>

Merging Cells

You can dynamically merge table cells with the same textual contents using cellMerge tags.

<<cellMerge -horz>>

A horizontal switch is optional. If the switch is present, it denotes a cell merging operation in a horizontal direction. If the switch is missing, it means that a cell merging operation is to be performed in a vertical direction (the default).

For two or more successive table cells to be merged, in either direction, the following requirements must be met:

  • Each of the cells must contain a cellMerge tag, indicating a cell merging operation in the same direction.
  • Each of the cells must not be already merged in another direction.
  • The cells must have equal textual contents (ignoring leading and trailing whitespaces).

Consider the following template.

...
<<cellMerge>><<[value1]>>
...
<<cellMerge>><<[value2]>>

If value1 and value2 have the same value, say “Hello”, table cells containing cellMerge tags are successfully merged during runtime:

...
Hello
...

If value1 and value2 have different values, say “Hello” and “World”, table cells containing cellMerge tags are not merged during runtime:

...
Hello
...
World

Charts

You can create and manipulate different types of dynamically populated charts by following these steps:

  1. Add a Chart to Your Template: Place a chart in your template at the desired location in the document.
  2. Configure your Chart Appearance: Set up the visual aspects of the chart as needed.
  3. Use foreach Tags: To populate the chart with dynamic data, include a foreach tag in the chart title. This allows the charts to iterate over a data collection.
  4. Add Chart Series: Define the chart series and configure their appearance. This can be done by right clicking on the chart, and selecting ‘Edit Data’. Update the Series Name by adding a template expression into the Series Name. This will populate that series with data from the data source at runtime.
  5. Define X and Y Values: us X, Y, size and other relevant tags to specify expressions that pull data for the chart series. For example:
  • <<x [x_value_expression]>> for x-values. X values must be declared in the Chart Title, just after the <<foreach>> opening tag.

  • <<y [y_value_expression]>> for y-values. Y values must be declared in Series Titles.

  • The expressions must return appropriate data types as per the chart requirements.

  • If you want to conditionally include or exclude chart series based on certain criteria, you can use the removeif tag to specify conditions under which series should not be displayed.

An example of a pie chart before data has been inserted: an example chart


  • Colours can be set dynamically using seriesColor or pointColor tags, allowing for customised data.
Chart Title: <<chartTitle>>
<<foreach [managers]>>
Series Name: <<seriesName [Name]>>
<<seriesColor [Color]>>
<<y [Contracts.Sum(Price)]>>
<<removeif [some_condition]>>
<<endforeach>>

Here’s an example of how the tags might look in your template:

Chart Title: <<chartTitle>>
<<foreach [managers]>>
Series Name: <<seriesName [Name]>>
<<seriesColor ["#FF5733"]>>
<<seriesColor ["#33C3FF"]>>
<<y [Contracts.Sum(Price)]>>
<</foreach>>

In this example:

  • <<chartTitle>> sets the dynamic title of the chart.
  • <<seriesName [Name]>> sets the name of each series based on the manager’s name.
  • <<seriesColor [Color]>> assigns a colour to each series.
  • <<y [Contracts.Sum(Price)]>> specifies the y-value for the series.

By following these steps and using the appropriate tags, you can configure the chart appearance in your report.