使用suds在SOAP请求中多次发送相同类型

时间:2014-01-12 05:19:28

标签: python web-services soap wsdl suds

我正在使用suds python库编写SOAP客户端。我正在使用的服务不提供WSDL文件,所以我必须手动编写一个。我正在尝试发出一个请求,它接受可变数量的类型作为参数。

目前,我对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>

我可以使用单个标记参数使用以下代码调用它:

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

这会产生如下所示的请求:

<?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>

如何修改我的代码或WSDL以生成如下所示的请求?

<?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>

更新了尝试次数

我根据herry的答案尝试了新的方法。将他的建议直接插入wsdl会导致无法解析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抛出异常:Exception: prefix (ns6) not resolved

我尝试将elementcomplexType定义添加到我现有的类型名称空间:

  <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>

- 剪断 -

  <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"/>

这导致了以下请求:

<?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>

由于它更改了类型,因此从服务器返回了错误:

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

即使没有错误,我也无法让suds两次发送相同的标签。使用更新的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'])

我目前正在使用的完整wsdl可以找到here

2 个答案:

答案 0 :(得分:0)

根据您的评论我已经开始调查服务器端为什么不处理数组。我已经检查了SOAP.pm中的代码。我只专注于get_usertag方法,它处理或将处理一个或三个参数:

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

我认为您的目标是发出一个请求,该请求接受可变数量的类型作为参数。以前,我提议你在参数中使用一个复合类型(complexType),它有很多或零参数。

现在我查看它所说的SOAP::Lite documentation

  
      
  • 不支持多维,部分传输和稀疏阵列(但支持阵列阵列,以及任何其他阵列   数据结构,您可以添加自己的实现   SOAP ::数据)。
  •   
  • 对WSDL架构的有限支持。
  •   

因此,支持简单数组和SOAP :: Data。从技术上讲,它可以发送和处理数组(第二个限制对我来说是可怕的消息)。但我可以想象另一个原因(另一个客户端使用此方法...)不支持数组。另请查看differences between a SOAP::WSDL and SOAP::Lite

我在考虑如何发送许多参数的许多选项,但是每个选项都需要更改服务器端代码。也许你可以做一些hacks / magic来解决这个问题(使用一个包含所有参数并在服务器端拆分的参数),但我认为简单的SOAP::Data是更好的选择。

我没有改变WSDL结构。你可以使用我的波纹管代码。请在get_usertag方法中更改服务器端代码(之前我没有看到perl代码,我无法编写此代码)。该方法声明了两个字段$email@tags。请更改为$email$tag_list$tag_list包含@tags数组。


基于您的WSDL,我创建了简单的WSDL。它只包含两个操作,消息和只有一个模式。这个shema使用你的命名空间。所以它不需要指定另一个名称空间。这是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>

我认为你可以将这部分实现给你的WSDL。如果可能,请合并架构。这段代码有效,我在soapUi中测试过。我收到以下请求:

<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>

在这种情况下,客户端发送以下参数:

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

答案 1 :(得分:0)

 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

<强>编辑:

根据您当前的wsdl解决方案:

根据你的wsdl,你的tagRequest是,

<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"/>

现在,如果您将转到类型:ArrayOfString,

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

所以你会像这样形成你的请求,

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

这将生成这样的消息(我已经排除了命名空间,这不完全正确)

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

现在如果你想在上面的请求中将字符串替换为“tag”,请在wsdl中更改,

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

<强>更新

编辑你的wsdl解决方案:

这里我只更新了你的wsdl for get_Usertag操作,你可以按照这种方法相应地设计你的wsdl。保存以下wsdl并生成请求。

   <?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>

如果您将使用上面的wsdl并生成soap请求消息,它将是,

    <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>