mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-06-17 00:07:37 +02:00
add raw option to xml parser for _ attribute prefix
This commit is contained in:
@ -5,6 +5,11 @@
|
|||||||
|
|
||||||
jc - JSON Convert `XML` file parser
|
jc - JSON Convert `XML` file parser
|
||||||
|
|
||||||
|
This parser adds a `@` prefix to attributes by default. This can be changed
|
||||||
|
to a `_` prefix by using the `-r` (cli) or `raw=True` (module) option.
|
||||||
|
|
||||||
|
Text values for nodes will have the key-name of `#text`.
|
||||||
|
|
||||||
Usage (cli):
|
Usage (cli):
|
||||||
|
|
||||||
$ cat foo.xml | jc --xml
|
$ cat foo.xml | jc --xml
|
||||||
@ -93,4 +98,4 @@ Returns:
|
|||||||
### Parser Information
|
### Parser Information
|
||||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||||
|
|
||||||
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
"""jc - JSON Convert `XML` file parser
|
"""jc - JSON Convert `XML` file parser
|
||||||
|
|
||||||
|
This parser adds a `@` prefix to attributes by default. This can be changed
|
||||||
|
to a `_` prefix by using the `-r` (cli) or `raw=True` (module) option.
|
||||||
|
|
||||||
|
Text values for nodes will have the key-name of `#text`.
|
||||||
|
|
||||||
Usage (cli):
|
Usage (cli):
|
||||||
|
|
||||||
$ cat foo.xml | jc --xml
|
$ cat foo.xml | jc --xml
|
||||||
@ -68,10 +73,15 @@ Examples:
|
|||||||
import jc.utils
|
import jc.utils
|
||||||
from jc.exceptions import LibraryNotInstalled
|
from jc.exceptions import LibraryNotInstalled
|
||||||
|
|
||||||
|
try:
|
||||||
|
import xmltodict
|
||||||
|
except Exception:
|
||||||
|
raise LibraryNotInstalled('The xmltodict library is not installed.')
|
||||||
|
|
||||||
|
|
||||||
class info():
|
class info():
|
||||||
"""Provides parser metadata (version, author, etc.)"""
|
"""Provides parser metadata (version, author, etc.)"""
|
||||||
version = '1.6'
|
version = '1.7'
|
||||||
description = 'XML file parser'
|
description = 'XML file parser'
|
||||||
author = 'Kelly Brazil'
|
author = 'Kelly Brazil'
|
||||||
author_email = 'kellyjonbrazil@gmail.com'
|
author_email = 'kellyjonbrazil@gmail.com'
|
||||||
@ -82,7 +92,7 @@ class info():
|
|||||||
__version__ = info.version
|
__version__ = info.version
|
||||||
|
|
||||||
|
|
||||||
def _process(proc_data):
|
def _process(proc_data, has_data=False):
|
||||||
"""
|
"""
|
||||||
Final processing to conform to the schema.
|
Final processing to conform to the schema.
|
||||||
|
|
||||||
@ -94,9 +104,13 @@ def _process(proc_data):
|
|||||||
|
|
||||||
Dictionary representing an XML document.
|
Dictionary representing an XML document.
|
||||||
"""
|
"""
|
||||||
|
raw_output = []
|
||||||
|
|
||||||
# No further processing
|
if has_data:
|
||||||
return proc_data
|
# standard output with @ prefix for attributes
|
||||||
|
raw_output = xmltodict.parse(proc_data)
|
||||||
|
|
||||||
|
return raw_output
|
||||||
|
|
||||||
|
|
||||||
def parse(data, raw=False, quiet=False):
|
def parse(data, raw=False, quiet=False):
|
||||||
@ -113,22 +127,19 @@ def parse(data, raw=False, quiet=False):
|
|||||||
|
|
||||||
Dictionary. Raw or processed structured data.
|
Dictionary. Raw or processed structured data.
|
||||||
"""
|
"""
|
||||||
# check if xml library is installed and fail gracefully if it is not
|
|
||||||
try:
|
|
||||||
import xmltodict
|
|
||||||
except Exception:
|
|
||||||
raise LibraryNotInstalled('The xmltodict library is not installed.')
|
|
||||||
|
|
||||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||||
jc.utils.input_type_check(data)
|
jc.utils.input_type_check(data)
|
||||||
|
|
||||||
raw_output = []
|
raw_output = []
|
||||||
|
has_data = False
|
||||||
|
|
||||||
if jc.utils.has_data(data):
|
if jc.utils.has_data(data):
|
||||||
|
has_data = True
|
||||||
|
|
||||||
raw_output = xmltodict.parse(data)
|
# modified output with _ prefix for attributes
|
||||||
|
raw_output = xmltodict.parse(data, attr_prefix='_')
|
||||||
|
|
||||||
if raw:
|
if raw:
|
||||||
return raw_output
|
return raw_output
|
||||||
else:
|
else:
|
||||||
return _process(raw_output)
|
return _process(data, has_data)
|
||||||
|
1
tests/fixtures/generic/xml-nmap-raw.json
vendored
Normal file
1
tests/fixtures/generic/xml-nmap-raw.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"nmaprun":{"_scanner":"nmap","_args":"nmap -oX - -p 443 galaxy.ansible.com","_start":"1666781498","_startstr":"Wed Oct 26 11:51:38 2022","_version":"7.92","_xmloutputversion":"1.05","scaninfo":{"_type":"connect","_protocol":"tcp","_numservices":"1","_services":"443"},"verbose":{"_level":"0"},"debugging":{"_level":"0"},"hosthint":{"status":{"_state":"up","_reason":"unknown-response","_reason_ttl":"0"},"address":{"_addr":"172.67.68.251","_addrtype":"ipv4"},"hostnames":{"hostname":{"_name":"galaxy.ansible.com","_type":"user"}}},"host":{"_starttime":"1666781498","_endtime":"1666781498","status":{"_state":"up","_reason":"syn-ack","_reason_ttl":"0"},"address":{"_addr":"172.67.68.251","_addrtype":"ipv4"},"hostnames":{"hostname":[{"_name":"galaxy.ansible.com","_type":"user"},{"_name":"galaxy.ansible.com","_type":"PTR"}]},"ports":{"port":{"_protocol":"tcp","_portid":"443","state":{"_state":"open","_reason":"syn-ack","_reason_ttl":"0"},"service":{"_name":"https","_method":"table","_conf":"3"}}},"times":{"_srtt":"12260","_rttvar":"9678","_to":"100000"}},"runstats":{"finished":{"_time":"1666781498","_timestr":"Wed Oct 26 11:51:38 2022","_summary":"Nmap done at Wed Oct 26 11:51:38 2022; 1 IP address (1 host up) scanned in 0.10 seconds","_elapsed":"0.10","_exit":"success"},"hosts":{"_up":"1","_down":"0","_total":"1"}}}}
|
1
tests/fixtures/generic/xml-nmap.json
vendored
Normal file
1
tests/fixtures/generic/xml-nmap.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"nmaprun":{"@scanner":"nmap","@args":"nmap -oX - -p 443 galaxy.ansible.com","@start":"1666781498","@startstr":"Wed Oct 26 11:51:38 2022","@version":"7.92","@xmloutputversion":"1.05","scaninfo":{"@type":"connect","@protocol":"tcp","@numservices":"1","@services":"443"},"verbose":{"@level":"0"},"debugging":{"@level":"0"},"hosthint":{"status":{"@state":"up","@reason":"unknown-response","@reason_ttl":"0"},"address":{"@addr":"172.67.68.251","@addrtype":"ipv4"},"hostnames":{"hostname":{"@name":"galaxy.ansible.com","@type":"user"}}},"host":{"@starttime":"1666781498","@endtime":"1666781498","status":{"@state":"up","@reason":"syn-ack","@reason_ttl":"0"},"address":{"@addr":"172.67.68.251","@addrtype":"ipv4"},"hostnames":{"hostname":[{"@name":"galaxy.ansible.com","@type":"user"},{"@name":"galaxy.ansible.com","@type":"PTR"}]},"ports":{"port":{"@protocol":"tcp","@portid":"443","state":{"@state":"open","@reason":"syn-ack","@reason_ttl":"0"},"service":{"@name":"https","@method":"table","@conf":"3"}}},"times":{"@srtt":"12260","@rttvar":"9678","@to":"100000"}},"runstats":{"finished":{"@time":"1666781498","@timestr":"Wed Oct 26 11:51:38 2022","@summary":"Nmap done at Wed Oct 26 11:51:38 2022; 1 IP address (1 host up) scanned in 0.10 seconds","@elapsed":"0.10","@exit":"success"},"hosts":{"@up":"1","@down":"0","@total":"1"}}}}
|
36
tests/fixtures/generic/xml-nmap.xml
vendored
Normal file
36
tests/fixtures/generic/xml-nmap.xml
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE nmaprun>
|
||||||
|
<?xml-stylesheet href="file:///usr/bin/../share/nmap/nmap.xsl" type="text/xsl"?>
|
||||||
|
<!-- Nmap 7.92 scan initiated Wed Oct 26 11:51:38 2022 as: nmap -oX - -p 443 galaxy.ansible.com -->
|
||||||
|
<nmaprun scanner="nmap" args="nmap -oX - -p 443 galaxy.ansible.com" start="1666781498" startstr="Wed Oct 26 11:51:38 2022" version="7.92" xmloutputversion="1.05">
|
||||||
|
<scaninfo type="connect" protocol="tcp" numservices="1" services="443"/>
|
||||||
|
<verbose level="0"/>
|
||||||
|
<debugging level="0"/>
|
||||||
|
<hosthint>
|
||||||
|
<status state="up" reason="unknown-response" reason_ttl="0"/>
|
||||||
|
<address addr="172.67.68.251" addrtype="ipv4"/>
|
||||||
|
<hostnames>
|
||||||
|
<hostname name="galaxy.ansible.com" type="user"/>
|
||||||
|
</hostnames>
|
||||||
|
</hosthint>
|
||||||
|
<host starttime="1666781498" endtime="1666781498">
|
||||||
|
<status state="up" reason="syn-ack" reason_ttl="0"/>
|
||||||
|
<address addr="172.67.68.251" addrtype="ipv4"/>
|
||||||
|
<hostnames>
|
||||||
|
<hostname name="galaxy.ansible.com" type="user"/>
|
||||||
|
<hostname name="galaxy.ansible.com" type="PTR"/>
|
||||||
|
</hostnames>
|
||||||
|
<ports>
|
||||||
|
<port protocol="tcp" portid="443">
|
||||||
|
<state state="open" reason="syn-ack" reason_ttl="0"/>
|
||||||
|
<service name="https" method="table" conf="3"/>
|
||||||
|
</port>
|
||||||
|
</ports>
|
||||||
|
<times srtt="12260" rttvar="9678" to="100000"/>
|
||||||
|
</host>
|
||||||
|
<runstats>
|
||||||
|
<finished time="1666781498" timestr="Wed Oct 26 11:51:38 2022" summary="Nmap done at Wed Oct 26 11:51:38 2022; 1 IP address (1 host up) scanned in 0.10 seconds" elapsed="0.10" exit="success"/>
|
||||||
|
<hosts up="1" down="0" total="1"/>
|
||||||
|
</runstats>
|
||||||
|
</nmaprun>
|
||||||
|
|
@ -15,6 +15,9 @@ class MyTests(unittest.TestCase):
|
|||||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-foodmenu.xml'), 'r', encoding='utf-8') as f:
|
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-foodmenu.xml'), 'r', encoding='utf-8') as f:
|
||||||
generic_xml_foodmenu = f.read()
|
generic_xml_foodmenu = f.read()
|
||||||
|
|
||||||
|
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-nmap.xml'), 'r', encoding='utf-8') as f:
|
||||||
|
generic_xml_nmap = f.read()
|
||||||
|
|
||||||
# output
|
# output
|
||||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-cd_catalog.json'), 'r', encoding='utf-8') as f:
|
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-cd_catalog.json'), 'r', encoding='utf-8') as f:
|
||||||
generic_xml_cd_catalog_json = json.loads(f.read())
|
generic_xml_cd_catalog_json = json.loads(f.read())
|
||||||
@ -22,6 +25,12 @@ class MyTests(unittest.TestCase):
|
|||||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-foodmenu.json'), 'r', encoding='utf-8') as f:
|
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-foodmenu.json'), 'r', encoding='utf-8') as f:
|
||||||
generic_xml_foodmenu_json = json.loads(f.read())
|
generic_xml_foodmenu_json = json.loads(f.read())
|
||||||
|
|
||||||
|
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-nmap.json'), 'r', encoding='utf-8') as f:
|
||||||
|
generic_xml_nmap_json = json.loads(f.read())
|
||||||
|
|
||||||
|
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/xml-nmap-raw.json'), 'r', encoding='utf-8') as f:
|
||||||
|
generic_xml_nmap_r_json = json.loads(f.read())
|
||||||
|
|
||||||
|
|
||||||
def test_xml_nodata(self):
|
def test_xml_nodata(self):
|
||||||
"""
|
"""
|
||||||
@ -29,6 +38,12 @@ class MyTests(unittest.TestCase):
|
|||||||
"""
|
"""
|
||||||
self.assertEqual(jc.parsers.xml.parse('', quiet=True), [])
|
self.assertEqual(jc.parsers.xml.parse('', quiet=True), [])
|
||||||
|
|
||||||
|
def test_xml_nodata_r(self):
|
||||||
|
"""
|
||||||
|
Test xml parser with no data and raw output
|
||||||
|
"""
|
||||||
|
self.assertEqual(jc.parsers.xml.parse('', raw=True, quiet=True), [])
|
||||||
|
|
||||||
def test_xml_cd_catalog(self):
|
def test_xml_cd_catalog(self):
|
||||||
"""
|
"""
|
||||||
Test the cd catalog xml file
|
Test the cd catalog xml file
|
||||||
@ -41,6 +56,18 @@ class MyTests(unittest.TestCase):
|
|||||||
"""
|
"""
|
||||||
self.assertEqual(jc.parsers.xml.parse(self.generic_xml_foodmenu, quiet=True), self.generic_xml_foodmenu_json)
|
self.assertEqual(jc.parsers.xml.parse(self.generic_xml_foodmenu, quiet=True), self.generic_xml_foodmenu_json)
|
||||||
|
|
||||||
|
def test_xml_nmap(self):
|
||||||
|
"""
|
||||||
|
Test nmap xml output
|
||||||
|
"""
|
||||||
|
self.assertEqual(jc.parsers.xml.parse(self.generic_xml_nmap, quiet=True), self.generic_xml_nmap_json)
|
||||||
|
|
||||||
|
def test_xml_nmap_r(self):
|
||||||
|
"""
|
||||||
|
Test nmap xml raw output
|
||||||
|
"""
|
||||||
|
self.assertEqual(jc.parsers.xml.parse(self.generic_xml_nmap, raw=True, quiet=True), self.generic_xml_nmap_r_json)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
Reference in New Issue
Block a user