Skip to content

Instantly share code, notes, and snippets.

@reimund
Last active May 30, 2024 10:58
Show Gist options
  • Save reimund/5435343 to your computer and use it in GitHub Desktop.
Save reimund/5435343 to your computer and use it in GitHub Desktop.
Simple dictionary to xml serializer.
"""
Simple xml serializer.
@author Reimund Trost 2013
Example:
mydict = {
'name': 'The Andersson\'s',
'size': 4,
'children': {
'total-age': 62,
'child': [
{ 'name': 'Tom', 'sex': 'male', },
{
'name': 'Betty',
'sex': 'female',
'grandchildren': {
'grandchild': [
{ 'name': 'herbert', 'sex': 'male', },
{ 'name': 'lisa', 'sex': 'female', }
]
},
}
]
},
}
print(dict2xml(mydict, 'family'))
Output:
<family name="The Andersson's" size="4">
<children total-age="62">
<child name="Tom" sex="male"/>
<child name="Betty" sex="female">
<grandchildren>
<grandchild name="herbert" sex="male"/>
<grandchild name="lisa" sex="female"/>
</grandchildren>
</child>
</children>
</family>
"""
def dict2xml(d, root_node=None):
wrap = False if None == root_node or isinstance(d, list) else True
root = 'objects' if None == root_node else root_node
root_singular = root[:-1] if 's' == root[-1] and None == root_node else root
xml = ''
children = []
if isinstance(d, dict):
for key, value in dict.items(d):
if isinstance(value, dict):
children.append(dict2xml(value, key))
elif isinstance(value, list):
children.append(dict2xml(value, key))
else:
xml = xml + ' ' + key + '="' + str(value) + '"'
else:
for value in d:
children.append(dict2xml(value, root_singular))
end_tag = '>' if 0 < len(children) else '/>'
if wrap or isinstance(d, dict):
xml = '<' + root + xml + end_tag
if 0 < len(children):
for child in children:
xml = xml + child
if wrap or isinstance(d, dict):
xml = xml + '</' + root + '>'
return xml
@zappfinger
Copy link

Looks interesting. And the other way around? From XML to dict?

@Gerst20051
Copy link

i was able to do str(value.encode('ascii', 'ignore'))

@jharms
Copy link

jharms commented Jun 1, 2016

also available using pip install dict2xml.

@jonahfang
Copy link

change line 59 to avalid unicode error:

xml = '%s %s="%s"' % (xml,key,value)

@abeaclark
Copy link

Thanks for the great code! Would you mind adding a license? I want to make sure everything is in order if I use it.

@thomaswpp
Copy link

thomaswpp commented Jul 31, 2018

Thank You Very Much.. I made a small modification to attributes to be accepted starting with @.
Example: dict2xml(d, "NFe")

{
    'infNFe': 
            {'@versao': '3.10', '@Id': '35150469012656000120550030000783031122216144', 
         'ide': {
                      'mod', '55', 'serie', '3', 'nNF', '78303', 'dhEmi', '20/04/2015T15:36:3603:00', 
                       'dhSaiEnt', '21/04/2015T15:36:3603:00', 'idDest', '1', 'indFinal', '0', 'indPres', '9', 
                        'procEmi', '0', 'verProc', '61000', 'tpEmis', '1', 'finNFe', '1', 'natOp', 'SAIDA', 'tpNF', '1', 'indPag', '0'
                    }
            }
} 
<NFe>
<infNFe versao="3.10" Id="35150469012656000120550030000783031122216144">
<ide>
<mod>55</mod>
<tpNF>1</tpNF>
<idDest>1</idDest>
<indFinal>0</indFinal>
<dhEmi>20/04/2015T15:36:3603:00</dhEmi>
<natOp>SAIDA</natOp>
<indPres>9</indPres>
<tpEmis>1</tpEmis>
<nNF>78303</nNF>
<serie>3</serie>
<procEmi>0</procEmi>
<indPag>0</indPag>
<verProc>61000</verProc>
<dhSaiEnt>21/04/2015T15:36:3603:00</dhSaiEnt>
<finNFe>1</finNFe>
</ide>
</infNFe>
</NFe>
def dict2xml(d, root_node=None):
    wrap          =  False if None == root_node or isinstance(d, list) else True
    root          = 'objects' if None == root_node else root_node
    root_singular = root[:-1] if 's' == root[-1] and None == root_node else root
    xml           = ''
    attr          = ''
    children      = []

    if isinstance(d, dict):
        # print(d)
        for key, value in dict.items(d):
            if isinstance(value, dict):
                children.append(dict2xml(value, key))
            elif isinstance(value, list):
                children.append(dict2xml(value, key))
            elif key[0] == '@':
                attr = attr + ' ' + key[1::] + '="' + str(value) + '"'
            else:
                xml = '<' + key + ">" + str(value) + '</' + key + '>' 
                children.append(xml)

    else:
        #if list
        for value in d:
            children.append(dict2xml(value, root_singular))

    end_tag = '>' if 0 < len(children) else '/>'
    
    if wrap or isinstance(d, dict):
        xml = '<' + root + attr + end_tag

    if 0 < len(children):
        for child in children:
            xml = xml + child

        if wrap or isinstance(d, dict):
            xml = xml + '</' + root + '>'

    return xml

@mucthienton
Copy link

Thanks @thomaswpp, your modify fit my problem.

@yinhaibo01
Copy link

It's quite simple, and enough for simple situations. I like simple code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment