Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xmltodict does not return a list for one element

The following Code produces an error, if there is only one "car" in "garage":

import xmltodict

mydict = xmltodict.parse(xmlstringResults)    
for carsInGarage in mydict['garage']['car']:
    # do something...

The Reason is that mydict['garage']['car'] is only a list if there is more than one element of "car". So I did something like this:

import xmltodict

mydict = xmltodict.parse(xmlstringResults)
if isinstance(mydict['garage']['car'], list):
    for carsInGarage in mydict['garage']['car']:
        # do something for each car...
else:
    # do something for the car

to get the code to run. But for more advanced operations this is no solution.

Does someone know some kind of function to use, even if there is only one element?

like image 390
user2111880 Avatar asked May 13 '16 10:05

user2111880


3 Answers

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.

like image 194
Jack Valmadre Avatar answered Oct 22 '22 16:10

Jack Valmadre


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.

like image 38
user2111880 Avatar answered Oct 22 '22 16:10

user2111880


I am using the combination of

1)

json_dict = xmltodict.parse(s, force_list={'item'})

And

2)

# Removes a level in python dict if it has only one specific key
# 
# Examples: 
# recursive_skip_dict_key_level({"c": {"a": "b"}}, "c")  # -> {"a", "b"}
# recursive_skip_dict_key_level({"c": ["a", "b"]}, "c") # -> ["a", "b"]
#
def recursive_skip_dict_key_level(d, skipped_key):
    if issubclass(type(d), dict):
        if list(d.keys()) == [skipped_key]:
            return recursive_skip_dict_key_level(d[skipped_key], skipped_key)
        else:
            for key in d.keys():
                d[key] = recursive_skip_dict_key_level(d[key], skipped_key)
            return d
    elif issubclass(type(d), list):
        new_list = []
        for e in d: 
            new_list.append(recursive_skip_dict_key_level(e, skipped_key))
        return new_list
    else: 
        return d

# Removes None values from a dict
# 
# Examples: 
# recursive_remove_none({"a": None})  # -> {}
# recursive_remove_none([None]) # -> []
#
def recursive_remove_none(d):
    if issubclass(type(d), dict):
        new_dict = {}
        for key in d.keys():
            if not (d[key] is None):
                new_dict[key] = recursive_remove_none(d[key])
        return new_dict
    elif issubclass(type(d), list):
        new_list = []
        for e in d: 
            if not (e is None):
                new_list.append(recursive_remove_none(e))
        return new_list
    else: 
        return d       

json_dict = recursive_skip_dict_key_level(json_dict, "item")
json_dict = recursive_remove_none(json_dict)

to interpret any "item" XML-elements as lists.

like image 32
Eugene Lycenok Avatar answered Oct 22 '22 17:10

Eugene Lycenok