Question

I am writing a SOAP client using the suds python library. The service that I am using does not provide a WSDL file, so I have to write one by hand. I am trying to make a request which accepts a variable number of types as parameters.

Currently, I have the following for the method in the WSDL:

  <wsdl:message name="get_usertagRequest">
    <wsdl:part name="email" type="xsd:string"
               minOccurs="1" maxOccurs="1"/>
    <wsdl:part name="tag" type="xsd:string"
               minOccurs="0" maxOccurs="unbounded"/>
  </wsdl:message>

I am able to call this with a single tag parameter with the following code:

client = Client(url)
service = client.service['debian.org']
foo = service.get_usertag('someone@debian.org', tag='malloc')

This produces a request that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns3="urn:Debbugs/SOAP" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="urn:Debbugs/SOAP/TYPES" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <SOAP-ENV:Header/>
   <ns0:Body>
      <ns3:get_usertag>
         <email xsi:type="ns1:string">someone@debian.org</email>
         <tag xsi:type="ns4:string">malloc</tag>
      </ns3:get_usertag>
   </ns0:Body>
</SOAP-ENV:Envelope>

How can I modify my code or WSDL to produce a request that looks like the following?

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns3="urn:Debbugs/SOAP" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="urn:Debbugs/SOAP/TYPES" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <SOAP-ENV:Header/>
   <ns0:Body>
      <ns3:get_usertag>
         <email xsi:type="ns1:string">someone@debian.org</email>
         <tag xsi:type="ns4:string">malloc</tag>
         <tag xsi:type="ns4:string">anothertag</tag>
      </ns3:get_usertag>
   </ns0:Body>
</SOAP-ENV:Envelope>

Updated Attempts

I tried new approaches based on herry's answer below. Inserting his suggestion directly into the wsdl results in a failure to parse the wsdl:

<xsd:schema targetNamespace="ns6:your_namespace" attributeFormDefault="qualified" elementFormDefault="qualified">
    <xsd:element name="tag_list">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element maxOccurs="unbounded" minOccurs="0" name="tag" nillable="true" type="ns4:string" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

Suds throws the exception: Exception: prefix (ns6) not resolved

I tried adding the element and complexType definition to my existing types namespace:

  <wsdl:types>
    <schema targetNamespace="urn:Debbugs/SOAP/TYPES"
        xmlns="http://www.w3.org/2001/XMLSchema">
      <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
       <element name="tag_list">
         <complexType>
           <sequence>
             <element maxOccurs="unbounded" minOccurs="0" name="tag" nillable="true" type="xsd:string" />
           </sequence>
         </complexType>
       </element>

--snip--

  <wsdl:message name="get_usertagRequest">
    <wsdl:part name="email" type="xsd:string"
               minOccurs="1" maxOccurs="1"/>
    <wsdl:part name="tag" element="types:tag_list"
               minOccurs="0" maxOccurs="unbounded"/>

This resulted in the following request:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns3="urn:Debbugs/SOAP" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns4="urn:Debbugs/SOAP/TYPES" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <SOAP-ENV:Header/>
   <ns0:Body>
      <ns3:get_usertag>
         <email xsi:type="ns1:string">someone@debian.org</email>
         <tag_list xsi:type="ns4:tag_list">malloc</tag_list>
      </ns3:get_usertag>
   </ns0:Body>
</SOAP-ENV:Envelope>

Since it changed the type, a fault was returned from the server:

suds.WebFault: Server raised fault: 'Application failed during request deserialization: Unrecognized type '{urn:Debbugs/SOAP/TYPES}tag_list'

Even without the fault, I am unable to get suds to send the same tag twice. With the updated wsdl:

# only malloc is sent in the request
foo = service.get_usertag('someone@debian.org', 'malloc', 'foo')

# results in suds.TypeNotFound: Type not found: 'tag_list'
foo = service.get_usertag('someone@debian.org', ['malloc', 'foo'])

The full wsdl that I am currently working with can be found here.

Was it helpful?

Solution

