Jinja2 template: output format

i am quite new to jinja2 template and i try to get output data by using jinja template.

data_list=

[
    {
        "v4-filter": {
            "accept_1": [
                {
                    "destination-prefix-list": "v4-future-prefix-list-1"
                },
                {
                    "source-prefix-list": "v4-future-prefix-list-2"
                },
                                {
                    "source-prefix-list": "v4-future-prefix-list-3"
                },
                {
                    "destination-port": "80"
                },
                {
                    "destination-port": "443"
                },
                {
                    "action": "accept"
                }
            ],
            "accept_2": [
                {
                    "destination-prefix-list": "v4-future-prefix-list4"
                },
                {
                    "source-prefix-list": "v4-future-prefix-list5"
                },
                {
                    "action": "accept"}]}}]

My jinja template

{%- for d  in data_list -%} 
    {%- for k,v  in d.items() -%} 
        {%- for term,value  in v.items() -%}
          term:: {{ term }} 
          {%- for dict_item in value -%}
            {%- for key, value in dict_item.items() -%}
               {% if  key == "source-prefix-list" %}
                 source-address:: {{value}} 
               {% endif %}
               {% if  key == "destination-prefix-list" %}
                 destination-address:: {{value}} 
               {% endif %}
               {% if  key == "destination-port" %}
                 destination-port:: {{value}} 
               {% endif %}
               {% if  key == "action" %}
                 action:: {{value}} 
               {% endif %}
            {%- endfor -%}
          {%- endfor -%}
        {%- endfor -%}
    {%- endfor -%} 
{%- endfor -%} 

Output that i get

term:: accept_1
               
                 destination-address:: v4-future-prefix-list-1 
               
               
               
                 source-address:: v4-future-prefix-list-2 
               
               
               
               
                 source-address:: v4-future-prefix-list-3 
               
               
               
               
               
               
                 destination-port:: 80 
               
               
               
               
                 destination-port:: 443 
               
               
               
               
               
                 action:: accept 
               term:: accept_2
               
                 destination-address:: v4-future-prefix-list4 
               
               
               
                 source-address:: v4-future-prefix-list5 
               
               
               
               
               
               
               
                 action:: accept 

Output that i want

term accept_1 {
    source-address:: v4-future-prefix-list-1
                     v4-future-prefix-list-2
                     v4-future-prefix-list-3
    destination-port:: 80
                       443
    action:: accept
}

term accept_2 {
    source-address:: v4-future-prefix-list-5
    destination-address:: v4-future-prefix-list-4
    action:: accept
}

The jinja template looks not nice i know, but at the end it contains all the information that i need, is just question now to format properly as expected.

I tried by using nested if statement to properly reach the result but with no success.

Any hint is welcome. Thanks, Pablo.


Solution 1:

The following template will produce the requested output:

{%- for d  in data_list -%}
{%- for k,v  in d.items() -%}
{%- for term,value  in v.items() -%}
{%- set label = namespace(source=false, dest=false, port=false) %}
term {{ term }} {
{%- for dict_item in value -%}
{%- for key, value in dict_item.items() -%}
    {%- if key == "source-prefix-list" %}
    {% if not label.source %}source-address::{% else %}{{ ' '*16 }}{% endif %} {{value}}
    {%- set label.source = true %}
    {%- endif %}
    {%- if key == "destination-prefix-list" %}
    {% if not label.dest %}destination-address::{% else %}{{ ' '*21 }}{% endif %} {{value}}
    {%- set label.dest = true %}
    {%- endif %}
    {%- if key == "destination-port" %}
    {% if not label.port %}destination-port::{% else %}{{ ' '*18 }}{% endif %} {{value}}
    {%- set label.port = true %}
    {%- endif %}
    {%- if key == "action" %}
    action:: {{value}}
    {%- endif %}
{%- endfor %}
{%- endfor %}
}
{% endfor %}
{%- endfor %}
{%- endfor %}

Output:

term accept_1 {
    destination-address:: v4-future-prefix-list-1
    source-address:: v4-future-prefix-list-2
                     v4-future-prefix-list-3
    destination-port:: 80
                       443
    action:: accept
}

term accept_2 {
    destination-address:: v4-future-prefix-list4
    source-address:: v4-future-prefix-list5
    action:: accept
}

Here we use a Jinja2 namespace object that we can use to track whether a label has been already printed or not in the current cycle. If a label is printed, we flip the boolean tracking variable in our label namespace variable and then just print enough space to correctly align the next printed value.