Reputation: 1201
I've inherited the following code which is working great, apart from when only a single data item is return from the original xml. When that occurs the following error is thrown: 'TypeError: string indices must be integers'
result = xmltodict.parse(get_xml())
latest_result = result['Response']['Items']['Item']
myJsonData = json.dumps(latest_result)
j= json.loads(myJason)
print type(j)
for item in j:
print (item['Id'])
print (item['OrderId'])
I have narrowed the change in behaviour to a difference in datatype here:
print type(j)
When only a single ['Item'] is returned from the source XML the datatype of j is a 'dict', whilst the rest of the time (greater than one ['Item']) its a 'list'.
Hope someone can help.
Upvotes: 0
Views: 518
Reputation: 473873
This is a common xmltodict
module usage problem. When there is a single child, by default, it makes a dict
out of it and not a list with a single item. Relevant github issue:
To workaround it, one option would be to set the dict_constructor
argument:
from collections import defaultdict
xmltodict.parse(xml, dict_constructor=lambda *args, **kwargs: defaultdict(list, *args, **kwargs))
Upvotes: 1
Reputation: 1122282
Encoding to JSON then decoding again has nothing to do with your question. It is a red herring, you can use latest_result
and still get the same error.
The result['Response']['Items']['Item']
can evidently be either a list of dictionaries, or a single dictionary. When iterating over a list, you'll get contained elements, while iteration over a dictionary gives you the keys. So your item
elements are strings (each a key in the dictionary) and you can't address elements in that string with 'Id'
or 'OrderId'
.
Test for the type or use exception handling:
if isinstance(latest_result, dict):
# just one result, wrap it in a single-element list
latest_result = [latest_result]
Alternatively, fix up the xmltodict
code (which you didn't share or otherwise identify) to always return lists for elements, even when there is just a single one.
Upvotes: 1