Home > OS >  Convert dictionary in list
Convert dictionary in list

Time:01-18

I have following json file

[
    {
        "v4-filter": {
            "accept_to_test1t": {
                "action": "accept"
            },
            "access_to_test2": [
                {
                    "source-prefix-list": "x.x.x.x/yy"
                },
                {
                    "destination-prefix-list": "x.x.x.x/yy"
                },
                {
                    "action": "accept"
                }
            ]
        }
    }
]

Please note that for dictionary key accept_to_test1 value is again a dictionary "action": "accept" Problem: I need to convert all the nested dictionaries like case above in a list. In this specific case, for example

accept_to_test1 : [{"action": "accept"}]. All the rest stay as it is. Result:

[
    {
        "v4-filter": {
            "accept_to_test1t": [
            {
                "action": "accept"
            }],
            "access_to_test2": [
            ... like before ...
        }
    }
]

I am using a jinja2 template for rendering this data and it works but only for list of dictionary.

{%- for d  in data_list -%}
    {%- for k,v  in d.items() -%} 
        {%- for term,value  in v.items() -%} 
        term {{ term  }} {{ '{ \n' }}
          {%- set label = namespace(source=false, dest=false, port=false, action=false, prot=false) -%}
          {%- for dict_item in value -%}
            {%- for key, value in dict_item.items()  -%}            
               {% if  key == "source-prefix-list" %}
               {% if not label.source %}  source-address::{% else %}{{ ' '*18 }}{% endif %} {{value}} {{ '\n' }}  
               {%- set label.source = true -%}
               {% endif %}
               {%- if  key == "destination-prefix-list" -%}
               {% if not label.dest %}  destination-address::{% else %}{{ ' '*20 }}{% endif %} {{value}} {{ '\n' }}  
               {%- set label.dest = true %} 
               {%- endif -%}
               {%- if  key == "destination-port" -%}
               {% if not label.port %}  destination-port::{% else %}{{ ' '*20 }}{% endif %} {{value}} {{ '\n' }}
               {%- set label.port = true -%}  
               {% endif %}
               {%- if  key == "action" -%}
               {% if not label.action %}  action::{% else %}{{ ' '*20 }}{% endif %} {{value}} {{ '\n' }}
               {%- set label.action = true -%}  
               {% endif %}
               {%- if  key == "protocol" -%}
               {% if not label.protocol %}  protocol::{% else %}{{ ' '*20 }}{% endif %} {{value}} {{ '\n' }}
               {%- set label.protocol = true -%}  
               {% endif %}
            {%- endfor -%}
          {%- endfor -%}
          {{ '} \n\n' }}
        {%- endfor -%}
    {%- endfor -%} 
{%- endfor -%} 
{# above template is for json file #}

Problem is here during rendering

    {%- for key, value in dict_item.items()  -%}            
  jinja2.exceptions.UndefinedError: 'str object' has no attribute 'item

Due to {'action': 'accept'} that is not an iterable item. It would work with something like [{'action': 'accept'}].

Any hint is welcome.

Thanks.

CodePudding user response:

A simple solution for this issue is just to detect when the value variable is a dict, then embed it in a list. For the detection we can use the mapping bultin test. The embedding is a simple encapsulation: {%- set value_list = [value] %}.

{%- for d  in data_list -%}
    {%- for k,v  in d.items() -%}
        {%- for term,value  in v.items() -%}
        term {{ term  }} {{ '{ \n' }}
        {%- set label = namespace(source=false, dest=false, port=false, action=false, prot=false) -%}
        {%- if value is mapping() %}
            {%- set value_list = [value] %}
        {%- else %}
            {%- set value_list = value %}
        {%- endif %}
        {%- for dict_item in value_list -%}
            {%- for key, value in dict_item.items() -%}
            {%- if  key == "source-prefix-list" %}
            {%- if not label.source %}  source-address::{% else %}{{ ' '*18 }}{% endif %} {{value}} {{ '\n' }}
            {%- set label.source = true -%}
            {%- endif %}
            {%- if  key == "destination-prefix-list" -%}
            {%- if not label.dest %}  destination-address::{% else %}{{ ' '*20 }}{% endif %} {{value}} {{ '\n' }}
            {%- set label.dest = true %}
            {%- endif -%}
            {%- if  key == "destination-port" -%}
            {%- if not label.port %}  destination-port::{% else %}{{ ' '*20 }}{% endif %} {{value}} {{ '\n' }}
            {%- set label.port = true -%}
            {%- endif %}
            {%- if  key == "action" -%}
            {%- if not label.action %}  action::{% else %}{{ ' '*20 }}{% endif %} {{value}} {{ '\n' }}
            {%- set label.action = true -%}
            {%- endif %}
            {%- if  key == "protocol" -%}
            {%- if not label.protocol %}  protocol::{% else %}{{ ' '*20 }}{% endif %} {{value}} {{ '\n' }}
            {%- set label.protocol = true -%}
            {%- endif %}
            {%- endfor -%}
        {%- endfor -%}
        {{ '} \n\n' }}
        {%- endfor -%}
    {%- endfor -%}
{%- endfor -%}

Output:

term accept_to_test1t { 
  action:: accept 
} 

term access_to_test2 { 
  source-address:: x.x.x.x/yy 
  destination-address:: x.x.x.x/yy 
  action:: accept 
} 

I've also fixed some indentation problems.

  •  Tags:  
  • Related