Выполните синтаксический анализ SOAP-запросов с помощью zeep, которые включают xsd: choice - PullRequest
0 голосов
/ 27 марта 2019

Позвольте мне начать с признания того, что я пытаюсь использовать zeep таким образом, который, вероятно, нестандартен и, возможно, не поддерживается. При этом до сих пор это работало фантастически, и это единственная проблема, которую я обнаружил.

Я написал SOAP-сервис на Python и использую zeep (3.2.0) для облегчения преобразования в / из конверта SOAP и объекта Python (zeep.xsd.CompoundValue). Вот пример кода, который иллюстрирует, как я это делаю (извиняюсь за то, что не предоставил полностью работоспособный пример; я не вправе делиться WSDL или XSD):

import zeep, requests
from lxml import etree

WSDL_URL = 'http://example.com/sample.wsdl'
OPERATION_NAME = 'sampleOperation'
RAW_ENVELOPE = '<soap-env:Envelope>...</soap-env:Envelope>'

document = etree.fromstring(RAW_ENVELOPE)

session = requests.Session()
transport = zeep.transports.Transport(session=session)
wsdl = zeep.wsdl.Document(WSDL_URL, transport=transport)

soap_service = wsdl.services.values()[0]
soap_port = soap_service.ports.values()[0]
soap_binding = soap_port.binding
operation = soap_binding.get(OPERATION_NAME)

data = operation.input.deserialize(document)

Когда это удается (что происходит во всех случаях, кроме этого), тогда data содержит все иерархические данные из конверта SOAP, правильно проанализированные в соответствии со спецификациями WSDL / XSD.

Однако в данном конкретном XSD (который предоставляется нашим поставщиком, и мы не можем его изменить), есть часть, которая определяет xsd:choice спецификацию:

<xsd:element name="section" type="sectionType" minOccurs="0" maxOccurs="unbounded">
</xsd:element>

...

<xsd:complexType name="sectionType">
    ...
    <xsd:group name="sectionItemGroup">
        <xsd:choice>
            <xsd:element name="section" type="sectionType">
            </xsd:element>
            <xsd:element name="item" type="itemType">
            </xsd:element>
        </xsd:choice>
    </xsd:group>
    ...
</xsd:complexType>

Когда я пытаюсь отправить запрос на сервер, который содержит один из этих <item> подэлементов, я получаю сообщение об ошибке при вызове deserialize() выше:

  File "/home/docker/docker_env/local/lib/python2.7/site-packages/zeep/xsd/elements/indicators.py", line 689, in parse_kwargs
    available_sub_kwargs = set(sub_kwargs.keys())
AttributeError: 'str' object has no attribute 'keys'

В этом случае значение sub_kwargs (из последней строки трассы) равно _value_1, что, конечно, является строкой, а не как идикт, как ожидалось, следовательно, ошибка.

На основании информации https://python -zeep.readthedocs.io / en / master / datastructures.html # nested-list-using-value-1 , я уже знал о _value_1 нюанс, и успешно использовали его в другом проекте при отправке SOAP запроса к внешней службе SOAP, которая содержала xsd:choice в очень похожем XSD (того же поставщика). Я также могу использовать его для правильной генерации действующего конверта SOAP для моей собственной службы. Например, если я сделаю:

data = {
    ...,
    'section': {
        ...,
        '_value_1': [{'item': { ... }],
    },
}
zeep_client.service.sampleOperation(**data)

Затем в службу отправляется правильный XML на основе WSDL / XSD:

<ns0:sampleOperationRequest>
    ...
    <section>
        ...
        <item>
            ...
        </item>
    </section>
    ...
</ns0:sampleOperationRequest>

Но когда я пытаюсь пойти по другому пути и десериализовать XML в объект Zeep CompoundValue, он взрывается.

Я бы предположил, что есть какой-то способ сделать это, даже при использовании zeep в качестве чистого клиента, потому что для ответа SOAP можно включить xsd:choice, поэтому я просто интересно, отключен ли способ десериализации входящего запроса?

...