Python zeep如何在单次SOAP请求中传递多个同名字段值
问题背景
首先为我的英语水平不佳致歉。我在使用zeep客户端传递多值参数时遇到了问题,接口对应方法的WSDL结构定义如下:
<s:element name="GetSomething"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="id" type="s:string"/> </s:sequence> </s:complexType> </s:element>
当我仅需要查询单个值的结果时,调用不存在问题,使用的代码如下:
WSDL = 'example.asmx?WSDL' session = Session() transport = Transport(session=session) client = Client(wsdl=WSDL, transport=transport) res = client.service.GetCompanyExtendedReport(id='1') print(res)
但当我需要查询多个值的结果时,目标请求XML格式如下(包含多个id节点,传入值为1-5):
<s11:Envelope xmlns:s11='http://schemas.xmlsoap.org/soap/envelope/'> <s11:Body> <ns1:GetSomething xmlns:ns1='http://examplesoapapi.ru/idk'> <ns1:id>1</ns1:id> <ns1:id>2</ns1:id> <ns1:id>3</ns1:id> <ns1:id>4</ns1:id> <ns1:id>5</ns1:id> </ns1:GetStateContractReport> </s11:Body> </s11:Envelope>
我不清楚如何通过zeep构造这类请求,尝试写多个同名id参数的写法不符合Python语法,也知道可以通过循环多次发起单id请求实现需求,但这并不是我想要的解决方案。
解决方案
Python本身不支持给函数传递多个同名关键字参数,所以你尝试的id='1', id='2'写法本身就会触发语法错误,无法运行。针对需要生成多个并列同名字段的SOAP请求,zeep提供了两种可直接使用的实现方案,不需要循环发起多次请求:
方法1:直接传入列表值(优先使用)
zeep默认会将传入的可迭代对象序列化为多个独立的同名XML节点,你只需要把id参数的取值替换为待传递的字符串列表即可。
注意你提供的WSDL中id字段被标注为maxOccurs="1",默认严格模式下zeep会对参数做schema校验,拦截列表传值,初始化Client时加上strict=False关闭校验即可:
WSDL = 'example.asmx?WSDL' session = Session() transport = Transport(session=session) client = Client(wsdl=WSDL, transport=transport, strict=False) # 直接传入id值的列表 res = client.service.GetCompanyExtendedReport(id=['1', '2', '3', '4', '5']) print(res)
方法2:手动构造XML节点
如果方法1生成的XML结构和服务端要求有偏差,可以使用zeep内置的xsd模块手动构造每个id节点,完全控制最终输出的请求结构:
from zeep import xsd WSDL = 'example.asmx?WSDL' session = Session() transport = Transport(session=session) client = Client(wsdl=WSDL, transport=transport, strict=False) # 逐个构造id节点 id_nodes = [xsd.Element('id', xsd.String(), value) for value in ['1','2','3','4','5']] res = client.service.GetCompanyExtendedReport(id=id_nodes) print(res)
两种方式最终生成的请求体都会和你给出的目标XML结构完全一致,在GetSomething节点下并列生成5个独立的id节点,满足传参要求。
内容的提问来源于stack exchange,提问作者Pavel Chelnokov
相关产品推荐
相关产品推荐

