使用zeep发出解析包含xsd:choice

时间:2019-03-26 21:14:04

标签: python soap wsdl zeep

让我首先确认我正在尝试以可能非标准且可能不受支持的方式使用zeep。话虽如此,到目前为止,它的运行非常出色,而这是我发现的唯一问题。

我已经用Python编写了SOAP服务,并且正在使用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,这当然是字符串,而不是预期的dict,因此是错误。

基于https://python-zeep.readthedocs.io/en/master/datastructures.html#nested-list-using-value-1的信息,我已经意识到_value_1的细微差别,并且在向外部进行SOAP request 时成功地将其用于另一个项目在非常相似的XSD(相同的供应商)中包含xsd:choice的SOAP服务。我还可以使用它为我自己的服务正确生成一个有效的SOAP信封。例如,如果我这样做:

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

然后基于WSDL / XSD将正确的XML发送到服务:

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

但是,当我尝试采用另一种方法并将XML反序列化为zeep CompoundValue对象时,它就会崩溃。

我认为即使使用zeep作为纯客户端,也存在某种的方式,因为SOAP响应中可能包含xsd:choice,所以我我只是想知道我对收到的请求进行反序列化的方式是否以某种方式关闭了?

0 个答案:

没有答案