Skip to content

Instantly share code, notes, and snippets.

@luiscoms
Created September 22, 2014 16:50
Show Gist options
  • Select an option

  • Save luiscoms/7c7f82015e27be2752b1 to your computer and use it in GitHub Desktop.

Select an option

Save luiscoms/7c7f82015e27be2752b1 to your computer and use it in GitHub Desktop.
Convert python dictionary to xml
# -*- coding: utf-8 -*-
''' Code based on
Huseyin Yilmaz - Convert python dictionary to xml - https://gist.github.com/huseyinyilmaz/1448723
Ye Lui - dict2xml - https://gist.github.com/jaux/1478881
Simple Dictionary XML Serializer - https://gist.github.com/reimund/5435343
'''
from xml.dom import minidom
from collections import Mapping
import unittest
def dict2element(root, structure, doc, cdatalist=[], attrlist=[]):
"""
Gets a dictionary like structure and converts its
content into xml elements. After that appends
resulted elements to root element. If root element
is a string object creates a new elements with the
given string and use that element as root.
This function returns a xml element object.
"""
assert isinstance(structure, Mapping), 'Structure must be a mapping object'
# if root is a string make it a element
if isinstance(root, str):
root = doc.createElement(root)
for key, value in structure.iteritems():
el = doc.createElement(str(key))
if isinstance(value, Mapping):
dict2element(el, value, doc, cdatalist, attrlist)
elif isinstance(value, list):
for item in value:
item_el = doc.createElement(str(key))
dict2element(item_el, item, doc, cdatalist, attrlist)
root.appendChild(item_el)
continue
else:
value = str(value) if value is not None else ''
if key in cdatalist:
value = doc.createCDATASection(value)
elif key in attrlist:
root.setAttribute(key, value)
continue
else:
value = doc.createTextNode(value)
el.appendChild(value)
root.appendChild(el)
return root
def dict2xml(structure, tostring=False, cdatalist=[], attrlist=[]):
"""
Gets a dict like object as a structure and returns a corresponding minidom
document object.
If str is needed instead of minidom, tostring parameter can be used
Restrictions:
Structure must only have one root.
Structure must consist of str or dict objects (other types will
converted into string)
"""
# This is main function call. which will return a document
assert len(structure) == 1, 'Structure must have only one root element'
assert isinstance(
structure, Mapping), 'Structure must be a mapping object such as dict'
root_element_name, value = next(structure.iteritems())
impl = minidom.getDOMImplementation()
doc = impl.createDocument(None, str(root_element_name), None)
dict2element(doc.documentElement, value, doc, cdatalist, attrlist)
return doc.toxml() if tostring else doc
# Unit tests
class TestSequenceFunctions(unittest.TestCase):
@unittest.expectedFailure
def testEmptyList(self):
d1 = []
res = dict2xml(d1)
print res.toxml()
@unittest.expectedFailure
def testEmptyDict(self):
d1 = {}
res = dict2xml(d1)
print res.toxml()
def testMinimal(self):
d1 = {
'root': {}
}
res = dict2xml(d1)
self.assertEquals(res.toxml(), '<?xml version="1.0" ?><root/>')
def testInnerElement(self):
d1 = {
'root': {
'elementwithtextnode': 'text content',
'innerelements': {
'innerinnerelements': 'inner element content'
}
}
}
# self.failUnless(lines)
res = dict2xml(d1)
self.assertEquals(res.toxml(), '<?xml version="1.0" ?><root><innerelements><innerinnerelements>inner element content</innerinnerelements></innerelements><elementwithtextnode>text content</elementwithtextnode></root>')
def testInnerElements(self):
d1 = {
'root': {
'elementwithtextnode': 'text content',
'innerelements': [
{
'innerinnerelements': 'inner element content'
},
{
'innerinnerelements': 'inner element content'
}
]
}
}
# self.failUnless(lines)
res = dict2xml(d1)
self.assertEquals(res.toxml(), '<?xml version="1.0" ?><root><innerelements><innerinnerelements>inner element content</innerinnerelements></innerelements><innerelements><innerinnerelements>inner element content</innerinnerelements></innerelements><elementwithtextnode>text content</elementwithtextnode></root>')
def testCDATA(self):
d1 = {
'root': {
'cdatatextnode': 'text content',
}
}
res = dict2xml(d1, False, ['cdatatextnode'])
self.assertEquals(res.toxml(), '<?xml version="1.0" ?><root><cdatatextnode><![CDATA[text content]]></cdatatextnode></root>')
def testAttribute(self):
d1 = {
'root': {
'elementwithattr': {
'attribute': 'xyz',
}
}
}
res = dict2xml(d1, False, [], ['attribute'])
self.assertEquals(res.toxml(), '<?xml version="1.0" ?><root><elementwithattr attribute="xyz"/></root>')
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment