This document describes the syntax of the scriban templating language.
NOTE: This document does not describe the
liquid
language. Check theliquid website
directly.
if <expression>
, else
, else if <expression>
case
and when
capture <variable> ... end
readonly <variable>
import <variable_path>
with <variable> ... end
wrap <function> <arg1...argn> ... end
include <name> arg1?...argn?
ret <expression>?
There are 3 types of block of text in a template:
A text enclosed by {{
and }}
is a scriban code block that will be evaluated by the scriban templating engine.
A scriban code block may contain:
{{ name }}
{{
if ![name_32x32.png](/help/_images/name_32x32.png)
name = "default"
end
name
}}
;
to allow compact forms in some use cases:
{{if ![name_32x32.png](/help/_images/name_32x32.png); name = "default"; end; name }}
Inside a code block, except for the EOL after each statement, white spaces characters are not affecting the parsing. There is only one case where whitespace is used to disambiguate between an array indexer and an array initializer.
Also, if a statement is an expression (but not an assignment expression), the result of the expression will be output to the rendering output of the template:
input
{{
x = "5" # This assignment will not output anything
x # This expression will print 5
x + 1 # This expression will print 6
}}
output
56
Note that in the previous example, there is no EOL between 5
and 6
because we are inside a code block.
You can still use a plain string with an EOL inside a code block "\n"
or you could use mixed code and text blocks:
input
{{ x = "5" }}
{{ x }}
{{ x + 1 }}
output
5
6
Otherwise, any text is considered as a text block and simply output as is
Hello this is {{ name }}, welcome to scriban!
______________ _____________________
^ text block ^ text block
Any code and text block can be escaped to produce a text block by enclosing it with {%{
and }%}
For example the following escape:
input:
{%{Hello this is {{ name }}}%}
output:Hello this is {{ name }}
Any escape block can be also escaped by increasing the number of %
in the starting and ending block:
input:
{%%{This is an escaped block: }%} here}%%}
output:This is an escaped block: }%} here
This allow effectively to nest escape blocks and still be able to escape them.
Hence a starting escape block {%%%%{
will required an ending }%%%%}
By default, any whitespace (including new lines) before or after a code/escape block are copied as-is to the output.
Scriban provides two modes for controlling whitespace:
The greedy mode using the character -
(e.g {{-
or -}}
), removes any whitespace, including newlines
Examples with the variable name = "foo"
:
Strip whitespace on the left:
input
This is a <
{{- name}}> text
output
This is a <foo> a text
Strip on the right:
input
This is a <{{ name -}}
> text:
output
This is a <foo> text
Strip on both left and right:
input
This is a <
{{- name -}}
> text:
output
This is a <foo> text
The non greedy mode using the character ~
{{~
will remove any whitespace before but will stop on the first newline without including it~}}
will remove any whitespace after including the first newline but will stop afterThis mode is very convenient when you want to use only a scriban statement on a line, but want that line to be completely removed from the output, but to keep spaces before and after this line intact.
In the following example, we want to remove entirely the lines {{~ for product in products ~}}
and {{~ end ~}}
, but we want
for example to keep the indentation of the opening <li>
.
Using the greedy mode {{-
or -}}
would have removed all whitespace and lines and would have put the results on a single line.
input
<ul>
{{~ for product in products ~}}
<li>{{ product.name }}</li>
{{~ end ~}}
</ul>
output
<ul>
<li>Orange</li>
<li>Banana</li>
<li>Apple</li>
</ul>
Both mode ~
and '-' can also be used with escape blocks {%%{~
or ~}%%}
or {%%{-
or -}%%}
Within a code block, scriban supports single line comments #
and multi-line comments ##
:
{{ name # this is a single line comment }}
input
{{ ## This
is a multi
line
comment ## }}
output
As you can notice, both single line and multi-line comments can be closed by the presence of a code block exit tag }}
Scriban supports two types of strings:
regular strings enclosed by double quotes "..."
or simple quotes '...'
. Regular strings supports multiline and will interpret the following escape sequences:
\'
single quote\"
double quote\\
backslash\n
new line\r
carriage return\t
tab\b
backspace\f
form feed\uxxxx
where xxxx is a unicode hexa code number 0000
to ffff
\x00-\xFF
a hexadecimal ranging from 0x00
to 0xFF
verbatim strings enclosed by backstick quotes `...`
. They are, for example, useful to use with for regex patterns :
input
{{ "this is a text" | regex.split `\s+` }}
output
[this, is, a, test]
A number in scriban {{ 100 }}
is similar to a javascript number:
100
, 1e3
100.0
, 1.0e3
, 1.0e-3
The boolean value {{ true }}
or {{ false }}
input
{{ true }}
{{ false }}
output
true
false
The null value {{ null }}
When resolving to a string output, the null value will output an empty string:
input
{{ null }}
output
Scriban supports the concept of global and local variables
A global/property variable like {{ name }}
is a liquid like handle, starting by a letter or underscore _
and following by a letter A-Z a-z
, a digit 0-9
, an underscore _
The following text are valid variable names:
var
var9
_var
NOTE: In liquid, the character
-
is allowed in a variable name, but when translating it to a scriban, you will have to enclose it into a quoted string
A local variable like {{ $name }}
is an identifier starting with $
. A local variable is only accessible within the same include page or function body.
The special local variable $
alone is an array containing the arguments passed to the current function or include page.
The special local variables $0
$1
... $n
is a shorthand of $[0]
, $[1]
... $[n]
. e.g Using $0
returns the first argument of the current function or including page.
this
The this
variable gives you access to the current object bound where you have access to all local variables for the current scope.
Thus the following variable access are equivalent:
input
{{
a = 5
a # output 5
this.a = 6
a # output 6
this["a"] = 7
a # output 7
}}
output
567
In the case of the with
statement, the this operator refers to the object passed to with
:
input
{{
a = {x: 1, y: 2}
with a
b = this
end
b.x
}}
output
1
empty
The empty
variable represents simply an empty object. It is mainly relevant to be compatible with liquid, by providing a way to compare an object with the empty
object to check if it is empty or not:
input
{{
a = {}
b = [1, 2]~}}
{{a == empty}}
{{b == empty}}
output
true
false
Scriban supports javascript like objects {...}
An object can be initialized empty :
{{ myobject = {} }}
An object can be initialized with some members:
{{ myobject = { member1: "yes", member2: "no" } }}
or use a json syntax:
{{ myobject = { "member1": "yes", "member2": "no" } }}
An object can be initialized with some members over multiple lines:
{{
myobject = {
member1: "yes",
member2: "no"
}
}}
Members of an object can be accessed:
{{ myobject.member1 }}
also equivalent to {{ myobject["member1"] }}
If the object is a "pure" scriban objects (created with a {...}
or instantiated by the runtime as a ScriptObject
), you can also add members to it with a simple assignment:
input
{{
myobject = {}
myobject.member3 = "may be"
myobject.member3
}}
output
may be
NOTICE
By default, Properties and methods of .NET objects are automatically exposed with lowercase and
_
names. It means that a property likeMyMethodIsNice
will be exposed asmy_method_is_nice
. This is the default convention, originally to match the behavior of liquid templates. If you want to change this behavior, you need to use aMemberRenamer
delegate
empty?
Any object can respond the the property .empty?
to check if it is empty or not:
input
{{
a = {}
b = [1, 2]~}}
{{a.empty?}}
{{b.empty?}}
output
true
false
An array can be initialized empty :
{{ myarray = [] }}
An array can be initialized with some items:
{{ myarray = [1, 2, 3, 4] }}
An array can be initialized with some items over multiple lines:
{{
myarray = [
1,
2,
3,
4,
]
}}
Items of an array can be zero-based indexed:
{{ myarray[0] }}
If the array is a "pure" scriban array (created with a [...]
or instantiated by the runtime as a ScriptArray
), you can also add items to it with a simple assignment that will expand automatically the array depending on the index:
{{
myarray = []
myarray[0] = 1
myarray[1] = 2
myarray[2] = 3
myarray[3] = 4
}}
You can also manipulate arrays with the array
builtin object.
Important notice
While whitespace characters are mostly not relevant while parsing in scriban, there is a case where a whitespace helps to disambiguate between an array indexer and an array initializer.
For instance, if a whitespace is found before a
[
and the previous expression was a variable path expressions (see later), the following expression[...]
will be considered as an array initializer instead of an array indexer:{{ myfunction [1] # There is a whitespace after myfunction. # It will result in a call to myfunction passing an array as an argument myvariable[1] # Without a whitespace, this is accessing # an element in the array provided by myvariable }}
An array can also contains attached properties:
input
{{
a = [5, 6, 7]
a.x = "yes"
a.x + a[0]
}}
output
yes5
size
propertyArrays have a size
property that can be used to query the number of elements in the array:
input
{{
a = [1, 2, 3]
a.size
}}
output
3
Scriban allows to define functions:
The following declares a function sub
that uses its first argument and subtract from it the second argument:
{{func sub
ret $0 - $1
end}}
All argument are passed to the special variable $
that will contain the list of direct arguments
and named arguments:
$0
or $[0]
will access the first argument$1
or $[1]
will access the second argument$[-1]
will access the last argument$.named
will access the named argument named
This function can then be used:
input
{{sub 5 1}}
{{5 | sub 1}}
output
4
4
As you can notice from the example above, when using the pipe, the result of the pipe is pushed as the first argument of the pipe receiver.
Note that a function can have mixed text statements as well:
{{func inc}}
This is a text with the following argument {{ $0 + 1 }}
{{end}}
Because functions are object, they can be stored into a property of an object by using the alias @
operator:
{{
myobject.myinc = @inc # Use the @ alias operator to allow to
# use a function without evaluating it
x = 1 | myobject.myinc # x = x + 1
}}
The function aliasing operator @
allows to pass a function as a parameter to another function, enabling powerful function compositions.
Scriban supports conventional unary and binary expressions.
A variable path expression contains the path to a variable:
{{ name }}
e.g resolve to the top level variable name
{{ myarray[1] }}
e.g resolve to the top level variable myarray
and an indexer to the array{{ myobject.member1.myarray[2] }}
e.g resolve to the top level variable myobject
, then the property member1
this object, the property myarray
and an indexer to the array returned by myarray
Note that a variable path can either point to a simple variable or can result into calling a parameter less function.
A value can be assigned to a top level variable or to the member of an object/array:
{{ name = "foo" }}
e.g Assign the string "foo"
the variable name
{{ myobject.member1.myarray[0] = "foo" }}
An assign expression must be a top level expression statement and cannot be used within a sub-expression.
An expression enclosed by (
and )
{{ name = ('foo' + 'bar') }}
The following binary operators are supported for numbers:
Operator | Description |
---|---|
<left> + <right> |
add left to right number |
<left> - <right> |
substract right number from left |
<left> * <right> |
multiply left by right number |
<left> / <right> |
divide left by right number |
<left> // <right> |
divide left by right number and round to an integer |
<left> % <right> |
calculates the modulus of left by right |
If left or right is a float and the other is an integer, the result of the operation will be a float.
The following binary operators are supported for strings:
Operator | Description |
---|---|
'left' + <right> |
concatenates left to right string: "ab" + "c" -> "abc" |
'left' * <right> |
concatenates the left string right times: 'a' * 5 -> aaaaa . left and right and be swapped as long as there is one string and one number. |
As long as there is a string in a binary operation, the other part will be automatically converted to a string.
The following literals are converted to plain strings:
null -> ""
. e.g: "aaaa" + null -> "aaaa"
0 -> "0"
1.0 -> "1.0"
true -> "true"
false -> "false"
A conditional expression produces a boolean by comparing a left and right value.
Operator | Description |
---|---|
<left> == <right> |
Is left equal to right? |
<left> != <right> |
Is left not equal to right? |
<left> > <right> |
Is left greater than right? |
<left> >= <right> |
Is left greater or equal to right? |
<left> < <right> |
Is left less than right? |
<left> <= <right> |
Is left less or equal to right? |
They work with both numbers
, strings
and datetimes.
You can combine conditionnal expressions with &&
(and operator) and ||
(or operator)
Operator | Description |
---|---|
<left> && <right> |
Is left true and right true? |
<left> || <right> |
Is left true or right true? |
Operator | Description |
---|---|
! <expression> |
Boolean negate an expression. e.g if ![page_32x32.png](/help/_images/page_32x32.png) |
+ <expression> |
Arithmetic positive an expression. e.g +1.5 |
- <expression> |
Arithmetic negate an expression |
^ <expression> |
Expand an array passed to arguments of a function call (see function call) |
@ <expression> |
Alias the result of an expression that would be evaluated if it was a function call |
They are special binary expressions that provides an iterator (used usually with the for
statement)
The evaluated left
and right
expressions must resolve to an integer at runtime.
Operator | Description |
---|---|
left..right |
Returns an iterator between left and right with a step of 1, including right . e.g: 1..5 iterates from 1 to 5 |
left..<right |
Returns an iterator between left and right with a step of 1, excluding right . e.g: 1..<5 iterates from 1 to 4 |
??
The operator left ?? right
can be used to return the right
value if left
is null.
A function can be called by passing parameters separated by a whitespace:
{{ myfunction arg1 "arg2" (1+5) }}
The pipe operator |
can also be used to pipe the result of an expression to a function:
{{ date.parse '2016/01/05' | date.to_string '%g' }}
will output 06 Jan 2016
Notice that when a function receives the result of a pipe call (e.g
date.to_string
in the example above), it is passed as the first argument of the call. This is valid for both .NET custom functions as well as for Scriban integrated functions.
When passing multiple arguments to an existing .NET function, you may want to use named arguments.
Suppose you have declared a .NET function like this:
public static string MyProcessor(string left, string right, int count, string options = null)
{
// ...
}
You can call this function from scriban with the following syntax:
{{ my_processor "Hello" "World" count: 15 options: "optimized" }}
with a pipe we could rewrite this to:
{{ "Hello" | my_processor "World" count: 15 options: "optimized" }}
Note that once arguments are named, the following arguments must be all named.
In a custom function declared with func
named arguments are accessible through the variable arguments variable $
, but as properties (and not as part of the default array arguments):
input
{{
func my_processor
"Argument count:" + $.count
"Argument options:" + $["options"]
for $x in $
"arg[" + $x + "]: " + $x
end
end
my_processor "Hello" "World" count: 15 options: "optimized"
}}
output
Argument count: 15
Argument options: optimized
arg[0]: Hello
arg[1]: World
Each statement must be terminated by a code block }}
or an EOL within a code block, or a semicolon to separate multiple statements on a single line within a code block.
An expression statement:
{{ value + 1 }}
e.g Evaluates value + 1
and output the result
{{
value + 1 # This is a single line expression statement followed by this comment
}}
if <expression>
, else
, else if <expression>
The general syntax is:
{{
if <expression>
...
else if <expression>
...
else
...
end
}}
An if
statement must be closed by an end
or followed by a else
or else if
statement. An else
or else if
statement must be followed by a else
, else if
or closed by an end
statement.
An expression evaluated for a if
or else if
will be converted to a boolean.
By default, only the null
and boolean false
are considered as false
when evaluated as booleans.
The following values are used for converting literals to boolean:
0 -> true
1 -> true
or any non zero valuenull -> false
false -> false
non_null_object -> true
"" -> true
An empty string returns true"foo" -> true
Example testing a page object:
{{ if ![page_32x32.png](/help/_images/page_32x32.png) }}Page is not null{{ else }}Page is null!{{ end }}
case
and when
This is the equivalent of switch
statement in C#, a selection statement that chooses a single switch section to execute from a list of candidates based on a value matching.
case <expression>
opens a switch with an expressionwhen <match>
allows to match with the specified expression and the case expression
when
can also be used with multiple values separated by ,
or ||
else
can be used to as a default handler in case nothing matched.input
{{
x = 5
case x
when 1, 2, 3
"Value is 1 or 2 or 3
when 5
"Value is 5"
else
"Value is " + x
end
}}
output
Value is 5
for <variable> in <expression> ... end
{{for <variable> in <expression>}}
...
{{end}}
The expression can be an array or a range iterator:
Loop on an array: {{ for page in pages }}This is the page {{ page.title }}{{ end }}
Loop on a range: {{ for x in 1..n }}This is the loop step [{{x}}]{{ end }}
The for loop (along with the tablerow
statement below) supports additional parameters, offset
, limit
and reversed
that can also be used togethers:
offset
parameterAllows to start the iteration of the loop at the specified zero-based index:
input
{{~ for $i in 4..9 offset:2 ~}}
{{ $i }}
{{~ endfor ~}}
output
6
7
8
9
limit
parameterAllows to limit the iteration of the loop for the specified count
input
{{~ for $i in 4..9 limit:2 ~}}
{{ $i }}
{{~ endfor ~}}
output
4
5
reversed
parameterAllows to reverse the iteration on the elements
input
{{~ for $i in 1..3 reversed ~}}
{{ $i }}
{{~ endfor ~}}
output
3
2
1
while <expression> ... end
{{while <expression>}}
...
{{end}}
Like the if
statement, the expression
is evaluated to a boolean.
tablerow <variable> in <expression> ... end
This function generates HTML rows compatible with an HTML table. Must be wrapped in an opening
This statement is mainly for compatibility reason with the liquid tablerow
tag.
It has overall the same syntax as a for
statement (supporting the same parameters).
{{tablerow <variable> in <expression>}}
...
{{end}}
input
<table>
{{~ tablerow $p in products | array.sort "title" -}}
{{ $p.title -}}
{{ end ~}}
</table>
output
<table>
<tr class="row1"><td class="col1">Apple</td></tr>
<tr class="row2"><td class="col1">Banana</td></tr>
<tr class="row3"><td class="col1">Computer</td></tr>
<tr class="row4"><td class="col1">Mobile Phone</td></tr>
<tr class="row5"><td class="col1">Orange</td></tr>
<tr class="row6"><td class="col1">Sofa</td></tr>
<tr class="row7"><td class="col1">Table</td></tr>
</table>
cols
parameterDefines the number of columns to output:
input
<table>
{{~ tablerow $p in (products | array.sort "title") limit: 4 cols: 2 -}}
{{ $p.title -}}
{{ end ~}}
</table>
output
<table>
<tr class="row1"><td class="col1">Apple</td><td class="col2">Banana</td></tr>
<tr class="row2"><td class="col1">Computer</td><td class="col2">Mobile Phone</td></tr>
</table>
The following variables are accessible within a for
block:
Name | Description |
---|---|
{{for.index}} |
The current index of the for loop |
{{for.rindex}} |
The current index of the for loop starting from the end of the list |
{{for.first}} |
A boolean indicating whether this is the first step in the loop |
{{for.last}} |
A boolean indicating whether this is the last step in the loop |
{{for.even}} |
A boolean indicating whether this is an even row in the loop |
{{for.odd}} |
A boolean indicating whether this is an odd row in the loop |
{{for.changed}} |
A boolean indicating whether a current value of this iteration changed from previous step |
Within a while
statement, the following variables can be used:
Name | Description |
---|---|
{{while.index}} |
The current index of the while loop |
{{while.first}} |
A boolean indicating whether this is the first step in the loop |
{{while.even}} |
A boolean indicating whether this is an even row in the loop |
{{while.odd}} |
A boolean indicating whether this is an odd row in the loop |
break
and continue
The break
statement allows to early exit a loop
{{ for i in 1..5
if i > 2
break
end
end }}
The continue
statement allows to skip the rest of a loop and continue on the next step
{{ for i in 1..5
if i == 2
continue
end
}}
[{{i}}]] step
{{ end }}
Will output:
[1] step
[3] step
[4] step
[5] step
capture <variable> ... end
The capture <variable> ... end
statement allows to capture the template output to a variable:
For example the following code:
{{ capture myvariable }}
This is the result of a capture {{ date.now }}
{{ end }}
will set myvariable = "This is the result of a capture 06 Jan 2016\n"
readonly <variable>
The readonly
statement prevents a variable for subsequent assignments:
{{ x = 1 }}
{{ readonly x }}
{{ x = 2 }} <- this will result in a runtime error
import <variable_path>
The import <variable_path>
statement allows to import the members of an object as variables of the current bound:
{{
myobject = { member1: "yes" }
import myobject
member1 # will print the "yes" string to the output
}}
Note that readonly
variables won't be override.
with <variable> ... end
The with <variable> ... end
statement will open a new object context with the passed variable, all assignment will result in setting the members of the passed object.
myobject = {}
with myobject
member1 = "yes"
end
wrap <function> <arg1...argn> ... end
Pass a block of statements to a function that will be able to evaluate it using the special variable $$
{{
func wrapped
for $i in 1..<$0
$$ # This special variable evaluates the block pass
# to the wrap statement
end
end
wrap wrapped 5
$i + " -> This is inside the wrap!\r\n"
end
}}
will output:
1 -> This is inside the wrap!
2 -> This is inside the wrap!
3 -> This is inside the wrap!
4 -> This is inside the wrap!
Note that variables declared outside the with
block are accessible within.
include <name> arg1?...argn?
The include is not a statement but actually a function that allows to parse and render the specified template name. In order to use this function, a delegate to an template loader must be setup on the TemplateOptions.TemplateLoader
property passed to the Template.Parse
method.
include 'myinclude.html'
x = include 'myinclude.html'
x + " modified"
assuming that myinclude.html
is
{{ y = y + 1 ~}}
This is a string with the value {{ y }}
will output:
This is a string with the value 1
This is a string with the value 2 modified
ret <expression>?
The return statement is used to early exit from a top-level/include page or a function.
This is a text
{{~ ret ~}}
This text will not appear
will output:
This is a text
Updated on : 2021-08-11 00:58:11. by : . at T470-01.
*Topic : *