Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add to_xml and from_xml filter plugin #56

Merged
merged 33 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e68671e
Add filter plugin for xml_to_json
ashwini-mhatre Mar 24, 2021
64826c1
Add xml_to_json and json_to_xml filter plugin
ashwini-mhatre Mar 25, 2021
f7d3a81
add valiadte input function
ashwini-mhatre Mar 26, 2021
7863d4e
Add changelog fragments
ashwini-mhatre Mar 26, 2021
a702805
Remove unwanted code
ashwini-mhatre Mar 26, 2021
43b87ef
Fix tox linters
ashwini-mhatre Mar 26, 2021
5e0d600
Add toxlinters
ashwini-mhatre Mar 26, 2021
f4825b7
Address review comments
ashwini-mhatre Mar 26, 2021
1ca534d
fix linter
ashwini-mhatre Mar 26, 2021
e722126
Address review comments
ashwini-mhatre Mar 26, 2021
604c113
Address review comments
ashwini-mhatre Mar 26, 2021
8baebc6
fix syntax errors
ashwini-mhatre Mar 29, 2021
4e00e83
Add uts for xml_tojson
ashwini-mhatre Mar 30, 2021
055a162
Add Uts for xml_to_json and json_to_xml
ashwini-mhatre Mar 30, 2021
5e3d79f
Add integration testcases for xml_to_json and json_to_xml plugin
ashwini-mhatre Mar 30, 2021
0ef8bfb
Merge branch 'main' of https://github.com/ansible-collections/ansible…
ashwini-mhatre Mar 30, 2021
a68ea89
fix linters
ashwini-mhatre Mar 31, 2021
5a8d78d
Fix linters
ashwini-mhatre Mar 31, 2021
9376985
Address review comments
ashwini-mhatre Mar 31, 2021
ba0263b
fix linters
ashwini-mhatre Mar 31, 2021
9248953
address review comments
ashwini-mhatre Mar 31, 2021
440760e
address review comments
ashwini-mhatre Mar 31, 2021
daa4f30
revert unwanted changes
ashwini-mhatre Mar 31, 2021
d845d76
revert unwanted changes
ashwini-mhatre Mar 31, 2021
fc28e99
Address review comments
ashwini-mhatre Mar 31, 2021
655f327
Address review comments
ashwini-mhatre Apr 1, 2021
43a49ec
Address review comments
ashwini-mhatre Apr 1, 2021
12b04eb
fix linters
ashwini-mhatre Apr 1, 2021
df52ffd
fix sanity
ashwini-mhatre Apr 1, 2021
ddfa8e3
Add docs
ashwini-mhatre Apr 1, 2021
d3694f7
Address review comments
ashwini-mhatre Apr 8, 2021
f395e39
Address review comments
ashwini-mhatre Apr 8, 2021
32141a9
Merge branch 'main' of https://github.com/ansible-collections/ansible…
ashwini-mhatre Apr 8, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelogs/fragments/add-xmltojson-and-jsontoxml-filter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- Add from_xml and to_xml fiter plugin (https://github.com/ansible-collections/ansible.utils/pull/56).
145 changes: 145 additions & 0 deletions plugins/filter/from_xml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#
# -*- coding: utf-8 -*-
# Copyright 2021 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#

"""
The from_xml filter plugin
"""
from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = """
name: from_xml
author: Ashwini Mhatre (@amhatre)
version_added: "2.0.2"
short_description: convert given xml string to native python dictionary.
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
description:
- This plugin converts the xml string to native python dictionary.
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
- Using the parameters below- C(data|ansible.utils.from_xml)
options:
data:
description:
- The input xml string .
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
- This option represents the xml value that is passed to the filter plugin in pipe format.
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
- For example C(config_data|ansible.utils.from_xml), in this case C(config_data) represents this option.
type: str
required: True
engine:
description:
- Conversion library to use within the filter plugin.
type: str
default: xmltodict
"""

EXAMPLES = r"""

#### Simple examples with out any engine. plugin will use default value as xmltodict

tasks:
- name: convert given xml to native python dictionary
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- name: convert given xml to native python dictionary
- name: convert given XML to native python dictionary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

ansible.builtin.set_fact:
data: "
<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><schemas><schema/></schemas></netconf-state>
"

- debug:
msg: "{{ data|ansible.utils.from_xml }}"

##TASK######
# TASK [convert given xml to json] *****************************************************************************************************
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Task name doesn't seem to match the task name above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

# task path: /Users/amhatre/ansible-collections/playbooks/test_utils.yaml:5
# ok: [localhost] => {
# "ansible_facts": {
# "data": " <netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><schemas><schema/></schemas></netconf-state> "
# },
# "changed": false
# }
#
# TASK [debug] *************************************************************************************************************************
# task path: /Users/amhatre/ansible-collections/playbooks/test_utils.yaml:13
# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils
# ok: [localhost] => {
# "msg": {
# "netconf-state": {
# "@xmlns": "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring",
# "schemas": {
# "schema": null
# }
# }
# }
# }

#### example2 with engine=xmltodict

tasks:
- name: convert given xml to json
ansible.builtin.set_fact:
data: "
<netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><schemas><schema/></schemas></netconf-state>
"

- debug:
msg: "{{ data|ansible.utils.from_xml('xmltodict') }}"

##TASK######
# TASK [convert given xml to json] *****************************************************************************************************
# task path: /Users/amhatre/ansible-collections/playbooks/test_utils.yaml:5
# ok: [localhost] => {
# "ansible_facts": {
# "data": " <netconf-state xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring\"><schemas><schema/></schemas></netconf-state> "
# },
# "changed": false
# }
#
# TASK [debug] *************************************************************************************************************************
# task path: /Users/amhatre/ansible-collections/playbooks/test_utils.yaml:13
# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils
# ok: [localhost] => {
# "msg": {
# "netconf-state": {
# "@xmlns": "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring",
# "schemas": {
# "schema": null
# }
# }
# }
# }
"""

from ansible.errors import AnsibleFilterError
from jinja2.filters import environmentfilter
from ansible_collections.ansible.utils.plugins.plugin_utils.from_xml import (
from_xml,
)
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
AnsibleArgSpecValidator,
)