Based on your comment I've started to investigate why server side doesn't handle arrays. I've checked code in your SOAP.pm. I've focused only to get_usertag method, which it handle or will be handle one or three parameters:

 my %ut = get_usertag('don@donarmstrong.com','this-bug-sucks','eat-this-bug');
 my %ut = get_usertag('don@donarmstrong.com');

I think your goal is make a request which accepts a variable number of types as parameters. Previously, I offered to you use one compound type (complexType) in parameter, which it has many or zero parameters.

Now I check SOAP::Lite documentation which it say:

  • No support for multidimensional, partially transmitted and sparse arrays (however arrays of arrays are supported, as well as any other data structures, and you can add your own implementation with SOAP::Data).
  • Limited support for WSDL schema.

So, the simple array and SOAP::Data are supported. Technically it is possible to send and handle array (second limitation is awful news for me). But I can imagine another reason (another client use this method...) for not supporting array. Please check also differences between a SOAP::WSDL and SOAP::Lite.

I thinking about many options how to send many parameters, but for each options are need to change server-side code. Perhaps can you do some hacks/magic to resolve this issue (use one parameter which contained all parameters and splited in server-side), but I think simple SOAP::Data is better option.

I doesn't change WSDL structure. You can use my bellow code. Please change server-side code in get_usertag method (I haven't seen perl code before, I cannot wrote this code). That method declare two fields $email and @tags. Please change to $email and $tag_list. The $tag_list containts @tags arrays.


Based on your WSDL I created simply WSDL. It containt only two operation, message and only one schema. This shema use your namespace. So it doesn't need to specify another namespace. Here is relevant part from WSDL:

<wsdl:types>

    <xsd:schema  targetNamespace="urn:Debbugs/SOAP" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="qualified">

    <xsd:element name="get_usertagResponse" >
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="msg" minOccurs="0" maxOccurs="unbounded"  type="xsd:string" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
<!--The new Tag_lis element-->
      <xsd:element name="Tag_list" >
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="tag" minOccurs="0" maxOccurs="unbounded"  type="xsd:string" />
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>

  </wsdl:types>
<!--get_usertagRequest use Tag_lis element-->
  <wsdl:message name="get_usertagRequest">
    <wsdl:part name="email" type="xsd:string"/>
    <wsdl:part name="tag_list" element="tns:Tag_list"/>
  </wsdl:message>

  <wsdl:message name="get_usertagResponse">
    <wsdl:part name="msg" type="tns:get_usertagResponse"/>
  </wsdl:message>

I think you can implement this part to your WSDL. If it possible, please merge schemas. This code works, I tested it in soapUi. I get following request:

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="urn:Debbugs/SOAP">
   <soapenv:Header/>
   <soapenv:Body>
      <soap:get_usertag soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <email xsi:type="xsd:string">?</email>
         <soap:Tag_list>
            <!--Zero or more repetitions:-->
            <tag xsi:type="xsd:string">?</tag>
         </soap:Tag_list>
      </soap:get_usertag>
   </soapenv:Body>
</soapenv:Envelope>

In this case client send these parameters:

client = Client(url)
service = client.service['debian.org']
foo = service.get_usertag('someone@debian.org', tag_list=['malloc', 'amother'])

OTHER TIPS

 client = Client(url)
 //forming request
arrayoftagList = client.factory.create('ArrayOfString')
arrayoftagList.tag_list = [malloc,anothertag]
print client.service.get_usertag(someone@debian.org, arrayoftagList).string

Edited:

Solution as per your current wsdl:

As per your wsdl, your tagRequest is,

<wsdl:message name="get_usertagRequest">
<wsdl:part name="email" type="xsd:string"
           minOccurs="1" maxOccurs="1"/>
<!-- <wsdl:part name="tag" type="xsd:string" -->
<!--            minOccurs="0" maxOccurs="unbounded"/> -->
<wsdl:part name="tag_list" type="types:ArrayOfString"
           minOccurs="0" maxOccurs="unbounded"/>

Now if you will go to types:ArrayOfString,

<complexType name="ArrayOfString">
     <sequence>
       <element minOccurs="0" maxOccurs="unbounded"
                name="string" nillable="true"
                type="xsd:string"/>
     </sequence>
   </complexType>

So you will form your request like this,

 client = Client(url)
 //forming request
