This Python-based template engine allows for powerful data transformations using familiar syntax like if/else logic and loops. It is ideal for rendering JSON-like data structures and can easily be extended for more advanced use cases.
To use Python expressions in the Config declarations of templates, the eval(…) expression is implemented without keyword restrictions. You can easily add a restricted expression in the resolve_template() function.
This project demonstrates a Python-based template engine inspired by STJS that supports features such as:
-
Loops using
#each. -
Conditionals using
#if/#else. -
Dynamic placeholders within templates using
{{ }}expressions. -
Python expression evaluation within templates.
The engine can handle complex data structures with nested dictionaries and lists, making it versatile for transforming JSON-like data.
—
- Overview
- Features
- Installation
- Usage
- Code Overview
- Example Data and Templates
- Expected Output
- Conclusion
—
This engine mimics template-based rendering commonly found in JavaScript but implemented in Python. It allows transforming JSON-like data using templates with:
- Conditionals (if/else logic).
- Loops for iterating over collections.
- String interpolation for placeholders in templates.
—
- #each Directive: Loop over lists and apply templates.
- #if Directive: Apply conditional logic.
- {{ }} Expressions: Embed Python expressions directly in templates.
- Nested Dictionary Access: Use dot-separated paths to access deeply nested data.
—
No additional libraries are required.
—
- Define your data structure.
- Create a template that uses
#each,#if, and{{ }}placeholders. - Use the
transform()function to apply the template to your data.
—
This function retrieves a value from a nested dictionary using a dot-separated path.
def get_value_by_path(data, path):
“””Retrieve a value from nested dictionaries using dot-separated paths.”””
keys = path.split(“.”)
result = data
try:
for key in keys:
result = result[key]
return result
except (KeyError, TypeError):
return None—
This function processes templates with {{ }} placeholders and supports Python expressions.
def resolve_template(template, context):
“””Replace all {{ }} expressions with evaluated results from the context.”””
def replace_match(match):
expression = match.group(1).strip()
try:
return str(eval(expression, {}, context))
except Exception as e:
print(f”Error evaluating expression ‘{expression}’: {e}”)
value = get_value_by_path(context, expression)
if value is None:
print(f”Error resolving path ‘{expression}’: Path not found.”)
return “”
return str(value)
return re.sub(r”{{(.*?)}}”, replace_match, template)—
This function applies the #each directive to iterate over a list in the context.
def handle_each(path, template, context):
“””Iterate over items at the given path and apply the template to each.”””
items = get_value_by_path(context, path) or []
return [transform(template, item) for item in items]This function applies the #if directive to evaluate conditions.
def handle_if(condition, then_template, else_template, context):
“””Evaluate a condition and apply either the ‘then’ or ‘else’ template.”””
condition_value = resolve_template(condition, context)
if condition_value.lower() in [“true”, “1”]:
return transform(then_template, context)
else:
return transform(else_template, context)—
This function applies the template to the given context.
def transform(template, context):
“””Apply a template to the given context, handling #each and #if directives.”””
result = {}
if not isinstance(template, dict):
return template
for key, value in template.items():
if key == “#each”:
return handle_each(value, template.get(“template”, {}), context)
elif key == “#if”:
condition = value.get(“condition”)
then_template = value.get(“then”, {})
else_template = value.get(“else”, {})
return handle_if(condition, then_template, else_template, context)
elif isinstance(value, str) and “{{“ in value:
result[key] = resolve_template(value, context)
elif isinstance(value, dict):
result[key] = transform(value, context)
else:
result[key] = value
return result—
data_simple = {
“employees”: [
{“name”: “Alice”, “role”: “Manager”, “active”: True},
{“name”: “Bob”, “role”: “Engineer”, “active”: False},
{“name”: “Charlie”, “role”: “Designer”, “active”: True},
{“name”: “David”, “role”: “Intern”, “active”: False}
]
}template_simple = {
“employees”: {
“#each”: “employees”,
“template”: {
“employeeName”: “{{name}}”,
“role”: “{{role}}”,
“status”: “{{‘Active’ if active else ‘Inactive’}}”,
“category”: {
“#if”: {
“condition”: “{{role == ‘Manager’}}”,
“#then”: “Category: Management”,
“#else”: {
“#if”: {
“condition”: “{{role == ‘Engineer’}}”,
“#then”: “Category: Technical”,
“#else”: {
“#if”: {
“condition”: “{{role == ‘Designer’}}”,
“#then”: “Category: Creative”,
“#else”: “Category: General”
}
}
}
}
}
}
}
}
}—
{
“employees”: [
{
“employeeName”: “Alice”,
“role”: “Manager”,
“status”: “Active”,
“category”: “Category: Management”
},
{
“employeeName”: “Bob”,
“role”: “Engineer”,
“status”: “Inactive”,
“category”: “Category: Technical”
},
{
“employeeName”: “Charlie”,
“role”: “Designer”,
“status”: “Active”,
“category”: “Category: Creative”
},
{
“employeeName”: “David”,
“role”: “Intern”,
“status”: “Inactive”,
“category”: “Category: General”
}
]
}