@environmentfilter
def _from_xml(*args, **kwargs):
"""Convert the given data from xml to json."""

keys = ["data", "engine"]
data = dict(zip(keys, args[1:]))
data.update(kwargs)
aav = AnsibleArgSpecValidator(
data=data, schema=DOCUMENTATION, name="from_xml"
)
valid, errors, updated_data = aav.validate()
if not valid:
raise AnsibleFilterError(errors)
return from_xml(**updated_data)


class FilterModule(object):
""" from_xml """

def filters(self):

"""a mapping of filter names to functions"""
return {"from_xml": _from_xml}
142 changes: 142 additions & 0 deletions plugins/filter/to_xml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#
# -*- coding: utf-8 -*-
# Copyright 2021 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#


"""
The to_xml filter plugin
"""
from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = """
name: to_xml
author: Ashwini Mhatre (@amhatre)
version_added: "2.0.2"
short_description: convert given json string to xml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
short_description: convert given json string to xml
short_description: Convert given JSON string to XML

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

description:
- This plugin converts the json string to xml.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- This plugin converts the json string to xml.
- This plugin converts the JSON string to XML.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

- Using the parameters below- C(data|ansible.utils.to_xml)
options:
data:
description:
- The input json string .
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- The input json string .
- The input JSON string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ack

- This option represents the json value that is passed to the filter plugin in pipe format.
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
- For example C(config_data|ansible.utils.to_xml), in this case C(config_data) represents this option.
type: str
required: True
engine:
description:
- Conversion library to use within the filter plugin.
type: str
default: xmltodict
"""

