Skip to content

Commit

Permalink
refactor: [xml] add argument 'to_str' to some functions and avoid com…
Browse files Browse the repository at this point in the history
…pute it more than once
  • Loading branch information
ssato committed Mar 18, 2017
1 parent df61749 commit 538be5d
Showing 1 changed file with 12 additions and 8 deletions.
20 changes: 12 additions & 8 deletions anyconfig/backend/xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,18 +378,19 @@ def _elem_from_descendants(children_nodes, **options):
yield celem


def _get_or_update_parent(key, val, parent=None, **options):
def _get_or_update_parent(key, val, to_str, parent=None, **options):
"""
:param key: Key of current child (dict{,-like} object)
:param val: Value of current child (dict{,-like} object or [dict{,...}])
:param to_str: Callable to convert value to string
:param parent: XML ElementTree parent node object or None
:param options: Keyword options, see :func:`container_to_etree`
"""
elem = ET.Element(key)

vals = val if anyconfig.utils.is_iterable(val) else [val]
for val in vals:
container_to_etree(val, parent=elem, **options)
container_to_etree(val, parent=elem, to_str=to_str, **options)

if parent is None: # 'elem' is the top level etree.
return elem
Expand All @@ -401,21 +402,23 @@ def _get_or_update_parent(key, val, parent=None, **options):
_ATC = ("attrs", "text", "children")


def container_to_etree(obj, parent=None, **options):
def container_to_etree(obj, parent=None, to_str=None, **options):
"""
Convert a dict-like object to XML ElementTree.
:param obj: Container instance to convert to
:param parent: XML ElementTree parent node object or None
:param to_str: Callable to convert value to string or None
:param options: Keyword options,
- tags: Dict of tags for special nodes to keep XML info, attributes,
text and children nodes, e.g. {"attrs": "@attrs", "text": "#text"}
"""
_str = _to_str_fn(**options)
if to_str is None:
to_str = _to_str_fn(**options)

if not anyconfig.utils.is_dict_like(obj):
obj = False if obj is None else _str(obj)
obj = False if obj is None else to_str(obj)
if parent is not None and obj:
parent.text = obj # Parent is a leaf text node.
return # All attributes and text should be set already.
Expand All @@ -425,14 +428,15 @@ def container_to_etree(obj, parent=None, **options):

for key, val in anyconfig.compat.iteritems(obj):
if key == attrs:
_elem_set_attrs(val, parent, _str)
_elem_set_attrs(val, parent, to_str)
elif key == text:
parent.text = _str(val)
parent.text = to_str(val)
elif key == children:
for celem in _elem_from_descendants(val, **options):
parent.append(celem)
else:
parent = _get_or_update_parent(key, val, parent=parent, **options)
parent = _get_or_update_parent(key, val, to_str, parent=parent,
**options)

return ET.ElementTree(parent)

Expand Down

0 comments on commit 538be5d

Please sign in to comment.