Given the XML
shell> cat inventory.xml
<?xml version = '1.0' encoding = 'UTF-8' standalone = 'yes'?>
<!-- Copyright (c) 1999, 2022, Oracle. All rights reserved. -->
<!-- Do not modify the contents of this file by hand. -->
<INVENTORY>
<VERSION_INFO>
<SAVED_WITH>13.9.4.0.0</SAVED_WITH>
<MINIMUM_VER>2.1.0.6.0</MINIMUM_VER>
</VERSION_INFO>
<HOME_LIST>
<HOME NAME="OraHome1" LOC="/oracle/agent/agent13.4" TYPE="O" IDX="3"/>
<HOME NAME="OraDB19Home1" LOC="/oracle/19.0.0" TYPE="O" IDX="2"/>
</HOME_LIST>
</INVENTORY>
Read the file and convert XML to YAML
inv_xml: "{{ lookup('file', 'inventory.xml') }}"
inv_yml: "{{ inv_xml|ansible.utils.from_xml }}"
gives
inv_yml:
INVENTORY:
HOME_LIST:
HOME:
- '@IDX': '3'
'@LOC': /oracle/agent/agent13.4
'@NAME': OraHome1
'@TYPE': O
- '@IDX': '2'
'@LOC': /oracle/19.0.0
'@NAME': OraDB19Home1
'@TYPE': O
VERSION_INFO:
MINIMUM_VER: 2.1.0.6.0
SAVED_WITH: 13.9.4.0.0
Create a dictionary of LOC and NAME
loc_name: "{{ inv_yml.INVENTORY.HOME_LIST.HOME|
items2dict(key_name='@LOC',
value_name='@NAME') }}"
gives
loc_name:
/oracle/19.0.0: OraDB19Home1
/oracle/agent/agent13.4: OraHome1
Then, searching is trivial
loc: '/oracle/19.0.0'
name_of_loc: "{{ loc_name[loc] }}"
gives
name_of_loc: OraDB19Home1
, or in the loop
- debug:
msg: "The name of LOC {{ item }} is {{ loc_name[item] }}"
loop:
- '/oracle/19.0.0'
- '/oracle/agent/agent13.4'
gives (abridged)
msg: The name of LOC /oracle/19.0.0 is OraDB19Home1
msg: The name of LOC /oracle/agent/agent13.4 is OraHome1
Example of a complete playbook for testing
shell> cat pb.yml
- hosts: localhost
vars:
inv_xml: "{{ lookup('file', 'inventory.xml') }}"
inv_yml: "{{ inv_xml|ansible.utils.from_xml }}"
loc_name: "{{ inv_yml.INVENTORY.HOME_LIST.HOME|
items2dict(key_name='@LOC',
value_name='@NAME') }}"
loc: '/oracle/19.0.0'
name_of_loc: "{{ loc_name[loc] }}"
tasks:
- debug:
var: inv_xml
- debug:
var: inv_yml
- debug:
var: loc_name
- debug:
var: name_of_loc
- debug:
msg: "The name of LOC {{ item }} is {{ loc_name[item] }}"
loop:
- '/oracle/19.0.0'
- '/oracle/agent/agent13.4'
Example of the project
shell> tree .
.
├── ansible.cfg
├── hosts
├── inventory.xml
└── pb.yml
0 directories, 4 files
shell> cat ansible.cfg
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
roles_path = $PWD/roles
remote_tmp = ~/.ansible/tmp
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts
localhost
Q: "Give an alternative to ansible.utils"
A: Install jc and use it in the pipe. The declaration below expands to the same YAML as before
inv_yml: "{{ lookup('pipe', 'cat inventory.xml | jc --xml') }}"
Q: "Using possible regex?"
A: Select the line first
inv_xml: "{{ lookup('file', 'inventory.xml') }}"
loc: '/oracle/19.0.0'
home_loc_regex: '^\s*<HOME .*? LOC="{{ loc }}" .*$'
home: "{{ inv_xml.splitlines()|
select('regex', home_loc_regex)|
first|
trim }}"
gives
home: <HOME NAME="OraDB19Home1" LOC="/oracle/19.0.0" TYPE="O" IDX="2"/>
Parse the attributes
home_dict: "{{ dict(home[6:-2]|
replace('\"', '')|
split(' ')|
map('split', '=')) }}"
gives
home_dict:
IDX: '2'
LOC: /oracle/19.0.0
NAME: OraDB19Home1
TYPE: O
Q: "No filter named 'split'"
A: The filter split is available since 2.11. For the lower versions, only the '.split' method is available. In this case, use Jinja and create the YAML structure. The declarations below give the same dictionary home_dict as before
home_dict_str: |
{% for i in home[6:-2].split(' ') %}
{% set arr = i.split('=') %}
{{ arr.0 }}: {{ arr.1 }}
{% endfor %}
home_dict: "{{ home_dict_str|from_yaml }}"