#!/usr/bin/env python
# encoding: utf-8
'''
This module is used to convert diction to xml and convert xml to diction
usage:
    import simplexml
    simplexml.dumps(dict)   # output xml string
    simplexml.loads(xml)    # output python dict
changelist:
    0.2: add unicode support.
'''

__version__ = 0.2
__author__ = "@boqiling"


from xml.dom.minidom import Document, parseString, Node

ROOTNAME = "xml"    # xml need a root name, dict doesn't.


def dumps(diction):
    '''convert diction to xml
    '''
    if(type(diction) == dict):
        xml = Dict2Xml().trans(diction)
        return xml


def loads(xml):
    '''convert xml to diction
    '''
    diction = Xml2Dict().trans(xml)
    return diction


class Xml2Dict(object):
    '''class to convert the xml to python diction
       usage:
           diction = Xml2Dict().trans("<xml>xml_string</xml>")
    '''

    def __init__(self):
        self.Dict = {}

    def remove_blanks(self, node):
        for x in node.childNodes:
            if x.nodeType == Node.TEXT_NODE:
                if x.nodeValue:
                    x.nodeValue = x.nodeValue.strip()
            elif x.nodeType == Node.ELEMENT_NODE:
                self.remove_blanks(x)

    def to_list(self, father):
        myList = []
        for node in father.childNodes:
            if(len(node.childNodes) > 1):
                myList.append(self.parse(node))
            else:
                myList.append(node.childNodes[0].nodeValue)
        return myList

    def parse(self, father):
        myDict = {}
        if(father.hasAttributes()):
            for attr in father.attributes.items():
                myDict.update({attr[0]: attr[1]})
        if(father.hasChildNodes()):
            if(len(father.childNodes) > 1):
                if(father.firstChild.nodeName == father.lastChild.nodeName):
                    # parse a list
                    listname = father.nodeName
                    tag = father.firstChild.nodeName
                    myDict.update({listname: {tag: self.to_list(father)}})
                else:
                    # parse a recurse dict
                    subDict = {}
                    for node in father.childNodes:
                        subDict.update(self.parse(node))
                    myDict.update({father.nodeName: subDict})
            else:
                # parse a value
                node = father.childNodes[0]
                if(node.nodeType == Node.TEXT_NODE):
                    myDict.update({father.nodeName: node.nodeValue})
                else:
                    myDict.update({father.nodeName: self.parse(node)})
        return myDict

    def trans(self, xml):
        self.doc = parseString(xml.encode("utf-8"))
        self.remove_blanks(self.doc)
        self.doc.normalize()
        self.root = self.doc.documentElement
        mydict = self.parse(self.root)
        self.Dict.update(mydict[ROOTNAME])
        return self.Dict


class Dict2Xml(object):
    '''class to convert the python diction to xml
       usage:
           xml = Dict2Xml().trans(diction)
    '''

    def __init__(self, **kvargs):
        self.doc = Document()
        self.rootName = kvargs.get("rootName", ROOTNAME)

    def build(self, father, structure):
        if type(structure) == dict:
            for k in structure:
                tag = self.doc.createElement(k)
                father.appendChild(tag)
                self.build(tag, structure[k])

        elif type(structure) == list:
            grandFather = father.parentNode
            tagName = father.tagName
            grandFather.removeChild(father)
            for l in structure:
                tag = self.doc.createElement(tagName)
                self.build(tag, l)
                grandFather.appendChild(tag)
        else:
            data = unicode(structure)
            tag = self.doc.createTextNode(data)
            father.appendChild(tag)

    def trans(self, diction):
        self.root = self.doc.createElement(self.rootName)
        self.doc.appendChild(self.root)
        self.build(self.root, diction)
        return self.doc.toprettyxml(indent="    ")
        #return self.doc.toxml("utf-8")


if __name__ == '__main__':
    from pprint import pprint as pp

    example = {
        "sn": 2103839,
        "item": "SNR",
        "date": "2009-11-25",
        "errorcode": 7,
        "errormsg": u"噪声太大",
        "signal": {"data": [1, 2, 3]},
        "noise": {"data": [5, 6, 7]},
        "round_59": {
            "fail": 1,
            "test_time": "2013-11-11 17:54:21",
            "test_result": "Pass"
            }
    }

    print("original:")
    pp(example)
    print("dict to xml:")
    myxml = dumps(example)
    print(myxml)
    print(type(myxml))

    print("xml to dict:")
    mydict = loads(myxml)
    pp(mydict)
    print mydict["errormsg"]

@@ -457,24 +457,40 @@
 umps(diction
+, rootname=%22XML%22
 ):%0A    '''co
@@ -564,32 +564,40 @@
  xml = Dict2Xml(
+rootname
 ).trans(diction)
@@ -2920,24 +2920,34 @@
 (mydict%5B
-ROOTNAME
+self.root.nodeName
 %5D)%0A     
@@ -3135,16 +3135,16 @@
 lf, 
-**kvargs
+rootname
 ):%0A 
@@ -3200,40 +3200,16 @@
 e = 
-kvargs.get(%22
 root
-N
+n
 ame
-%22, ROOTNAME)
 %0A%0A  
@@ -4363,25 +4363,22 @@
         
-%22errormsg
+u%22%E9%94%99%E8%AF%AF%E4%BF%A1%E6%81%AF
 %22: u%22%E5%99%AA%E5%A3%B0%E5%A4%AA
@@ -4827,16 +4827,13 @@
 ict%5B
-%22errormsg
+u%22%E9%94%99%E8%AF%AF%E4%BF%A1%E6%81%AF
 %22%5D%0A

fix unicode support