From: Royce Lv <lvroyce(a)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(a)linux.vnet.ibm.com>
Signed-off-by: Royce Lv <lvroyce(a)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