Daniel
Daniel

Reputation: 61

How to substitute in Ansible a XML node by a "complex" one?

How can I use xml module, being idempotent (no "changed" when run twice) to attain the example desired state?

Example:

Initial state, bar node only contains text:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <foo>foo</foo>
  <bar>bar</bar>
  <baz>baz</baz>
</root>

Desired state, bar node contains:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <foo>foo</foo>
  <bar name="bar">
     <content name="1" type="text">lorem</content>
     <content name="2" type="yml">lorem: ipsum</content>
     </verbose>
  </bar>
  <baz>baz</baz>
</root>

My attempts:

---
- hosts: localhost
  vars:
    xml_text: >-
      <?xml version='1.0' encoding='UTF-8'?>
      <root>
        <foo>foo</foo>
        <bar><barbar/></bar>
        <baz>baz</baz>
      </root>
  tasks:
    - name: "Substitute bar. Bad: wipes the other nodes"
      xml:
        xmlstring: "{{ xml_text }}"
        xpath: /root
        input_type: xml
        set_children: |-
          <bar>
            <verbose />
            <content name="1" type="text">lorem</content>
            <content name="2" type="yml">lorem: ipsum</content>
          </bar>
      register: result

    - debug:
        var: result

    # Imitating https://github.com/ansible-collections/community.general/blob/main/tests/integration/targets/xml/tasks/test-set-children-elements-level.yml
    - name: "Substitute bar. Bad: Can't do both tags ans values"
      xml:
        xmlstring: "{{ xml_text }}"
        xpath: /root/bar
        input_type: yaml
        set_children:
            - verbose: "1"
            - content:
                name: "1"
                type: text
            #     _ : lorem
            #     "": lorem
            #     ~ : lorem
            - content: "lorem: ipsum"
            #       name: 2
            #       type: yml
      register: result

    - debug:
        var: result

    - name: "Substitute bar. Bad: Fails"
      xml:
        xmlstring: "{{ xml_text }}"
        xpath: /root/bar
        input_type: xml
        set_children: |-
            <verbose />
            <content name="1" type="text">lorem</content>
            <content name="2" type="yml">lorem: ipsum</content>
      register: result

    - debug:
        var: result

Upvotes: 0

Views: 416

Answers (2)

Daniel
Daniel

Reputation: 61

It's not possible at 2021-05-26.
A bug is open waiting for contributors:

Upvotes: 0

Nicholas Sushkin
Nicholas Sushkin

Reputation: 13780

I think you need use empty node (key "_") for XML content. See https://github.com/cmprescott/ansible-xml/issues/101

For example

- name: Configure proxy in maven
xml:
  path: /etc/maven/settings.xml
  namespaces:
    mvn: http://maven.apache.org/SETTINGS/1.0.0
  xpath: /mvn:settings/mvn:proxies
  pretty_print: yes
  set_children:
    - proxy:
        _:
          - id: "proxy"
          - active: "true"
          - protocol: "http"
          - host: '{{ proxied_proxy_node }}'
          - port: '{{ proxied_proxy_port | string }}'
when: maven_settings_file.stat.exists

Upvotes: 1

Related Questions