Search code examples
pythonsoapwsdlsoappy

How do I pass a list parameter as multiple link-named elements instead of as an array in SOAPpy?


I am trying to pass multiple instances of an element to a web servile that has the following wsdl

 <complexType name="OAMCommand">
   <sequence>
     <element name="m-strName" type="xsd:string" minOccurs="1" maxOccurs="1"/>
     <element name="m-argVector" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
   </sequence>
  </complexType>

This is my code in python for the client

  oamCmdStruct = SOAPpy.structType()
  oamCmdStruct._addItem('m-strName','set-log-level')
  oamCmdStruct._addItem('m-argVector', logLevel)
  oamCmdStruct._addItem('m-argVector', loggerName)
  self.serverConnection.executeCommand({'in-cmd':oamCmdStruct}

Here is the output I get from SOAPpy that gets rejected by the web service, it creates an array for the 2 m-argVector elements.

<xsd:in-cmd>
  <m-strName xsi:type="xsd:string">set-log-level</m-strName>
  <m-argVector SOAP-ENC:arrayType="xsd:string[2]" xsi:type="SOAP-ENC:Array">
    <item>WARN_LOG_LEVEL</item>
    <item>netborder</item>
  </m-argVector>
</xsd:in-cmd>

Here is the output that another client sends that works. No array, just two elements that have the same name.

   <SoapOAM:executeCommand>
      <in-cmd>
        <m-strName>set-log-level</m-strName>
        <m-argVector>ERROR_LOG_LEVEL</m-argVector>
        <m-argVector>netborder.media</m-argVector>
      </in-cmd>
    </SoapOAM:executeCommand>

How can I modify my SOAPpy code to generate the xml output like the one above ?

EDIT: I tried the following code in python

 oamCmdStruct = SOAPpy.structType( data = {"m-strName":"set-log-level",
                                              "m-argVector": logLevel,
                                              "m-argVector": loggerName})

But this is what the XML output from SOAPpy looked like

<xsd:in-cmd>
  <m-strName xsi:type="xsd:string">set-log-level</m-strName>
  <m-argVector xsi:type="xsd:string">loggerName</m-argVector>
</xsd:in-cmd>

The value for logLevel gets overwritten by loggerName instead of creating 2 entries...


Solution

  • After trying a few different librairies (suds, soaplib), I finally dug into the SOAPpy code.

    In order to remove the arrays from my SOAP requests, I modified the dump_list() function in the SOAPBuilder class of the SOAPpy library.

    # COMMENT: We dont want arrays in SOAP-XML so I commented out the following lines
    # if typed:
    #    self.out.append(
    #        '<%s %sarrayType="%s[%d]" %stype="%sArray"%s%s%s%s%s%s>\n' %
    #        (tag, ens, t, len(data), ins, ens, ndecl, edecl, idecl,
    #         self.genroot(ns_map), id, a))
    
    #if typed:
    #    try: elemsname = obj._elemsname
    #    except: elemsname = "item"
    #else:
    elemsname = tag
    
    for i in data:
        self.dump(i, elemsname, not same_type, ns_map)
    
    #if typed: self.out.append('</%s>\n' % tag)
    

    This change gives me the following output for my SOAP XML request.

    <SOAP-ENV:Body>
    <ns1:executeCommand xmlns:ns1="urn:SoapOAM">
    <xsd:in-cmd>
    <m-strName xsi:type="xsd:string">set-log-level</m-strName>
    <m-argVector>ERROR_LOG_LEVEL</m-argVector>
    <m-argVector>netborder</m-argVector>
    </xsd:in-cmd>
    </ns1:executeCommand>
    </SOAP-ENV:Body>