arrayoftagList = client.factory.create('ArrayOfString')
arrayoftagList.string = [malloc,anothertag]
print client.service.get_usertag(someone@debian.org, arrayoftagList).string

This will generate message like this (i have excluded namespace, it's not exact)

  <get_usertag>
     <email>someone@debian.org</email>
     <string>malloc</string>
     <string>anothertag</string>
  </get_usertag>

now if you want to replace string as "tag" in above request, change here in your wsdl,

   <complexType name="ArrayOfString">
     <sequence>
       <element minOccurs="0" maxOccurs="unbounded"
                name="tag" nillable="true"
                type="xsd:string"/>
     </sequence>
   </complexType>

Updated:

Solution by editing your wsdl:

here i have updated your wsdl for get_Usertag operation only, you can follow this approach to design your wsdl accordingly. save following wsdl and generate request.

   <?xml version="1.0" encoding="UTF-8"?>


<wsdl:definitions
    name="Debbugs/SOAP"
    targetNamespace="urn:Debbugs/SOAP"
    xmlns:tns="urn:Debbugs/SOAP"
    xmlns:types="urn:Debbugs/SOAP/TYPES"
    xmlns:apachens="http://xml.apache.org/xml-soap"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
    xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
    soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

  <wsdl:types>
    <schema targetNamespace="urn:Debbugs/SOAP/TYPES"
        xmlns="http://www.w3.org/2001/XMLSchema">
      <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>

       <element name="UsertagRequest">
           <complexType>
            <sequence>
           <element name="email" type="xsd:string"
                    minOccurs="1" MaxOccurs="1"/>
           <element name="tag" type="xsd:string"
                    minOccurs="0" MaxOccurs="unbounded"/>
         </sequence>
       </complexType>
       </element>
    </schema>
  </wsdl:types>

  <wsdl:message name="get_usertagRequest">
    <wsdl:part name = "parameters" element="types:UsertagRequest"/>
  </wsdl:message>
  <wsdl:message name="get_usertagResponse">
    <wsdl:part name="s-gensym3" type="xsd:string"/>
  </wsdl:message>


  <wsdl:portType name="Debbugs/SOAP">
    <wsdl:operation name="get_usertag">
      <wsdl:input message="tns:get_usertagRequest">
        <soap:body
        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        namespace="urn:Debbugs/SOAP"
        use="encoded"/>
      </wsdl:input>
      <wsdl:output message="tns:get_usertagResponse">
        <soap:body
        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        namespace="urn:Debbugs/SOAP"
        use="encoded"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="Debbugs/SOAP/BINDING" type="tns:Debbugs/SOAP">
    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="get_usertag">
      <wsdl:input message="tns:get_usertagRequest">
        <soap:body
        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        namespace="urn:Debbugs/SOAP"
        use="encoded"/>
      </wsdl:input>
      <wsdl:output message="tns:get_usertagResponse">
        <soap:body
        encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        namespace="urn:Debbugs/SOAP"
        use="encoded"/>
      </wsdl:output>
    </wsdl:operation>

  </wsdl:binding>

  <wsdl:service name="Debbugs/SOAP/SERVICE">
    <wsdl:port binding="tns:Debbugs/SOAP/BINDING" name="gnu.org">
      <wsdlsoap:address location="http://debbugs.gnu.org/cgi/soap.cgi"/>
    </wsdl:port>
    <wsdl:port binding="tns:Debbugs/SOAP/BINDING" name="debian.org">
      <wsdlsoap:address location="http://bugs.debian.org/cgi-bin/soap.cgi"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

If you will use above wsdl and generate soap request message, it would be look like,

    <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="urn:Debbugs/SOAP" xmlns:typ="urn:Debbugs/SOAP/TYPES">
   <soapenv:Header/>
   <soapenv:Body>
      <soap:get_usertag soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <typ:UsertagRequest>
            <email xsi:type="xsd:string">?</email>
            <!--Optional:-->
            <tag xsi:type="xsd:string">?</tag>
         </typ:UsertagRequest>
      </soap:get_usertag>
   </soapenv:Body>
</soapenv:Envelope>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top