Create a string array parameter with zeep?

2019-06-26 20:34发布

问题:

I have a vendor-supplied webservice; the WSDL for a certain operation looks like:

<complexType name="ArrayOf_soapenc_string">
 <complexContent>
  <restriction base="soapenc:Array">
   <attribute ref="soapenc:arrayType" wsdl:arrayType="soapenc:string[]"/>
  </restriction>
 </complexContent>
</complexType>
...
<wsdl:message name="initExportDeviceRequest">
 <wsdl:part name="filter" type="soapenc:string"/>
 <wsdl:part name="options" type="impl:ArrayOf_soapenc_string"/>
</wsdl:message>
...
<wsdl:operation name="initExportDevice" parameterOrder="filter options">
 <wsdl:input message="impl:initExportDeviceRequest" name="initExportDeviceRequest"/>
 <wsdl:output message="impl:initExportDeviceResponse" name="initExportDeviceResponse"/>
</wsdl:operation>

Running python -mzeep ipam_export.wsdl on the WSDL yields this:

Global types:
 ns0:ArrayOf_soapenc_string(_value_1: string[], arrayType: xsd:string, offset: ns1:arrayCoordinate, id: xsd:ID, href: xsd:anyURI, _attr_1: {})
...
Service: ExportsService
 Port: Exports (Soap11Binding: {http://diamondip.com/netcontrol/ws/}ExportsSoapBinding)
  Operations:
   ...
   initExportDevice(filter: ns1:string, options: {_value_1: string[], arrayType: xsd:string, offset: ns1:arrayCoordinate, id: xsd:ID, href: xsd:anyURI, _attr_1: {}}) -> initExportDeviceReturn: ns2:WSContext

I am having difficulty in executing the initExportDevice call, specifically, the options parameter.


How to use a complex type from a WSDL with zeep in Python suggests to me that this should work:

filter_type=client.get_type('ns1:string')
filter=filter_type('addrType=4')
options_type=client.get_type('ns0:ArrayOf_soapenc_string')
options=options_type(['recurseContainerHierarchy'])
client.service.initExportDevice(filter, options)

but it raises an exception

Any element received object of type 'str', expected lxml.etree._Element or zeep.objects.string
See http://docs.python-zeep.org/en/master/datastructures.html#any-objects for more information

Any of

options_type=client.get_type('ns0:ArrayOf_soapenc_string')
options=options_type('recurseContainerHierarchy')
client.service.initExportDevice(filter, options)

or

factory = client.type_factory('ns0')
options=factory.ArrayOf_soapenc_string(['recurseContainerHierarchy'])
client.service.initExportDevice(filter=filter, options=options)

or

factory = client.type_factory('ns0')
options=factory.ArrayOf_soapenc_string('recurseContainerHierarchy')
client.service.initExportDevice(filter=filter, options=options)

or

factory = client.type_factory('ns0')
options=factory.ArrayOf_soapenc_string(_value_1=['recurseContainerHierarchy'])
client.service.initExportDevice(filter=filter, options=options)

all raise the same exception


options_type=client.get_type('ns0:ArrayOf_soapenc_string')
options=xsd.AnyObject(options_type, ['recurseContainerHierarchy'])
client.service.initExportDevice(filter, options)

yields

argument of type 'AnyObject' is not iterable

How do I construct this parameter?

回答1:

Ok so I had trouble with this using Zeep as well (works with suds easily), the problem is Zeep returns arrays as a function (from my testing) so you need to assign the function to an array, and then modify it. From your current code, it looks as if you are passing data directly to the function (which won't store it).

Using your example above, the below should retrieve the Array type and allow you to modify it as a valid data type.

emptyArrayPlaceholder = client.get_type('ns0:ArrayOf_soapenc_string')

Zeep then returns this type as a function, so first off you need to assign this function to a variable, such as:

options = emptyArrayPlaceholder()

If you were then to inspect options you will see it is a dict, with your list inside of it.

print (options)
{'soapenc': []}

You can then add items to the array easily with:

options['soapenc'].append('Foo')

You should then be able to submit your client with

client.service.initExportDevice(filter, options)

As options is now a valid Zeep data type.