Search code examples
dictionaryfilteransiblewhitespacetrim

How to remove additional spacing between the quotes in a list of values?


How do I remove the additional spacing from the left and right side of each value between the quotation marks?

This is a shorter version of a much longer list. Some values have additional spacing in the front and back, such as Code, Date of Submission, and First Name, while others are normal (no additional spacing).

    "userdata": [
        {
            "AliasName": "Alias Name",
            "Code": " Code "
            "DateofSubmission": " Date of Submission ",
            "Description": "Description",
            "FirstName": " First Name ",
            "path": "path"
        },
        {
            "AliasName": "",
            "Code": " #3091 ",
            "DateofSubmission": " 14/5/2023 ",
            "Description": "NIL",
            "FirstName": " Peter ",
            "path": "OU=fulltime,OU=Test OU,DC=localdemo,DC=local" 
        },
        {
            "AliasName": "",
            "Code": " #3092 ",
            "DateofSubmission": " 2/5/2023 ",
            "Description": "NIL",
            "FirstName": " Sam ",
            "path": "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
        },
        {
            "AliasName": "",
            "Code": " #3093 ",
            "DateofSubmission": " 10/5/2023 ",
            "Description": "NIL",
            "FirstName": " Judy ",
            "path": "OU=flexi,OU=Test OU,DC=localdemo,DC=local" 
        }
    ]

I have tried these two ways with the trim filter, but nothing changed.

    - name: Extract the list with fields
      set_fact:
        userdata: "{{ userdata | map('trim') | list }}"
    - name: Extract the list with fields
      set_fact:
        userdata: "{{ userdata | trim }}"



Minimal play:

- hosts: localhost

  vars:

    userdata:
      - {k1a: v1a, k1b: v1b, k1c: v1c}
      - {k2a: v2a, k2b: v2b}
      - {k3a: v3a}

  tasks:

    - set_fact:
        userdata: |
          {% filter from_yaml %}
          {% for i in userdata %}
          {% set keys=i.keys()|map('trim') %}
          {% set values=i.values()|map('trim') %}
          - {{ dict(keys|zip(values)) }}
          {% endfor %}
          {% endfilter %}

    - debug:
        var: userdata|to_yaml

Results of minimal play:

fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({% filter from_yaml %}\n{% for i in userdata %}\n{% set keys=i.keys()|map('trim') %}\n{% set values=i.values()|map('trim') %}\n- {{ dict(keys|zip(values)) }}\n{% endfor %}\n{% endfilter %}\n): sequence item 0: expected str instance, list found"}


Play to isolate the problem:

- hosts: localhost

  vars:

    ud:
      - {k1a: v1a, k1b: v1b, k1c: v1c}
      - {k2a: v2a, k2b: v2b}
      - {k3a: v3a}

    ud_keys: "{{ ud|json_query('[].keys(@)') }}"
    ud_vals: "{{ ud|json_query('[].values(@)') }}"

  tasks:

    - debug:
        var: ud_keys|to_yaml
    - debug:
        var: ud_vals|to_yaml
    - debug:
        msg: |
          {% for k,v in ud_keys|zip(ud_vals) %}
          {{ k }} {{ v }}
          {% endfor %}
    - debug:
        msg: |
          {% for k,v in ud_keys|zip(ud_vals) %}
          {{ dict(k|zip(v)) }}
          {% endfor %}

    - name: Test 1
      set_fact:
        ud: |
          [{% for k,v in ud_keys|zip(ud_vals) %}
          {{ dict(k|zip(v)) }},
          {% endfor %}]
    - debug:
        var: ud
    - debug:
        var: ud|type_debug


    - name: Test 2
      set_fact:
        ud: |
          {% filter from_yaml %}
          [{% for k,v in ud_keys|zip(ud_vals) %}
          {{ dict(k|zip(v)) }},
          {% endfor %}]
          {% endfilter %}
      ignore_errors: true
    - debug:
        var: ud
    - debug:
        var: ud|type_debug


    - name: Test 3
      set_fact:
        ud: |
          {% filter from_yaml %}
          {% for k,v in ud_keys|zip(ud_vals) %}
          - {{ dict(k|zip(v)) }}
          {% endfor %}
          {% endfilter %}
      ignore_errors: true
    - debug:
        var: ud
    - debug:
        var: ud|type_debug

Results of the play to isolate the problem:

TASK [debug] *******************************************************************
ok: [localhost] => {
    "ud_keys|to_yaml": "- [k1a, k1b, k1c]\n- [k2a, k2b]\n- [k3a]\n"
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "ud_vals|to_yaml": "- [v1a, v1b, v1c]\n- [v2a, v2b]\n- [v3a]\n"
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "['k1a', 'k1b', 'k1c'] ['v1a', 'v1b', 'v1c']\n['k2a', 'k2b'] ['v2a', 'v2b']\n['k3a'] ['v3a']\n"
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "{'k1a': 'v1a', 'k1b': 'v1b', 'k1c': 'v1c'}\n{'k2a': 'v2a', 'k2b': 'v2b'}\n{'k3a': 'v3a'}\n"
}

