Ваш исходный код создает некорректный XML и может создавать один и тот же XML для двух разных словарей (не инъективно , говоря математически).
Например, если у вас есть список в качестве значения единственного ключа в словаре:
d = { 'list': [1,2,3] }
Я ожидаю, что ваш код выдаст
<list>1</list><list>2</list><list>3</list>
и нет корневого элемента. Любой XML должен иметь один и только один корневой элемент.
Тогда, учитывая XML, созданный вашим кодом, невозможно сказать, является ли этот XML
<tag>1</tag>
был произведен из { 'tag': 1 }
или из { 'tag': [1] }
.
Итак, я предлагаю
- всегда начинается с корневого элемента
- представляют списки с двумя специальными тегами (например,
<list/>
и <item/>
) или помечают их как таковые в атрибутах
Затем, после принятия решения об этих концептуальных недостатках, мы можем генерировать правильный и однозначный XML. Я решил использовать атрибуты для разметки списков и использовал ElementTree для автоматического создания дерева XML. Также помогает рекурсия (add_value_to_xml
вызывается рекурсивно):
from xml.etree.ElementTree import Element, SubElement, tostring
def is_scalar(v):
return isinstance(v,basestring) or isinstance(v,float) \
or isinstance(v,int) or isinstance(v,bool)
def add_value_to_xml(root,v):
if type(v) == type({}):
for k,kv in v.iteritems():
vx = SubElement(root,unicode(k))
vx = add_value_to_xml(vx,kv)
elif type(v) == list:
root.set('type','list')
for e in v:
li = SubElement(root,root.tag)
li = add_value_to_xml(li,e)
li.set('type','item')
elif is_scalar(v):
root.text = unicode(v)
else:
raise Exception("add_value_to_xml: unsuppoted type (%s)"%type(v))
return root
def dict_to_xml(d,root='dict'):
x = Element(root)
x = add_value_to_xml(x,d)
return x
d = { 'float': 5194.177, 'str': 'eggs', 'int': 42,
'list': [1,2], 'dict': { 'recursion': True } }
x = dict_to_xml(d)
print tostring(x)
Результат преобразования тестового дикта:
<dict><int>42</int><dict><recursion>True</recursion></dict><float>5194.177</float><list type="list"><list type="item">1</list><list type="item">2</list></list><str>eggs</str></dict>