I think I found the right syntax (it seems to be working as I expected):
response = xmltodict.parse(xml, force_list=('Child','Brother'))
Just posting in case anyone would look for the same answer in the future.
Answer from Phileas on Stack Overflow
» pip install xmltodict
Videos
You can pass a postprocessing function to xmltodict, which allows you to modify the dict values.
But postprocecssing needs to return a key and a value:
import xmltodict
import json
def postprocessor(path, key, value):
if key == 'Pokemons' and not value:
return key, []
return key, value
xml = """<Something>
<Guitar>
<name>Walden</name>
<strings>5</strings>
</Guitar>
<Pokemons>
</Pokemons>
</Something>"""
res = xmltodict.parse(xml, postprocessor=postprocessor)
print(json.dumps(res, indent=2, sort_keys=True))
Output:
{
"Something": {
"Guitar": {
"name": "Walden",
"strings": "5"
},
"Pokemons": []
}
}
xmltodict.parse (with force_list arg) convert xml to a OrderedDict with tag as key irrespective for if node is empty or not (in case of empty node None value is stored in dict).
Therefore you have to filter your dict result for None yourself.
To filter dict you can define your custom method:
def filter_dict(item):
if not item:
return ''
elif isinstance(item, list):
return [it for it in item if it]
elif not hasattr(item, 'items'):
return item
else:
return {key: filter_dict(value) for key, value in item.items()}
>>> res = xmltodict.parse(xml, force_list=('Pokemons',))
>>> res = filter_dict(res)
>>> pokemons = res['Something']['Pokemons']
>>> pokemons
>>> []
This problem is discussed in this issue on Github. The xmltodict package now supports
d = xmltodict.parse(s, force_list={'car'})
Although this still doesn't create an empty list if the field is absent.
This is of course not an elegant way, but this is what i have done to get the code run (if someone hase the same probleme an found this via google):
import xmltodict
def guaranteed_list(x):
if not x:
return []
elif isinstance(x, list):
return x
else:
return [x]
mydict = xmltodict.parse(xmlstringResults)
for carsInGarage in guaranteed_list(mydict['garage']['car']):
# do something...
but i thing i will write my code again and "use XML directly" as one of the comments said.
Try a flatten function on the "episodes" key?
def flatten(it):
res = []
for item in it:
if not isinstance(item, list):
res.append(item)
continue
res.extend(item)
return res
xmltodict provides force_list for this use case.
Here's how it would work:
>>> xmltodict.parse(xml, force_list=('episode'))
{'child': {'episode': ['["a","b"]']}}