Разбор сложного типа данных Suds SOAP в Python dict

У меня есть некоторые данные, поступающие из SOAP API с использованием Suds, которые мне нужно проанализировать в моем сценарии Python. Прежде чем я уйду и напишу синтаксический анализатор (есть еще что-то, что нужно сделать):

1) Кто-нибудь знает, что это такое? Это стандартный тип данных сложного объекта, возвращаемый Suds (документация). Должен был заметить это.

2) Если да, существует ли существующая библиотека, которую я могу использовать для преобразования ее в словарь Python? Как мне преобразовать этот объект в словарь Python? Кажется, я могу передать словарь Suds, но не вижу простого способа получить его обратно.

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

person Jamie Bull    schedule 10.07.2013    source источник
comment
вау.. Я могу честно сказать, что за 20 лет работы я никогда не видел такой формы сериализации. Теперь я ДОЛЖЕН знать, что это такое, лол. Можете ли вы дать нам контекст для данных?   -  person Dustin Anderson    schedule 11.07.2013
comment
Рада, что не только я! Это ответ о балансе кошелька от API OKPay.   -  person Jamie Bull    schedule 11.07.2013
comment
Похоже на самодельную структуру данных :-\   -  person tamasgal    schedule 11.07.2013
comment
Как я и подозревал. Однако на самом деле он ведет себя как объект. Если вы попробуете и response.split(',') он даст AttributeError: ArrayOfBalance instance has no attribute 'split'. Собираюсь копаться в документах немного больше.   -  person Jamie Bull    schedule 11.07.2013


Ответы (6)


Существует метод класса с именем dict в классе suds.client.Client, который принимает sudsobject в качестве входных данных и возвращает Python dict в качестве выходных данных. Ознакомьтесь с ним здесь: Официальный Документация Suds

Результирующий фрагмент становится таким же элегантным, как этот:

from suds.client import Client

# Code to obtain your suds_object here...

required_dict = Client.dict(suds_object)

Вы также можете ознакомиться с методом класса items (link) в том же классе, который извлекает элементы из suds_object аналогично методу items в dict.

person aayushsarva    schedule 10.10.2016
comment
теперь, когда я добрался до python dic, как я могу извлечь из него информацию. - person Ayyoub; 31.03.2017
comment
дает вам поверхностную копию, которая бесполезна, если у вас есть вложенные sudsobjects - person Rich Steinmetz; 22.11.2020
comment
это сработало для некоторых моих требований - спасибо :) - person MistaWizard; 04.12.2020

Вы можете привести объект к dict(), но вы все равно получите сложный тип данных, используемый suds. Итак, вот несколько полезных функций, которые я написал специально для этого случая:

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)

Если есть более простой способ, я хотел бы услышать об этом.

person radtek    schedule 18.01.2016

Найдено одно решение:

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))

Если подпрограммы представляют собой просто вложенные словарь и список, это должно работать.

person aGuegu    schedule 06.05.2015

Я столкнулся с подобной проблемой, и мне пришлось прочитать ответ пены. Ответ Suds будет возвращен в виде кортежа, состоящего из объектов. len(response) покажет вам количество объектов, содержащихся в кортеже ответа suds. Чтобы получить доступ к первому объекту, нам нужно указать response[0].

В IDLE, если вы введете >>>print response[0], за которым следует точка '.' вы получите всплывающее окно, показывающее различные объекты, к которым можно получить доступ с этого уровня.

Пример: если вы наберете response[0]. это вызовет всплывающее окно и покажет объект Balance, поэтому команда теперь станет response[0].Balance.

Вы можете использовать тот же подход, чтобы получить список объектов на последующих уровнях.

person earthProgrammer    schedule 25.12.2014

Правильный ответ, как это часто бывает, указан в документации. Биты в скобках — это объекты, которые могут содержать другие объекты или типы.

В этом случае у нас есть объект ArrayOfBalance, который содержит список типов Balance, каждый из которых имеет атрибуты Amount и Currency.

На все это можно ссылаться, используя нотацию ., поэтому следующий однострочный код делает свое дело.

balance = {item.Currency: item.Amount for item in response.Balance}  
person Jamie Bull    schedule 11.07.2013
comment
Ссылка, которую вы предоставили, мертва - она ​​была повторно размещена где-то еще? - person Eric Fulmer; 10.08.2018
comment
Имейте в виду, что это было 5 лет назад, и хостинга Fedora, похоже, больше не существует. Я отредактировал спасенную копию документов, но важные части находятся в ответе здесь. - person Jamie Bull; 10.08.2018

Ответ checkaayush не является рекурсивным, поэтому он не учитывает вложенные объекты.

Основываясь на ответе aGuegu, я внес некоторые изменения, чтобы решить проблему, когда объект suds имеет словари внутри списков.

Оно работает!


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
person Gustavo Díaz    schedule 22.02.2018