Control Flow
Beyond calling functions to produce values, JsonFabrica templates support two block constructs for shaping the generated document: for loops for repeating a section of the template, and if/elseIf/else conditionals for including a section only when a condition holds. These are template-level constructs, not functions — they use their own block syntax rather than the <functionName(...)> call form described on the Function Reference page.
For loops
A for block repeats its body once per iteration, over an inclusive integer range:
<for(varName, start, end)> ...body... <end_for>- Both bounds are inclusive.
<for(i, 0, 2)>runs 3 times, withitaking the values0,1, then2. - Inside the loop body, read the current index with
<getVar(varName)>. - The loop variable only exists inside the loop —
<getVar(varName)>after the matching<end_for>fails with anUNDEFINED_VARIABLEerror. startandenddon't have to be literals — they can be a param (getParam(...)) or a variable set earlier in the template (getVar(...)), for example one populated bygetRandomNumber(..., assignToVar='n')or bysetVar.
If / elseIf / else
An if block includes exactly one of its branches, based on the first condition that evaluates truthy:
<if(expr)> A <elseIf(expr2)> B <else> C <endIf>This renders A if expr is truthy, otherwise B if expr2 is truthy, otherwise C. Both elseIf and else are optional — you can write a bare <if(expr)> A <endIf> or chain as many elseIf clauses as you need, but the block always closes with a single <endIf>.
Operators
Conditions are expressions built from getVar(...), getParam(...), literals, and the operators below, evaluated with standard precedence — from tightest to loosest binding:
| Precedence | Operators | Meaning |
|---|---|---|
| 1 (tightest) | ! | logical not |
| 2 | < > <= >= | relational |
| 3 | == != | equality |
| 4 | && | logical and |
| 5 (loosest) | || | logical or |
Nesting
for blocks and if blocks can be nested inside each other, to any depth — a for containing an if, an if containing a for, or several levels of both. Each block must still be closed with its own matching <end_for> or <endIf>.
Worked examples
1. Basic loop building a JSON array
An inline if is used here just to avoid emitting a trailing comma after the last element.
{ "items": [<for(i, 0, 2)><getVar(i)><if(getVar(i) < 2)>,<endIf><end_for>] }produces { "items": [0,1,2] }
2. A loop bound set by a variable earlier in the template
start and end can be getVar(...) lookups instead of literals — here n is set with setVar before the loop, but it could equally come from getRandomNumber(..., assignToVar='n') or getParam(n).
{ "items": [<setVar(n, 3)><for(i, 0, getVar(n))><getVar(i)><if(getVar(i) < getVar(n))>,<endIf><end_for>] }produces { "items": [0,1,2,3] } — 4 iterations, because n is 3 and the end bound is inclusive.
3. if / elseIf / else classifying a generated value
A random score is generated and stored with assignToVar, then classified into one of three tiers.
{ "score": <getRandomNumber(1, 100, 0, score)>, "tier": "<if(getVar(score) < 34)>low<elseIf(getVar(score) < 67)>medium<else>high<endIf>" }one possible output: { "score": 63, "tier": "medium" } — the exact score varies by seed, but tier always matches which of the three ranges it falls into.
4. Compound boolean expression and operator precedence
&& binds tighter than ||, and relational/equality operators bind tighter than both — so a > 1 && b == 2 parses as (a > 1) && (b == 2), not as a single flat comparison.
{ "v": "<setVar(a, 5)><setVar(b, 2)><if(getVar(a) > 1 && getVar(b) == 2)>YES<else>NO<endIf>" }produces { "v": "YES" } — both a > 1 (5 > 1) and b == 2 are true.
With a set to 0 instead (same template otherwise), a > 1 is false, so the whole && expression is false and it produces { "v": "NO" }.
5. Nesting — for containing if
A 2×3 grid, generated with an outer for over rows, an inner for over columns, and an if inside the inner loop to special-case the middle column.
{ "rows": [<for(row, 0, 1)>{ "row": <getVar(row)>, "cells": [<for(col, 0, 2)><if(getVar(col) == 1)>"mid"<else><getVar(col)><endIf><if(getVar(col) < 2)>,<endIf><end_for>] }<if(getVar(row) < 1)>,<endIf><end_for>] }produces { "rows": [{ "row": 0, "cells": [0,"mid",2] },{ "row": 1, "cells": [0,"mid",2] }] }
Errors
Referencing a loop variable outside its for/end_for block, or leaving a block unclosed (a for without a matching end_for, or an if without a matching endIf), fails template generation with a descriptive error rather than producing partial output.
See the Function Reference for every function you can call inside a condition, a loop bound, or anywhere else in a template.