Jinja2 Recursive Rendering of a Deep Data Structure to YAML: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
(Created page with "=Internal= * Jinja2 =Overview= The method uses recursive macros.")
 
Line 2: Line 2:
* [[Jinja2#Recursive_Rendering_of_a_Deep_Data_Structure|Jinja2]]
* [[Jinja2#Recursive_Rendering_of_a_Deep_Data_Structure|Jinja2]]
=Overview=
=Overview=
The method uses recursive macros.
The method uses a recursive [[Jinja2#Macros|macro]].
 
=The Template=
<syntaxhighlight lang='jinja'>
{%- macro recursively_render_data_structure(d, indentation_index) -%}
{%- if d is number %}{{ d }}
{%- elif d is string %}"{{ d }}"
{%- elif d is mapping -%}
  {%- for key, value in d.items() %}
{{ ' ' * indentation_index }}{{ key }}: {{ recursively_render_data_structure(value, indentation_index + 2) }}
  {%- endfor %}
{%- elif d is iterable %}
  {%- for i in d %}
{{ ' ' * indentation_index }} - {{ recursively_render_data_structure(i, indentation_index + 4) }}
  {%- endfor %}
{%- else %}ERROR: UNKNOWN VALUE {{ d }}
{%- endif %}
{%- endmacro -%}
 
{{- recursively_render_data_structure(m, 0) }}
</syntaxhighlight>
 
=The Rendering Code=
The code includes a test that the rendered structure is equivalent with the input:
<syntaxhighlight lang='py'>
from pathlib import Path
 
import yaml
from jinja2 import Environment, FileSystemLoader
 
tdir = Path('.')
template = Environment(loader=FileSystemLoader(tdir)).get_template('experimental-jinja-template.yaml.j2')
yaml_data = """
config:
  color: blue
  size: 1
  samples:
    - name: venice
      neighborhoods:
        cannaregio: 1
        castello: 2
        giudecca: 3
    - name: genoa
      neighborhoods:
        molo: 1
        foce: 2
        marassi: 3
    - name: florence
      neighborhoods:
        santamaria: 1
        sanmarco: 2
        santacroce: 3
        no-such-neighborhood:
          - a1: v1
            a2: v2
          - b
          - c
"""
m = yaml.safe_load(yaml_data)
rendered_text = template.render(m=m)
print(rendered_text)
 
m2 = yaml.safe_load(rendered_text)
assert m == m2
</syntaxhighlight>

Revision as of 22:30, 23 August 2023

Internal

Overview

The method uses a recursive macro.

The Template

{%- macro recursively_render_data_structure(d, indentation_index) -%}
{%- if d is number %}{{ d }}
{%- elif d is string %}"{{ d }}"
{%- elif d is mapping -%}
  {%- for key, value in d.items() %}
{{ ' ' * indentation_index }}{{ key }}: {{ recursively_render_data_structure(value, indentation_index + 2) }}
  {%- endfor %}
{%- elif d is iterable %}
  {%- for i in d %}
{{ ' ' * indentation_index }} - {{ recursively_render_data_structure(i, indentation_index + 4) }}
  {%- endfor %}
{%- else %}ERROR: UNKNOWN VALUE {{ d }}
{%- endif %}
{%- endmacro -%}

{{- recursively_render_data_structure(m, 0) }}

The Rendering Code

The code includes a test that the rendered structure is equivalent with the input:

from pathlib import Path

import yaml
from jinja2 import Environment, FileSystemLoader

tdir = Path('.')
template = Environment(loader=FileSystemLoader(tdir)).get_template('experimental-jinja-template.yaml.j2')
yaml_data = """
config:
  color: blue
  size: 1
  samples:
    - name: venice
      neighborhoods:
        cannaregio: 1
        castello: 2
        giudecca: 3
    - name: genoa
      neighborhoods:
        molo: 1
        foce: 2
        marassi: 3
    - name: florence
      neighborhoods:
        santamaria: 1
        sanmarco: 2
        santacroce: 3
        no-such-neighborhood:
          - a1: v1
            a2: v2
          - b
          - c
"""
m = yaml.safe_load(yaml_data)
rendered_text = template.render(m=m)
print(rendered_text)

m2 = yaml.safe_load(rendered_text)
assert m == m2