xmlfilteransible

How to filter XML attribute in Ansible?


Output below is log message and I need to retrieve log count which is 5.

Code

- name: get system log count
  connection: local
  xml:
    xmlstring: "{{ log.content }}"
    content: attribute
    xpath: '/response/result/log/logs[@count]'
  register: log_count

- name: print log count
  debug:
    msg: "{{ log_count.matches }}"

Output

ok: [10.46.255.101] => {
    "msg": {
        "actions": {
            "namespaces": {},
            "state": "present",
            "xpath": "/response/result/log/logs[@count]"
        },
        "changed": false,
        "count": 1,
        "failed": false,
        "matches": [
            {
                "logs": {
                    "count": "5",
                    "progress": "100"
                }
            }
        ]

How to filter log count and use that as condition in next task? How to modify this code to store value of count (5) in a variable use it as condition in next task? I tries to use log_count.matches.count that doesn't work.

Basically I am trying to get count value from this output

<response status="success"><result>
  <job>
    <tenq>05:03:36</tenq>
    <tdeq>05:03:36</tdeq>
    <tlast>05:03:36</tlast>
    <status>FIN</status>
    <id>90</id>
  </job>
  <log>
    <logs count="0" progress="100"/>
  </log>
</result></response>

Solution

  • Q: "I am trying to get count value from this output"

    Based on How to fetch value from an API response with Ansible playbook?, a minimal example playbook

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        XML: "{{ lookup('file', 'response.xml') }}"
        YML: "{{ XML | ansible.utils.from_xml }}"
    
      tasks:
    
      - debug:
          msg: "{{ YML }}"
    
      - name: Logs count
        debug:
          msg: "{{ YML.response.result.log.logs['@count'] }}"
    

    will result into an output of

    TASK [debug] *****************
    ok: [localhost] =>
      msg:
        response:
          '@status': success
          result:
            job:
              id: '90'
              status: FIN
              tdeq: 05:03:36
              tenq: 05:03:36
              tlast: 05:03:36
            log:
              logs:
                '@count': '0'
                '@progress': '100'
    
    TASK [Logs count] ************
    ok: [localhost] =>
      msg: '0'
    

    Q: "How to use that as condition in the next task?"

    In example

      - fail:
          msg: No logs!
        when: YML.response.result.log.logs['@count'] | int < 1
    

    resulting into an output of

    TASK [fail] ********************************
    fatal: [localhost]: FAILED! => changed=false
      msg: No logs!
    

    Based on your initial problem description and example, the content of the registed variable log_count is

    TASK [debug] *********************************
    ok: [localhost] =>
      log_count:
        actions:
          namespaces: {}
          state: present
          xpath: /response/result/log/logs[@count]
        changed: false
        count: 1
        failed: false
        matches:
        - logs:
            count: '0'
            progress: '100'
        msg: 1
        xmlstring: |-
          <?xml version='1.0' encoding='UTF-8'?>
          <response status="success"><result>
            <job>
              <tenq>05:03:36</tenq>
              <tdeq>05:03:36</tdeq>
              <tlast>05:03:36</tlast>
              <status>FIN</status>
              <id>90</id>
            </job>
            <log>
              <logs count="0" progress="100"/>
            </log>
          </result></response>
    

    Return Values under matches are a list, in your case with one element only. You can get the count in a similar way as already shown.

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        XML: "{{ lookup('file', 'response.xml') }}"
    
      tasks:
    
      - community.general.xml:
          xmlstring: "{{ XML }}"
          content: attribute
          xpath: '/response/result/log/logs[@count]'
        register: log_count
    
      - debug:
          var: log_count
    
      - name: Logs count
        debug:
          msg: "{{ (log_count.matches | first).logs.count }}"
    

    resulting into an output of

    TASK [Logs count] ***************************************
    ok: [localhost] =>
      msg: '0'
    

    A note regarding dependencies ... Whereby xml module requires

    on the host that executes this module. lxml >= 2.3.0

    the from_xml filter does not.