
From: Royce Lv <lvroyce@linux.vnet.ibm.com> Add an xml parser to xmlutils.py to deal with the increasing need in kimchi to converse an xml to dict. Signed-off-by: Bing Bu Cao <mars@linux.vnet.ibm.com> Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/exception.py | 4 ++++ src/kimchi/xmlutils.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/kimchi/exception.py b/src/kimchi/exception.py index bff0a18..623e6b3 100644 --- a/src/kimchi/exception.py +++ b/src/kimchi/exception.py @@ -43,3 +43,7 @@ class InvalidOperation(Exception): class IsoFormatError(Exception): pass + + +class ParseError(Exception): + pass diff --git a/src/kimchi/xmlutils.py b/src/kimchi/xmlutils.py index 51ff0ec..f94db30 100644 --- a/src/kimchi/xmlutils.py +++ b/src/kimchi/xmlutils.py @@ -23,7 +23,11 @@ import libxml2 -from xml.etree import ElementTree +from collections import defaultdict +from xml.etree import ElementTree as ET + + +from kimchi.exception import ParseError def xpath_get_text(xml, expr): @@ -36,7 +40,51 @@ def xpath_get_text(xml, expr): def xml_item_update(xml, xpath, value): - root = ElementTree.fromstring(xml) + root = ET.fromstring(xml) item = root.find(xpath) item.text = value - return ElementTree.tostring(root, encoding="utf-8") + return ET.tostring(root, encoding="utf-8") + + +def xml_to_dict(xml, fromstring=True): + try: + if fromstring: + t = ET.fromstring(xml) + else: + t = ET.parse(xml).getroot() + except ET.ParseError: + raise ParseError("XML parse failed, invalid XML file") + return _etree_to_dict(t) + + +def _etree_to_dict(t): + # Convert an etree object to dict + d = {t.tag: {} if t.attrib else None} + children = list(t) + td = {} + if children: + dd = defaultdict(list) + #if has subelement, iteration as it's a new element + for dc in map(_etree_to_dict, children): + for k, v in dc.iteritems(): + dd[k].append(v) + for k, v in dd.iteritems(): + if len(v) == 1: + va = v[0] + else: + va = v + td.update({k: va}) + d[t.tag] = td + + #prepend '@' to attr and '#' to value + if t.attrib: + d[t.tag].update((k, v) for k, v in t.attrib.iteritems()) + if t.text: + text = t.text.strip() + if children or t.attrib: + if text: + d[t.tag]['#value'] = text + else: + d[t.tag] = text + + return d -- 1.8.1.2