简体   繁体   English

将 Suds SOAP 复杂数据类型解析为 Python dict

[英]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.我有一些数据来自使用SudsSOAP API,我需要在我的Python脚本中解析这些数据。 Before I go off and write a parser (there is more than just this one to do):在我开始编写解析器之前(要做的不仅仅是这个):

1) Does anyone recognise what this is? 1) 有人知道这是什么吗? It's the standard complex object datatype as returned by Suds (documentation) .它是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? 2) 如果是这样,是否有现有的库可用于将其转换为 Python 字典? How do I parse this object into a Python dict?如何将此对象解析为 Python 字典? It seems I can pass a dictionary to Suds but can't see an easy way of getting one back out.似乎我可以将字典传递给 Suds,但看不到一种简单的方法将其取出。

(ArrayOfBalance){
   Balance[] = 
      (Balance){
         Amount = 0.0
         Currency = "EUR"
      },
      (Balance){
         Amount = 0.0
         Currency = "USD"
      },
      (Balance){
         Amount = 0.0
         Currency = "GBP"
      },
 }

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. suds.client.Client类中有一个名为dict的类方法,它以sudsobject作为输入并返回 Python dict作为输出。 Check it out here: Official Suds Documentation在这里查看: 官方 Suds 文档

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 .您可能还想查看同一个类中的items类方法( 链接),它从 suds_object 中提取类似于dict上的items方法的items

You can cast the object to dict() , but you still get the complex data type used by suds.您可以将对象dict()dict() ,但您仍然会获得 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.如果有更简单的方法,我很想听听。

Found one solution :找到了一个解决方案

from suds.sudsobject import asdict

def recursive_asdict(d):
    """Convert Suds object into serializable format."""
    out = {}
    for k, v in asdict(d).iteritems():
        if hasattr(v, '__keylist__'):
            out[k] = recursive_asdict(v)
        elif isinstance(v, list):
            out[k] = []
            for item in v:
                if hasattr(item, '__keylist__'):
                    out[k].append(recursive_asdict(item))
                else:
                    out[k].append(item)
        else:
            out[k] = v
    return out

def suds_to_json(data):
    return json.dumps(recursive_asdict(data))

If subs are just nested dict and list, it should work.如果 subs 只是嵌套的 dict 和 list,它应该可以工作。

The right answer, as is often the case, is in the docs .通常情况下,正确答案 在 docs 中 The bits in (brackets) are objects which can contain other objects or types. (括号)中的位是可以包含其他对象或类型的对象。

In this case we have an ArrayOfBalance object which contains a list of Balance types, each of which has the attributes of Amount and Currency .在本例中,我们有一个ArrayOfBalance对象,其中包含一个Balance类型列表,每个类型都具有AmountCurrency属性。

These can all be referred to using .这些都可以使用. notation so the following one-liner does the trick.符号,所以下面的单行代码可以解决问题。

balance = {item.Currency: item.Amount for item in response.Balance}  

I was encountering a similar problem and had to read a suds response.我遇到了类似的问题,不得不阅读 suds 回复。 Suds response will be returned as a tuple consisting of objects. Suds 响应将作为由对象组成的元组返回。 len(response) will show you the number of objects contained in the suds response tuple. len(response) 将显示 suds 响应元组中包含的对象数量。 In order to access the first object we need to give response[0] .为了访问第一个对象,我们需要给出response[0]

In IDLE if you type >>>print response[0] followed by a period '.'在 IDLE 中,如果您键入>>>print response[0]后跟一个句点“.” symbol you will get a popup showing the various objects that can be accessed from this level.符号,您将看到一个弹出窗口,显示可以从此级别访问的各种对象。

Example: if you type response[0] .示例:如果您输入response[0] it will bring a popup and show the Balance object so the command would now become response[0].Balance .它将带来一个弹出窗口并显示 Balance 对象,因此命令现在将变为response[0].Balance

You can follow the same approach to get the list of objects under the subsequent levels您可以按照相同的方法获取后续级别下的对象列表

The checkaayush's answer is not recursive so, it does not consider the nested objects. checkaayush 的答案不是递归的,所以它不考虑嵌套对象。

Based on aGuegu Answer i did some changes to solve an issue when the suds object has dicts inside lists.基于 aGuegu 答案,当 suds 对象在列表中有 dicts 时,我做了一些更改以解决问题。

It works!它有效!


from suds.sudsobject import asdict

def recursive_asdict(d):
    """Convert Suds object into serializable format."""
    out = {}
    for k, v in asdict(d).items():
        if hasattr(v, '__keylist__'):
            out[k] = recursive_asdict(v)
        elif isinstance(v, list):
            out[k] = []
            for item in v:
                if hasattr(item, '__keylist__'):
                    out[k].append(recursive_asdict(item))
                elif not isinstance(item, list):
                    out[k] = item
                else:
                    out[k].append(item)
        else:
            out[k] = v
    return out

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM