Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing Suds SOAP complex data type into Python dict

I have some data coming from a SOAP API using Suds which I need to parse in my Python script. Before I go off and write a parser (there is more than just this one to do):

1) Does anyone recognise what this is? It's the standard complex object datatype as returned by Suds (documentation). Should have spotted that.

2) If so, is there an existing library that I can use to convert it to a Python dictionary? How do I parse this object into a Python dict? It seems I can pass a dictionary to Suds but can't see an easy way of getting one back out.

(ArrayOfBalance){
   Balance[] = 
      (Balance){
         Amount = 0.0
         Currency = "EUR"
      },
      (Balance){
         Amount = 0.0
         Currency = "USD"
      },
      (Balance){
         Amount = 0.0
         Currency = "GBP"
      },
 }
like image 758
Jamie Bull Avatar asked Jul 10 '13 22:07

Jamie Bull


2 Answers

There is a class method called dict in suds.client.Client class which takes a sudsobject as input and returns a Python dict as output. Check it out here: Official Suds Documentation

The resulting snippet becomes as elegant as this:

from suds.client import Client

# Code to obtain your suds_object here...

required_dict = Client.dict(suds_object)

You might also want to check out items class method (link) in the same class which extracts items from suds_object similar to items method on dict.

like image 114
aayushsarva Avatar answered Nov 12 '22 20:11

aayushsarva


You can cast the object to dict(), but you still get the complex data type used by suds. So here are some helpful functions that I wrote just for the occasion:

def basic_sobject_to_dict(obj):
    """Converts suds object to dict very quickly.
    Does not serialize date time or normalize key case.
    :param obj: suds object
    :return: dict object
    """
    if not hasattr(obj, '__keylist__'):
        return obj
    data = {}
    fields = obj.__keylist__
    for field in fields:
        val = getattr(obj, field)
        if isinstance(val, list):
            data[field] = []
            for item in val:
                data[field].append(basic_sobject_to_dict(item))
        else:
            data[field] = basic_sobject_to_dict(val)
    return data


def sobject_to_dict(obj, key_to_lower=False, json_serialize=False):
    """
    Converts a suds object to a dict.
    :param json_serialize: If set, changes date and time types to iso string.
    :param key_to_lower: If set, changes index key name to lower case.
    :param obj: suds object
    :return: dict object
    """
    import datetime

    if not hasattr(obj, '__keylist__'):
        if json_serialize and isinstance(obj, (datetime.datetime, datetime.time, datetime.date)):
            return obj.isoformat()
        else:
            return obj
    data = {}
    fields = obj.__keylist__
    for field in fields:
        val = getattr(obj, field)
        if key_to_lower:
            field = field.lower()
        if isinstance(val, list):
            data[field] = []
            for item in val:
                data[field].append(sobject_to_dict(item, json_serialize=json_serialize))
        elif isinstance(val, (datetime.datetime, datetime.time, datetime.date)):
            data[field] = val.isoformat()
        else:
            data[field] = sobject_to_dict(val, json_serialize=json_serialize)
    return data


def sobject_to_json(obj, key_to_lower=False):
    """
    Converts a suds object to json.
    :param obj: suds object
    :param key_to_lower: If set, changes index key name to lower case.
    :return: json object
    """
    import json
    data = sobject_to_dict(obj, key_to_lower=key_to_lower, json_serialize=True)
    return json.dumps(data)

If there is an easier way, I would love to hear about it.

like image 27
radtek Avatar answered Nov 12 '22 18:11

radtek