Skip to content

Instantly share code, notes, and snippets.

@huseyinyilmaz
Last active November 26, 2020 12:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save huseyinyilmaz/1448723 to your computer and use it in GitHub Desktop.
Save huseyinyilmaz/1448723 to your computer and use it in GitHub Desktop.
Convert python dictionary to xml
# -*- coding: utf-8 -*-
import unittest
import xmlutils
from xml.dom import minidom
from collections import Mapping
def dict2element(root, structure, doc):
"""
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 such as dict'
# 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("" if key is None else unicode(key))
if isinstance(value, Mapping):
dict2element(el, value, doc)
else:
el.appendChild(doc.createTextNode("" if value is None
else unicode(value)))
root.appendChild(el)
return root
def dict2xml(structure, tostring=False):
"""
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)
Sample structure object would be
{'root':{'elementwithtextnode':'text content',
'innerelements':{'innerinnerelements':'inner element content'}}}
result for this structure would be
'<?xml version="1.0" ?>
<root>
<innerelements>
<innerinnerelements>inner element content</innerinnerelements>
</innerelements>
<elementwithtextnode>text content</elementwithtextnode>
</root>'
"""
# 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, unicode(root_element_name), None)
dict2element(doc.documentElement, value, doc)
return doc.toxml() if tostring else doc
#############
# unittests #
#############
class TestValidXML(unittest.TestCase):
dict_value = {'root':
{'elementwithtextnode': 'text content',
'innerelements': {'innerinnerelements': 'inner content'}}}
str_value = ('<?xml version="1.0" ?>'
'<root>'
'<innerelements>'
'<innerinnerelements>inner content</innerinnerelements>'
'</innerelements>'
'<elementwithtextnode>text content</elementwithtextnode>'
'</root>')
unicode_dict_value = {'root': {u'kâğıt': u'ığdır'}}
unicode_value = u'<?xml version="1.0" ?><root><kâğıt>ığdır</kâğıt></root>'
def test_valid(self):
xml_value = xmlutils.dict2xml(self.dict_value)
self.assertEqual(xml_value.toxml(), self.str_value)
def test_unicode(self):
xml_value = xmlutils.dict2xml(self.unicode_dict_value)
self.assertEqual(xml_value.toxml(), self.unicode_value)
if __name__ == '__main__':
unittest.main()
@nooperpudd
Copy link

I think u need to support unicode , just like textnode , if the strvalue is uniocde ,it will raise an error.

if isinstance(value,Mapping):
       dict2element(el,value,doc)
else:
       text_value = ""
       if value is not None:
                text_value = value.encode("utf-8") if isinstance(value, unicode) else str(value)

@huseyinyilmaz
Copy link
Author

@nooperpudd Sorry about the late response.
You are right. Code was not supporting unicode. I have change it to support unicode. But instead of encoding it myself I am letting xml library to handle encoding on its own. This version should not have any problem with unicode values.

@arnab-s
Copy link

arnab-s commented Dec 28, 2015

How do I run the above code?

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