TASK [Test 1] ******************************************************************
ok: [localhost] => {"ansible_facts": {"ud": [{"k1a": "v1a", "k1b": "v1b", "k1c": "v1c"}, {"k2a": "v2a", "k2b": "v2b"}, {"k3a": "v3a"}]}, "changed": false}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "ud": [
        {
            "k1a": "v1a",
            "k1b": "v1b",
            "k1c": "v1c"
        },
        {
            "k2a": "v2a",
            "k2b": "v2b"
        },
        {
            "k3a": "v3a"
        }
    ]
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "ud|type_debug": "list"
}

TASK [Test 2] ******************************************************************
fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({% filter from_yaml %}\n[{% for k,v in ud_keys|zip(ud_vals) %}\n{{ dict(k|zip(v)) }},\n{% endfor %}]\n{% endfilter %}\n): sequence item 0: expected str instance, list found"}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "ud": [
        {
            "k1a": "v1a",
            "k1b": "v1b",
            "k1c": "v1c"
        },
        {
            "k2a": "v2a",
            "k2b": "v2b"
        },
        {
            "k3a": "v3a"
        }
    ]
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "ud|type_debug": "list"
}

TASK [Test 3] ******************************************************************
fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({% filter from_yaml %}\n{% for k,v in ud_keys|zip(ud_vals) %}\n- {{ dict(k|zip(v)) }}\n{% endfor %}\n{% endfilter %}\n): sequence item 0: expected str instance, list found"}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "ud": [
        {
            "k1a": "v1a",
            "k1b": "v1b",
            "k1c": "v1c"
        },
        {
            "k2a": "v2a",
            "k2b": "v2b"
        },
        {
            "k3a": "v3a"
        }
    ]
}

TASK [debug] *******************************************************************
ok: [localhost] => {
    "ud|type_debug": "list"
}