EXAMPLES = r"""

#### Simple examples with out any engine. plugin will use default value as xmltodict

- name: Define json data
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
ansible.builtin.set_fact:
data: {
"interface-configurations": {
"@xmlns": "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg",
"interface-configuration": null
}
}
- debug:
msg: "{{ data|ansible.utils.to_xml }}"

# TASK [Define json data ] *************************************************************************
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
# task path: /Users/amhatre/ansible-collections/playbooks/test_utils_json_to_xml.yaml:5
# ok: [localhost] => {
# "ansible_facts": {
# "data": {
# "interface-configurations": {
# "@xmlns": "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg",
# "interface-configuration": null
# }
# }
# },
# "changed": false
# }
#
# TASK [debug] ***********************************************************************************************************
# task path: /Users/amhatre/ansible-collections/playbooks/test_utils_json_to_xml.yaml:13
# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils
# ok: [localhost] => {
# "msg": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<interface-configurations xmlns=\"http://cisco.com/ns/yang/
# Cisco-IOS-XR-ifmgr-cfg\">\n\t<interface-configuration></interface-configuration>\n</interface-configurations>"
# }

#### example2 with engine=xmltodict

- name: Define json data
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
ansible.builtin.set_fact:
data: {
"interface-configurations": {
"@xmlns": "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg",
"interface-configuration": null
}
}
- debug:
msg: "{{ data|ansible.utils.to_xml('xmltodict') }}"

# TASK [Define json data ] *************************************************************************
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
# task path: /Users/amhatre/ansible-collections/playbooks/test_utils_json_to_xml.yaml:5
# ok: [localhost] => {
# "ansible_facts": {
# "data": {
# "interface-configurations": {
# "@xmlns": "http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg",
# "interface-configuration": null
# }
# }
# },
# "changed": false
# }
# TASK [debug] ***********************************************************************************************************
# task path: /Users/amhatre/ansible-collections/playbooks/test_utils_json_to_xml.yaml:13
# Loading collection ansible.utils from /Users/amhatre/ansible-collections/collections/ansible_collections/ansible/utils
# ok: [localhost] => {
# "msg": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<interface-configurations xmlns=\"http://cisco.com/ns/yang/
# Cisco-IOS-XR-ifmgr-cfg\">\n\t<interface-configuration></interface-configuration>\n</interface-configurations>"
# }

"""

from ansible.errors import AnsibleFilterError
from jinja2.filters import environmentfilter
from ansible_collections.ansible.utils.plugins.plugin_utils.to_xml import (
to_xml,
)
from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import (
AnsibleArgSpecValidator,
)


@environmentfilter
def _to_xml(*args, **kwargs):
"""Convert the given data from json to xml."""
keys = ["data", "engine"]
data = dict(zip(keys, args[1:]))
data.update(kwargs)
aav = AnsibleArgSpecValidator(
data=data, schema=DOCUMENTATION, name="to_xml"
)
valid, errors, updated_data = aav.validate()
if not valid:
raise AnsibleFilterError(errors)
return to_xml(**updated_data)


class FilterModule(object):
""" to_xml """

def filters(self):
"""a mapping of filter names to functions"""
return {"to_xml": _to_xml}
49 changes: 49 additions & 0 deletions plugins/plugin_utils/from_xml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#
# -*- coding: utf-8 -*-
# Copyright 2021 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#

"""
The from_xml plugin code
"""
from __future__ import absolute_import, division, print_function

__metaclass__ = type

import json
from ansible.errors import AnsibleFilterError

try:
import xmltodict

HAS_XMLTODICT = True
except ImportError:
HAS_XMLTODICT = False


def _raise_error(msg):
"""Raise an error message, prepend with filter name
:param msg: The message
:type msg: str
:raises: AnsibleError
"""
error = "Error when using plugin 'from_xml': {msg}".format(msg=msg)
raise AnsibleFilterError(error)


def from_xml(data, engine):
"""Convert data which is in xml to json"
:param data: The data passed in (data|from_xml(...))
:type data: xml
:param engine: Conversion library default=xml_to_dict
"""
if engine == "xmltodict":
ashwini-mhatre marked this conversation as resolved.
Show resolved Hide resolved
if not HAS_XMLTODICT:
_raise_error("Missing required library xmltodict")
try:
res = json.dumps(xmltodict.parse(data))
except Exception:
_raise_error("Input Xml is not valid")
return res
52 changes: 52 additions & 0 deletions plugins/plugin_utils/to_xml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#
# -*- coding: utf-8 -*-
# Copyright 2021 Red Hat
# GNU General Public License v3.0+
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#

"""
The to_xml plugin
"""
from __future__ import absolute_import, division, print_function

__metaclass__ = type

import ast
from ansible.errors import AnsibleFilterError

try:
import xmltodict

HAS_XMLTODICT = True
except ImportError:
HAS_XMLTODICT = False


def _raise_error(msg):
"""Raise an error message, prepend with filter name

:param msg: The message
:type msg: str
:raises: AnsibleError
"""
error = "Error when using plugin 'to_xml': {msg}".format(msg=msg)
raise AnsibleFilterError(error)


def to_xml(data, engine):
"""Convert data which is in json to xml"

:param data: The data passed in (data|to_xml(...))
:type data: xml
:param engine: Conversion library default=xmltodict
"""
if engine == "xmltodict":
if not HAS_XMLTODICT:
_raise_error("Missing required library xmltodict")
try:
data = ast.literal_eval(data)
res = xmltodict.unparse(data, pretty=True)
except Exception:
_raise_error("Input json is not valid")
return res
Loading