Module pyboiler.hml
XML object (de)serialization in a similar interface to python.json
Expand source code
"""XML object (de)serialization in a similar interface to python.json"""
import xml.etree.ElementTree as ET
from xml.dom import minidom
from xml.etree.ElementTree import tostring
def dumps(obj: dict, tag="root", pretty: bool = True):
"""Serializes a python dict to xml notation"""
root = ET.Element(tag, {"t": "d"})
_serialize(obj, root)
xml = minidom.parseString(tostring(root))
if pretty:
return xml.toprettyxml()
return xml.toxml()
def loads(xml_str: str):
"""Deserializes xml to a python dictionary"""
xml_str = xml_str.replace("\n", "").replace("\t", "")
return _deserialize(ET.fromstring(xml_str))
def _serialize(obj, elem=None, tag=None, depth=0):
if elem is None:
elem = ET.Element("root")
elem.attrib["d"] = str(depth)
if isinstance(obj, str): # For strings
elem.text = obj
return
if hasattr(obj, "__iter__"): # For lists, tuples, sets, and dicts
if isinstance(obj, dict):
elem.attrib["t"] = "d"
for k, v in obj.items():
ele = ET.SubElement(elem, k, {"d": f"{depth+1}"})
_serialize(v, ele, k, depth=depth + 1)
return
elem.attrib["t"] = "l"
for idx, item in enumerate(obj):
ele = ET.SubElement(elem, f"i{idx}", {"d": f"{depth+1}"})
_serialize(item, ele, depth=depth + 1)
return
if obj is None:
elem.attrib["t"] = "n"
elem.text = "null"
return
elem.text = str(obj)
return
def _deserialize(root: ET.Element):
results = {}
def parse(root):
r_type = root.attrib.get("t", None)
r_depth = int(root.attrib.get("d"))
if r_type == "d":
return r_type, r_depth, parse_dict(root)
elif r_type == "l":
return r_type, r_depth, parse_list(root)
elif r_type == "n":
return r_type, r_depth, None
else:
return r_type, r_depth, root.text
def parse_dict(root):
res = {}
r_depth = int(root.attrib.get("d"))
for elem in root.iter():
if not int(elem.attrib.get("d")) == r_depth + 1:
continue
e_t, e_d, e_res = parse(elem)
res[elem.tag] = e_res
return res
def parse_list(root):
res = []
r_depth = int(root.attrib.get("d"))
for elem in root.iter():
if not int(elem.attrib.get("d")) == r_depth + 1:
continue
e_t, e_d, e_res = parse(elem)
res.append(e_res)
return res
r_depth = int(root.attrib.get("d")) # type: ignore
for elem in root.iter():
# print(f"{elem}: {elem.attrib.get('d')}")
if not int(elem.attrib.get("d")) == r_depth + 1: # type: ignore
continue
e_t, e_d, e_r = parse(elem)
results[elem.tag] = e_r
return results
Functions
def dumps(obj: dict, tag='root', pretty: bool = True)
-
Serializes a python dict to xml notation
Expand source code
def dumps(obj: dict, tag="root", pretty: bool = True): """Serializes a python dict to xml notation""" root = ET.Element(tag, {"t": "d"}) _serialize(obj, root) xml = minidom.parseString(tostring(root)) if pretty: return xml.toprettyxml() return xml.toxml()
def loads(xml_str: str)
-
Deserializes xml to a python dictionary
Expand source code
def loads(xml_str: str): """Deserializes xml to a python dictionary""" xml_str = xml_str.replace("\n", "").replace("\t", "") return _deserialize(ET.fromstring(xml_str))