Solution

  • map('trim') works on items of a list. If you want to trim a dictionary's values and keys, you have to separate them first. For example, in a Jinja template

        - set_fact:
            userdata: |
              {% filter from_yaml %}
              {% for i in userdata %}
              {% set keys=i.keys()|map('trim') %}
              {% set vals=i.values()|map('trim') %}
              - {{ dict(keys|zip(vals)) }}
              {% endfor %}
              {% endfilter %}
    

    gives

      userdata:
        [
            {
                "AliasName": "Alias Name",
                "Code": "Code",
                "DateofSubmission": "Date of Submission",
                "Description": "Description",
                "FirstName": "First Name",
                "path": "path"
            },
            {
                "AliasName": "",
                "Code": "#3091",
                "DateofSubmission": "14/5/2023",
                "Description": "NIL",
                "FirstName": "Peter",
                "path": "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"
            },
            {
                "AliasName": "",
                "Code": "#3092",
                "DateofSubmission": "2/5/2023",
                "Description": "NIL",
                "FirstName": "Sam",
                "path": "OU=parttime,OU=Test OU,DC=localdemo,DC=local"
            },
            {
                "AliasName": "",
                "Code": "#3093",
                "DateofSubmission": "10/5/2023",
                "Description": "NIL",
                "FirstName": "Judy",
                "path": "OU=flexi,OU=Test OU,DC=localdemo,DC=local"
            }
        ]
    

    Example of a complete playbook for testing

    - hosts: localhost
    
      vars:
    
        userdata:
          - {"AliasName": "Alias Name",
             "Code": " Code ",
             "DateofSubmission": " Date of Submission ",
             "Description": "Description",
             "FirstName": " First Name ",
             "path": "path"}
          - {"AliasName": "",
             "Code": " #3091 ",
             "DateofSubmission": " 14/5/2023 ",
             "Description": "NIL",
             "FirstName": " Peter ",
             "path": "OU=fulltime,OU=Test OU,DC=localdemo,DC=local"}
          - {"AliasName": "",
             "Code": " #3092 ",
             "DateofSubmission": " 2/5/2023 ",
             "Description": "NIL",
             "FirstName": " Sam ",
             "path": "OU=parttime,OU=Test OU,DC=localdemo,DC=local"}
          - {"AliasName": "",
             "Code": " #3093 ",
             "DateofSubmission": " 10/5/2023 ",
             "Description": "NIL",
             "FirstName": " Judy ",
             "path": "OU=flexi,OU=Test OU,DC=localdemo,DC=local"}
    
      tasks:
    
        - set_fact:
            userdata: |
              {% filter from_yaml %}
              {% for i in userdata %}
              {% set keys=i.keys()|map('trim') %}
              {% set vals=i.values()|map('trim') %}
              - {{ dict(keys|zip(vals)) }}
              {% endfor %}
              {% endfilter %}
    
        - debug:
            var: userdata|to_nice_json
    

    Q: "msg": "Unexpected templating type error occurred on ({% filter from_yaml %}\n{% for i in userdata %}\n{% set keys=i.keys()|map('trim') %}\n{% set vals=i.values()|map('trim') %}\n- {{ dict(keys|zip(vals)) }}\n{% endfor %}\n{% endfilter %}\n): sequence item 0: expected str instance, list found".

    A: I can't reproduce the problem. The minimal play below

    shell> cat pb.yml 
    - hosts: localhost
    
      vars:
    
        userdata:
          - {k1a: v1a, k1b: v1b, k1c: v1c}
          - {k2a: v2a, k2b: v2b}
          - {k3a: v3a}
    
      tasks:
    
        - set_fact:
            userdata: |
              {% filter from_yaml %}
              {% for i in userdata %}
              {% set keys=i.keys()|map('trim') %}
              {% set values=i.values()|map('trim') %}
              - {{ dict(keys|zip(values)) }}
              {% endfor %}
              {% endfilter %}
    
        - debug:
            var: userdata|to_yaml
    

    gives

    shell> ansible-playbook pb.yml
    
    PLAY [localhost] ******************************************************************************
    
    TASK [set_fact] *******************************************************************************
    ok: [localhost]
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      userdata|to_yaml: |-
        - {k1a: v1a, k1b: v1b, k1c: v1c}
        - {k2a: v2a, k2b: v2b}
        - {k3a: v3a}
    
    PLAY RECAP ************************************************************************************
    localhost: ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    

    To isolate the problem try the play below

    shell> cat pb.yml
    - hosts: localhost
    
      vars:
    
        ud:
          - {k1a: v1a, k1b: v1b, k1c: v1c}
          - {k2a: v2a, k2b: v2b}
          - {k3a: v3a}
    
        ud_keys: "{{ ud|json_query('[].keys(@)') }}"
        ud_vals: "{{ ud|json_query('[].values(@)') }}"
    
      tasks:
    
        - debug:
            var: ud_keys|to_yaml
        - debug:
            var: ud_vals|to_yaml
        - debug:
            msg: |
              {% for k,v in ud_keys|zip(ud_vals) %}
              {{ k }} {{ v }}
              {% endfor %}
        - debug:
            msg: |
              {% for k,v in ud_keys|zip(ud_vals) %}
              {{ dict(k|zip(v)) }}
              {% endfor %}
    
        - name: Test 1
          set_fact:
            ud: |
              [{% for k,v in ud_keys|zip(ud_vals) %}
              {{ dict(k|zip(v)) }},
              {% endfor %}]
        - debug:
            var: ud
        - debug:
            var: ud|type_debug
    
        - name: Test 2
          set_fact:
            ud: |
              {% filter from_yaml %}
              [{% for k,v in ud_keys|zip(ud_vals) %}
              {{ dict(k|zip(v)) }},
              {% endfor %}]
              {% endfilter %}
        - debug:
            var: ud
        - debug:
            var: ud|type_debug
    
        - name: Test 3
          set_fact:
            ud: |
              {% filter from_yaml %}
              {% for k,v in ud_keys|zip(ud_vals) %}
              - {{ dict(k|zip(v)) }}
              {% endfor %}
              {% endfilter %}
        - debug:
            var: ud
        - debug:
            var: ud|type_debug
    

    gives

    shell> ansible-playbook pb.yml
    
    PLAY [localhost] ******************************************************************************
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      ud_keys|to_yaml: |-
        - [k1a, k1b, k1c]
        - [k2a, k2b]
        - [k3a]
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      ud_vals|to_yaml: |-
        - [v1a, v1b, v1c]
        - [v2a, v2b]
        - [v3a]
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      msg: |-
        ['k1a', 'k1b', 'k1c'] ['v1a', 'v1b', 'v1c']
        ['k2a', 'k2b'] ['v2a', 'v2b']
        ['k3a'] ['v3a']
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      msg: |-
        {'k1a': 'v1a', 'k1b': 'v1b', 'k1c': 'v1c'}
        {'k2a': 'v2a', 'k2b': 'v2b'}
        {'k3a': 'v3a'}
    
    TASK [Test 1] *********************************************************************************
    ok: [localhost]
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      ud:
      - k1a: v1a
        k1b: v1b
        k1c: v1c
      - k2a: v2a
        k2b: v2b
      - k3a: v3a
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      ud|type_debug: list
    
    TASK [Test 2] *********************************************************************************
    ok: [localhost]
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      ud:
      - k1a: v1a
        k1b: v1b
        k1c: v1c
      - k2a: v2a
        k2b: v2b
      - k3a: v3a
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      ud|type_debug: list
    
    TASK [Test 3] *********************************************************************************
    ok: [localhost]
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      ud:
      - k1a: v1a
        k1b: v1b
        k1c: v1c
      - k2a: v2a
        k2b: v2b
      - k3a: v3a
    
    TASK [debug] **********************************************************************************
    ok: [localhost] => 
      ud|type_debug: list
    
    PLAY RECAP ************************************************************************************
    localhost: ok=13   changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0