Позвольте мне начать с признания того, что я пытаюсь использовать 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
, поэтому я просто интересно, отключен ли способ десериализации входящего запроса?