JsonFabrica

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, with i taking the values 0, 1, then 2.
  • 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 an UNDEFINED_VARIABLE error.
  • start and end don't have to be literals — they can be a param (getParam(...)) or a variable set earlier in the template (getVar(...)), for example one populated by getRandomNumber(..., assignToVar='n') or by setVar.

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:

PrecedenceOperatorsMeaning
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.

Template
{ "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).

Template
{ "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.

Template
{ "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.

Template
{ "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.

Template
{ "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.