Hay un código que llama a los servicios web de una aplicación.

 - uri:
         url: http://10.164.52.61:8080/ems/v74/ws/customer.ws?customerRefId=f4XXXb15d69c3
         method: GET
         content_as_json: true
         password: admin
         user: admin
         validate_certs: no
         return_content: yes
         HEADER_Cookie: "{{login.set_cookie}}"
        register: customerId

      - debug:
          var: customerId.content

La respuesta de muestra es

"customerId.content": "<listResponse type=\"customer\" count=\"1\"><instance customerId=\"28\" name=\"abc\" customerRefId=\"xyz\" refId1=\"12\" type=\"org\" enabled=\"true\" phone=\"\" fax=\"\" billingZip=\"\" billingAddress=\"\" billingCity=\"\" billingCountry=\"\" billingState=\"\" vendor=\"1\" defaultEmail=\"test\" defaultContactName=\"test\"/></listResponse>"

Quiero acceder a la respuesta de la lista en mi siguiente bloque de código. Como si solo necesitara el valor de "ID de cliente". Cómo se puede lograr esto usando ansible

3
Nishant Singh 23 sep. 2016 a las 13:11

6 respuestas

La mejor respuesta

No hay soporte XML en Ansible listo para usar.
Puede usar filtros de expresiones regulares para realizar algunas búsquedas simples en sus datos XML.
En tu ejemplo:

- debug: msg="{{ customerId.content | regex_findall('customerId=\"(\d+)\"') }}"

Buscará cadenas customerId=\"<number>\" y devolverá una lista de números entre comillas.

Actualización: ejemplo completamente funcional:

- hosts: localhost
  gather_facts: no
  vars:
    myvar: "<listResponse type=\"customer\" count=\"1\"><instance customerId=\"28\" name=\"abc\" customerRefId=\"xyz\" refId1=\"12\" type=\"org\" enabled=\"true\" phone=\"\" fax=\"\" billingZip=\"\" billingAddress=\"\" billingCity=\"\" billingCountry=\"\" billingState=\"\" vendor=\"1\" defaultEmail=\"test\" defaultContactName=\"test\"/></listResponse>"
  tasks:
    - debug: msg="{{ myvar | regex_findall('customerId=\"(\d+)\"') }}"

Yo uso ansible 2.1.1.0.

2
Konstantin Suvorov 26 sep. 2016 a las 11:17

Como esto era razonablemente complejo para que esto funcionara, pensé en publicar mis parámetros XML de Ansible para analizar una respuesta SOAP:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <S:Body xmlns:ns2="http://ws.coverity.com/v9">
      <ns2:getLdapServerDomainsResponse>
        <return>
            <name>soapui_test</name>
        </return>
      </ns2:getLdapServerDomainsResponse>
   </S:Body>
</S:Envelope>

El truco consistía en conseguir espacios de nombres y xpath correctos. Además, como quería el nombre real, necesitaba content: text

- name: Extract the name from the SOAP
  xml:
    xmlstring: "{{ ldap_response.content }}"
    xpath: "/S:Envelope/S:Body/ns2:getLdapServerDomainsResponse/return/name"
    namespaces:
      S: "http://schemas.xmlsoap.org/soap/envelope/"
      SOAP-ENV: "http://schemas.xmlsoap.org/soap/envelope/"
      ns2: "http://ws.coverity.com/v9"
    content: text
  register: ldap_name

Sigo sin entender por qué la sección xpath al final no funciona con .../ns2:return/ns2:name como Ejemplo sugerido de Ansible - Documentos XML. Lo anterior llena ldap_name con (simplificado):

"ldap_name": {
    "matches": [
        {
            "name": "soapui_test"
        }
    ],
}
0
Martin 20 abr. 2020 a las 16:00

Vale la pena mirar ansible-xml para esto. No es parte de Ansible pero es un módulo muy útil para analizar xml, usa la biblioteca Python lxml bajo el capó.

0
Zlemini 27 ene. 2017 a las 20:49

Acabo de agregar soporte de análisis XML en el módulo uri porque también lo necesitaba. https://github.com/ansible/ansible/pull/53045

Al igual que el soporte JSON, devolverá una clave 'xml' con un diccionario que consta del contenido XML para la conveniencia de acceder a los datos en la carga útil.

Su ejemplo se vería así:

 - uri:
     url: http://10.164.52.61:8080/ems/v74/ws/customer.ws?customerRefId=f4XXXb15d69c3
     method: GET
     password: admin
     user: admin
     validate_certs: no
     HEADER_Cookie: "{{login.set_cookie}}"
    register: customerId

  - debug:
      var: customerId.xml.listResponse.instance['@customerId']

La salida en customerId.xml sería:

{
    'listResponse': {
        '@type': 'customer',
        '@count', '1',
        'instance': {
            '@customerId': '28',
            '@name': 'abc'
            '@customerRefId': 'xyz',
            '@refId1': '12',
            '@type': 'org',
            '@enabled': 'true',
            '@phone': '',
            '@fax': '',
            '@billingZip': '',
            '@billingAddress': '',
            '@billingCity': '',
            '@billingCountry': '',
            '@billingState': '',
            '@vendor': '1',
            '@defaultEmail': 'test',
            '@defaultContactName': 'test'
        }
    }
}
1
Dag Wieers 27 feb. 2019 a las 11:43

Desde Ansible 2.4 puede hacer esto:

- get_url:
    url: http://10.164.52.61:8080/ems/v74/ws/customer.ws?customerRefId=f4XXXb15d69c3
    dest: ./response.xml
    url_password: admin
    url_user: admin
    validate_certs: no
    headers:
      Cookie: "{{login.set_cookie}}"

- xml:
    path: ./response.xml
    xpath: /listResponse/instance
    content: attribute
  register: instance_attributes

- debug:
    var: instance_attributes.matches.0.instance.customerId
2
sebaszw 9 ene. 2018 a las 16:15

Esto es similar a la respuesta de sebaszw, sin embargo, no requiere que la respuesta xml se escriba en un archivo, sino que se almacena en una variable.

- uri:
    url: http://10.164.52.61:8080/ems/v74/ws/customer.ws?customerRefId=f4XXXb15d69c3
    method: GET
    content_as_json: true
    password: admin
    user: admin
    validate_certs: no
    return_content: yes
    HEADER_Cookie: "{{login.set_cookie}}"
  register: customerId

- xml:
    xmlstring: "{{customerId.content}}"
    xpath: /listResponse/instance
    content: attribute
  register: instance_attributes

- debug:
    var: instance_attributes.matches.0.instance.customerId 
6
davegravy 23 nov. 2018 a las 14:37