diff options
Diffstat (limited to 'gsxws/xmltodict.py')
-rw-r--r-- | gsxws/xmltodict.py | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/gsxws/xmltodict.py b/gsxws/xmltodict.py new file mode 100644 index 0000000..c577e55 --- /dev/null +++ b/gsxws/xmltodict.py @@ -0,0 +1,183 @@ +## {{{ http://code.activestate.com/recipes/573463/ (r7) + +import re +import base64 +import tempfile +from datetime import datetime +from xml.etree import ElementTree + + +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): + v = self.__getitem__(item) + + if item in ["packingList", "proformaFileData", "returnLabelFileData"]: + v = base64.b64decode(v) + of = tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) + of.write(v) + return of.name + + try: + if isinstance(v, basestring): + v = unicode(v) # "must be unicode, not str" + + # convert Y and N to boolean + if re.search(r'^[YN]$', v): + v = (v == "Y") + + # strip currency prefix and munge into float + if re.search(r'Price$', item): + v = float(re.sub(r'[A-Z ,]', '', v)) + + # Convert timestamps to native Python type + # 18-Jan-13 14:38:04 + if re.search(r'TimeStamp$', item): + v = datetime.strptime(v, "%d-%b-%y %H:%M:%S") + + if re.search(r'Date$', item): + # looks like some sort of date, let's try to convert + try: + # standard GSX format: "mm/dd/yy" + dt = datetime.strptime(v, "%m/%d/%y") + v = dt.date() + except ValueError: + pass + + try: + # some dates are formatted as "yyyy-mm-dd" + dt = datetime.strptime(v, "%Y-%m-%d") + v = dt.date() + except (ValueError, TypeError): + pass + except TypeError: + pass + + return v + + def __setattr__(self, item, value): + self.__setitem__(item, value) + + def __str__(self): + if self.has_key('_text'): + 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.iteritems()) + elif isinstance(x, list): + return [XmlDictObject.Wrap(v) for v in x] + else: + return x + + @staticmethod + def _UnWrap(x): + if isinstance(x, dict): + return dict((k, XmlDictObject._UnWrap(v)) for (k, v) in x.iteritems()) + elif isinstance(x, list): + return [XmlDictObject._UnWrap(v) for v in x] + else: + return x + + def UnWrap(self): + """ + Recursively converts an XmlDictObject to a standard dictionary and returns the result. + """ + + return XmlDictObject._UnWrap(self) + + +def _ConvertDictToXmlRecurse(parent, dictitem): + assert type(dictitem) is not type([]) + + if isinstance(dictitem, dict): + for (tag, child) in dictitem.iteritems(): + if str(tag) == '_text': + parent.text = str(child) + elif type(child) is type([]): + # iterate through the array and convert + for listchild in child: + elem = ElementTree.Element(tag) + parent.append(elem) + _ConvertDictToXmlRecurse(elem, listchild) + else: + elem = ElementTree.Element(tag) + parent.append(elem) + _ConvertDictToXmlRecurse(elem, child) + else: + parent.text = str(dictitem) + + +def ConvertDictToXml(xmldict): + """ + Converts a dictionary to an XML ElementTree Element + """ + roottag = xmldict.keys()[0] + root = ElementTree.Element(roottag) + _ConvertDictToXmlRecurse(root, xmldict[roottag]) + return root + + +def _ConvertXmlToDictRecurse(node, dictclass): + nodedict = dictclass() + + if len(node.items()) > 0: + # if we have attributes, set them + nodedict.update(dict(node.items())) + + for child in node: + # recursively add the element's children + newitem = _ConvertXmlToDictRecurse(child, dictclass) + if nodedict.has_key(child.tag): + # found duplicate tag, force a list + if type(nodedict[child.tag]) is type([]): + # append to existing list + nodedict[child.tag].append(newitem) + else: + # convert to list + nodedict[child.tag] = [nodedict[child.tag], newitem] + else: + # only one, directly set the dictionary + nodedict[child.tag] = newitem + + if node.text is None: + text = '' + 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 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 ConvertXmlToDict(root, dictclass=XmlDictObject): + """ + Converts an XML file or ElementTree Element to a dictionary + """ + # If a string is passed in, try to open it as a file + if type(root) == type(''): + root = ElementTree.parse(root).getroot() + elif not isinstance(root, ElementTree.Element): + raise TypeError("Expected ElementTree.Element or file path string") + + return dictclass({root.tag: _ConvertXmlToDictRecurse(root, dictclass)}) |