Inja is a modern C++ template engine inspired by Jinja2, designed for rendering dynamic text using JSON data. It’s lightweight, header-only, and integrates seamlessly with C++ projects. This expanded reference provides a comprehensive guide to Inja’s features, syntax, and advanced usage, including detailed explanations of control structures, logical operators, and additional template features.
- Overview
- Setup
- Basic Usage
- Template Syntax
- C++ Integration
- Custom Callbacks
- Best Practices
- Resources
- Jinja2-inspired syntax for templates.
- Header-only, dependency-light (requires nlohmann/json).
- Supports variables, loops, conditionals, filters, functions, comments, and custom callbacks.
- Fast, memory-efficient, and suitable for both simple and complex templating needs.
Inja is header-only and requires the nlohmann/json library. Include it in your project:
-
Add Dependencies:
- Download Inja: GitHub Repository.
- Download nlohmann/json: GitHub Repository.
- Include headers in your project.
-
CMake Example:
find_package(nlohmann_json REQUIRED)
add_executable(myapp main.cpp)
target_include_directories(myapp PRIVATE /path/to/inja/include)
target_link_libraries(myapp PRIVATE nlohmann_json::nlohmann_json)- C++ Includes:
#include <inja/inja.hpp>
#include <nlohmann/json.hpp>Render a template with JSON data using Inja’s core components: inja::Environment and nlohmann::json.
Example:
#include <inja/inja.hpp>
#include <nlohmann/json.hpp>
#include <iostream>
int main() {
inja::Environment env;
nlohmann::json data;
data["name"] = "World";
std::string result = env.render("Hello {{ name }}!", data);
std::cout << result << std::endl; // Outputs: Hello World!
return 0;
}inja::Environment: Manages template parsing and rendering.nlohmann::json: Stores data for template substitution.env.render: Renders a template string with JSON data.
Inja uses Jinja2-like syntax for templates, supporting variables, control structures, filters, functions, and comments.
Access JSON data using {{ variable }}.
Hello {{ name }}!Nested access:
{{ user.address.city }}Safe access with default:
{{ user.address.city | default("Unknown") }}Inja supports advanced control structures for dynamic template rendering.
The set statement assigns values to variables within a template, useful for temporary calculations or formatting.
Syntax:
{% set variable = value %}Example:
{% set greeting = "Hello, " + name %}
{{ greeting }}! {# Outputs: Hello, World! #}You can also set multiple variables:
{% set first_name = "John" %}
{% set last_name = "Doe" %}
{{ first_name }} {{ last_name }} {# Outputs: John Doe #}You can also use the set statement to define object-style variables directly inside a template. This is useful for encapsulating structured data like server configurations:
{% set server_list = {
"server_name": "Test",
"download_url": "https://localhost:8443/downloading",
"upload_url": "https://localhost:8443/upload"
} %}
#### If Statements
Conditionals control template output based on boolean expressions.
Syntax:
```jinja
{% if condition %}
True case
{% elif another_condition %}
Another case
{% else %}
False case
{% endif %}Example:
{% if age >= 18 %}
Adult
{% elif age >= 13 %}
Teen
{% else %}
Child
{% endif %}Nested conditionals:
{% if user.is_active %}
{% if user.role == "admin" %}
Admin Dashboard
{% else %}
User Dashboard
{% endif %}
{% else %}
Please log in
{% endif %}Loops iterate over arrays or objects in JSON data.
Syntax:
{% for item in list %}
{{ item }}
{% endfor %}Example:
<ul>
{% for user in users %}
<li>{{ user.name }} ({{ user.email }})</li>
{% endfor %}
</ul>Loop over object properties:
{% for key, value in user %}
{{ key }}: {{ value }}
{% endfor %}Loop variables:
loop.index: 1-based index (starts at 1).loop.index0: 0-based index (starts at 0).loop.first: True if first iteration.loop.last: True if last iteration.
Example:
{% for item in items %}
{% if loop.first %}
First item: {{ item }}
{% elif loop.last %}
Last item: {{ item }}
{% else %}
Item {{ loop.index }}: {{ item }}
{% endif %}
{% endfor %}Inja supports logical operators for complex conditions:
and: True if both operands are true.or: True if at least one operand is true.not: Negates a condition.- Parentheses
(): Group expressions for precedence.
Example:
{% if age >= 18 and user.is_active %}
Active adult user
{% endif %}
{% if role == "admin" or role == "editor" %}
Authorized user
{% endif %}
{% if not user.is_blocked %}
Access granted
{% endif %}
{% if (age >= 18 or role == "admin") and user.is_active %}
Special access
{% endif %}Filters transform data: {{ variable | filter }}.
Common filters:
upper: Convert to uppercase.lower: Convert to lowercase.default(value): Use default if variable is missing.join(sep): Join array elements with separator.length: Get length of string or array.trim: Remove leading/trailing whitespace.replace(old, new): Replace occurrences of a string.sort: Sort an array.
Example:
{{ name | upper }} {# WORLD #}
{{ items | join(", ") }} {# item1, item2, item3 #}
{{ missing | default("N/A") }} {# N/A #}
{{ text | trim }} {# Removes whitespace #}
{{ text | replace("hello", "hi") }} {# Replaces 'hello' with 'hi' #}
{{ numbers | sort }} {# Sorts array in ascending order #}Inja supports built-in functions for dynamic operations:
range(n): Generate array[0, 1, ..., n-1].is_type: Check JSON type (e.g.,is_string,is_number,is_array,is_object).exists: Check if variable exists.existsIn(object, key): Check if a key exists in an object.first: Get first element of an array.last: Get last element of an array.
Example:
{% for i in range(3) %}
{{ i }} {# Outputs: 0 1 2 #}
{% endfor %}
{% if is_string(name) %}
Name is a string
{% endif %}
{% if exists("user") %}
User exists
{% endif %}
{{ items | first }} {# First item of array #}Template comments are ignored during rendering.
Syntax:
{# This is a comment #}Multi-line comments:
{# This is a
multi-line comment #}Example:
{# Display user info #}
{{ name }} {# Renders name, comment is ignored #}Load templates from strings or files.
From string:
std::string result = env.render("Hello {{ name }}!", data);From file:
inja::Environment env;
env.set_search_path("/path/to/templates");
std::string result = env.render_file("template.html", data);Handle parsing and rendering errors with try-catch.
Example:
try {
std::string result = env.render("{{ undefined }}", data);
} catch (const inja::InjaError& e) {
std::cerr << "Inja error: " << e.what() << std::endl;
} catch (const nlohmann::json::exception& e) {
std::cerr << "JSON error: " << e.what() << std::endl;
}Customize delimiters or other settings.
Example:
inja::Environment env;
env.set_statement("<%", "%>"); // Change statement delimiters
env.set_expression("[[", "]]"); // Change variable delimiters
env.set_comment("{#", "#}"); // Change comment delimitersDisable whitespace trimming:
env.set_trim_blocks(false);
env.set_lstrip_blocks(false);Extend Inja with custom filters and functions.
Add a filter to transform data.
Example:
env.add_callback("double", 1, [](inja::Arguments& args) {
double value = args.at(0)->get<double>();
return value * 2.0;
});Usage:
{{ 5 | double }} {# Outputs: 10 #}Add a function for custom logic.
Example:
env.add_callback("greet", 1, [](inja::Arguments& args) {
std::string name = args.at(0)->get<std::string>();
return "Hello, " + name + "!";
});Usage:
{{ greet(name) }} {# Outputs: Hello, World! #}Multiple arguments:
env.add_callback("sum", 2, [](inja::Arguments& args) {
double a = args.at(0)->get<double>();
double b = args.at(1)->get<double>();
return a + b;
});Usage:
{{ sum(3, 4) }} {# Outputs: 7 #}- Validate JSON Data: Ensure JSON data is complete to avoid runtime errors.
- Use Error Handling: Always wrap
rendercalls in try-catch blocks. - Modular Templates: Use
{% include %}for reusable template components. - Optimize Filters: Avoid complex logic in templates; use C++ callbacks for heavy computation.
- Sanitize Inputs: Escape user inputs to prevent injection attacks (use
escapefilter if available). - Test Templates: Test templates with edge cases (empty arrays, missing keys).
- Official Inja Documentation: GitHub
- nlohmann/json Documentation: GitHub
- Jinja2 Documentation (for syntax inspiration): Jinja2 Docs