# This code taken from recipe # http://code.activestate.com/recipes/ # 573463-converting-xml-to-dictionary-and-back/ # Modified slightly to remove namespace and number of other small details # Licensed: PSF from xml.etree import ElementTree def _ns(tag): return tag[tag.find('}') + 1:] class XmlDictObject(dict): """ Adds object like functionality to the standard dictionary. """ def __init__(self, initdict=None): if initdict is None: initdict = {} dict.__init__(self, initdict) def __getattr__(self, item): return self.__getitem__(item) def __setattr__(self, item, value): self.__setitem__(item, value) def __str__(self): if '_text' in self: return self.__getitem__('_text') else: return '' @staticmethod def wrap(x): """ Static method to wrap a dictionary recursively as an XmlDictObject """ if isinstance(x, dict): return XmlDictObject( (k, XmlDictObject.wrap(v)) for (k, v) in x.items()) elif isinstance(x, list): return [XmlDictObject.wrap(v) for v in x] else: return x @staticmethod def _un_wrap(x): if isinstance(x, dict): return dict( (k, XmlDictObject._un_wrap(v)) for (k, v) in x.items()) elif isinstance(x, list): return [XmlDictObject._un_wrap(v) for v in x] else: return x def un_wrap(self): """ Recursively converts an XmlDictObject to a standard dictionary and returns the result. """ return XmlDictObject._un_wrap(self) def _convert_dict_to_xml_recurse(parent, dictitem): assert isinstance(dictitem, dict) if isinstance(dictitem, dict): for (tag, child) in dictitem.items(): if str(tag) == '_text': parent.text = str(child) elif isinstance(child, list): # iterate through the array and convert for listchild in child: elem = ElementTree.Element(tag) parent.append(elem) _convert_dict_to_xml_recurse(elem, listchild) else: elem = ElementTree.Element(tag) parent.append(elem) _convert_dict_to_xml_recurse(elem, child) else: parent.text = str(dictitem) def convert_dict_to_xml(xmldict): """ Converts a dictionary to an XML ElementTree Element """ roottag = list(xmldict.keys())[0] root = ElementTree.Element(roottag) _convert_dict_to_xml_recurse(root, xmldict[roottag]) return root def _convert_xml_to_dict_recurse(node, dictclass): nodedict = dictclass() if len(list(node.items())) > 0: # if we have attributes, set them if'attrib' in nodedict: nodedict['attrib'].update(dict(list(node.items()))) else: nodedict['attrib'] = {} nodedict['attrib'].update(dict(list(node.items()))) # We get a collision so attributes get their own hash! # nodedict.update(dict(node.items())) for child in node: # recursively add the element's children newitem = _convert_xml_to_dict_recurse(child, dictclass) if _ns(child.tag) in nodedict: # found duplicate tag, force a list if isinstance(nodedict[_ns(child.tag)], list): # append to existing list nodedict[_ns(child.tag)].append(newitem) else: # convert to list nodedict[_ns(child.tag)] = [nodedict[_ns(child.tag)], newitem] else: # only one, directly set the dictionary nodedict[_ns(child.tag)] = newitem if node.text is None: text = None else: text = node.text.strip() if len(nodedict) > 0: # if we have a dictionary add the text as a dictionary value # (if there is any) if text is not None and len(text) > 0: nodedict['_text'] = text else: # if we don't have child nodes or attributes, just set the text nodedict = text return nodedict def convert_xml_to_dict(root, dictclass=XmlDictObject): """ Converts an ElementTree Element to a dictionary """ return dictclass( {_ns(root.tag): _convert_xml_to_dict_recurse(root, dictclass)})