3

I am trying to do xml that looks like:

<xml....
<key1>aaa </key1>
<key1>bbb</key1>
<key1>ccc</key1>
</xml>

using python dicttoxml lib

tried:

quest_dict = [{'key1': 'aaa'}, {'key1': 'bbb'}, {'key1': 'ccc'}]
request_xml = dicttoxml.dicttoxml(request_dict, attr_type=False, root=False)

but got bad xml not as excepted. Thanks for help!

Lior Pozin
  • 393
  • 1
  • 5
  • 14

2 Answers2

5

You can create a dictionary with a repeating key by wrapping the keys with a dummy class and then use dicttoxml on that dictionary. Use collections.OrderedDict if the order matters:

from dicttoxml import dicttoxml
from collections import OrderedDict

class Node(object):
    def __init__(self, name):
        self._name = name

    def __str__(self):
        return self._name

quest_dict = OrderedDict([(Node('key1'), 'aaa'), (Node('key1'), 'bbb'), (Node('key1'), 'ccc')])
request_xml = dicttoxml(quest_dict, attr_type=False, root=False)
print(request_xml)

This gives your desired output:

b'<key1>aaa</key1><key1>bbb</key1><key1>ccc</key1>'
Dave Reikher
  • 1,645
  • 1
  • 16
  • 15
2

You can get the xml you expect using the custom_root and item_func arguments to the dicttoxml method:

import dicttoxml

request_dict = ['aaa', 'bbb', 'ccc']
item_name = lambda x: 'key1'
request_xml = dicttoxml.dicttoxml(request_dict, attr_type=False, custom_root='xml', item_func=item_name)

print(request_xml.decode('utf-8'))

Output:

<xml><key1>aaa</key1><key1>bbb</key1><key1>ccc</key1></xml>


An extension to this example is solving the case of multiple repeating keys in a single xml, like defined by <xsd:element minOccurs="0" maxOccurs="unbounded"> which I could neither achieve using OrderedDict from Dave's answer. The closest result is using a the item_func lambda that names the items in the name of the parent:

import dicttoxml

xml_dict = {}
xml_dict['key1'] = ['aaa', 'bbb', 'ccc']
xml_dict['another-key'] = ['a','b','c']

item_name = lambda x: x
request_xml = dicttoxml.dicttoxml(xml_dict, attr_type=False, custom_root='xml', item_func=item_name)

print(request_xml.decode('utf-8'))

But then we you'll have to remove the parents from the result:

<xml>
    <key1>
        <key1>aaa</key1>
        ...

Clean up can be applied (explicit):

xml_str = request_xml.decode("utf-8", "strict")
xml_str = xml_str.replace('<key1><key1>', '<key1>').replace('</key1></key1>', '</key1>')
xml_str = xml_str.replace('<another-key><another-key>', '<another-key>').replace('</another-key></another-key>', '</another-key>')
print(xml_str)

Result:

<xml>
    <key1>aaa</key1>
    ...
    <another-key>a</another-key>
    ...
</xml>
rforce
  • 61
  • 2