How do I form a suds request in Python using a WSDL that uses the "any" type?

44 views Asked by At

Note, this is not a duplicate of How to pass "Any" type parameter in SOAP request using zeep in Python.

This question relates to using suds, the other to zeep, and the problem and issues encountered are different.

I have a WSDL that uses the "any" type for the core element (Element) in all SOAP operations. Note that I have trimmed this down as it's quite big.

<?xml version="1.0" encoding="utf-8"?>
<definitions targetNamespace="urn:xtk:queryDef" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="urn:xtk:queryDef" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
  <types>
    <s:schema elementFormDefault="qualified" targetNamespace="urn:xtk:queryDef">
        <s:complexType name="Element">
            <s:sequence>
                <s:any processContents="lax"/>
            </s:sequence>
        </s:complexType>
      <s:element name="ExecuteQuery">
        <s:complexType>
          <s:sequence>
            <s:element maxOccurs="1" minOccurs="1" name="sessiontoken" type="s:string" />
            <s:element maxOccurs="1" minOccurs="1" name="entity" type="tns:Element" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:element name="ExecuteQueryResponse">
        <s:complexType>
          <s:sequence>
            <s:element maxOccurs="1" minOccurs="1" name="pdomOutput" type="tns:Element" />
          </s:sequence>
        </s:complexType>
      </s:element>
    </s:schema>
  </types>
  <message name="ExecuteQueryIn">
    <part element="tns:ExecuteQuery" name="parameters" />
  </message>
  <message name="ExecuteQueryOut">
    <part element="tns:ExecuteQueryResponse" name="parameters" />
  </message>
  <portType name="queryDefMethodsSoap">
    <operation name="ExecuteQuery">
      <input message="tns:ExecuteQueryIn" />
      <output message="tns:ExecuteQueryOut" />
    </operation>
  </portType>
<binding name="queryDefMethodsSoap" type="tns:queryDefMethodsSoap">
  <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
  <operation name="ExecuteQuery">
    <soap:operation soapAction="xtk:queryDef#ExecuteQuery" style="document" />
    <input>
      <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal" />
    </input>
    <output>
      <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="literal" />
    </output>
  </operation>
    </binding>
    <service name="XtkQueryDef">
      <port binding="tns:queryDefMethodsSoap" name="queryDefMethodsSoap">
        <soap:address location="https://xxxxxxxxxxxxxx/nl/jsp/soaprouter.jsp" />
      </port>
    </service>
</definitions>

I cannot seem to form the correct parameters to call the ExecuteQuery service using suds-jurko in Python 3.

I want to send the equivalent of this payload:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:xtk:queryDef">
   <soapenv:Header/>
   <soapenv:Body>
      <urn:ExecuteQuery>
         <urn:sessiontoken>xxxxxxx</urn:sessiontoken>
         <urn:entity>
            <queryDef schema="nms:recipient" operation="select">
              <select>
                <node expr="@email"/>
                <node expr="@lastName+'-'+@firstName"/>
                <node expr="Year(@birthDate)"/>
              </select>
              <orderBy>
                <node expr="@birthDate" sortDesc="true"/>
              </orderBy>
        </queryDef>
         </urn:entity>
      </urn:ExecuteQuery>
   </soapenv:Body>
</soapenv:Envelope>

So I have this code:

import urllib.parse
import urllib.request
from suds.client import Client
import os


# Executes a query and returns the result set
def execute_query():
    # Load the WSDL locally - not authorised to get from server
    wsdl_url = urllib.parse.urljoin('file:', urllib.request.pathname2url(os.path.abspath("querydef_dev.wsdl")))
    session_token = "xxxxxxxxxxx"

    # Init the client
    query_client = Client(wsdl_url)

    # Construct the query def
    query_def = {
            "queryDef": {
                "select": {
                    "node": [
                        {
                            "_expr": "@email"
                        },
                        {
                            "_expr": "@lastName+'-'+@firstName"
                        },
                        {
                            "_expr": "Year(@birthDate)"
                        }
                    ]
                },
                "orderBy": {
                    "node": {
                        "_expr": "@birthDate",
                        "_sortDesc": "true"
                    }
                },
                "_schema": "nms:recipient",
                "_operation": "select"
            }
        }

    try:
        response = query_client.service.ExecuteQuery(sessiontoken=session_token, entity=query_def)
    except:
        print("Failed!")
    print(query_client.last_sent())


if __name__ == '__main__':
    execute_query()


However, that results in an incorrect XML payload that messes with the attributes:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:xtk:queryDef">
   <SOAP-ENV:Header/>
   <ns0:Body>
      <ns1:ExecuteQuery>
         <ns1:sessiontoken>xxxxxxxxxxx</ns1:sessiontoken>
         <ns1:entity>
            <ns1:queryDef>
               <ns1:select>
                  <ns1:node>
                     <ns1:_expr>@email</ns1:_expr>
                  </ns1:node>
                  <ns1:node>
                     <ns1:_expr>@lastName+&apos;-&apos;+@firstName</ns1:_expr>
                  </ns1:node>
                  <ns1:node>
                     <ns1:_expr>Year(@birthDate)</ns1:_expr>
                  </ns1:node>
               </ns1:select>
               <ns1:orderBy>
                  <ns1:node>
                     <ns1:_expr>@birthDate</ns1:_expr>
                     <ns1:_sortDesc>true</ns1:_sortDesc>
                  </ns1:node>
               </ns1:orderBy>
               <ns1:_schema>nms:recipient</ns1:_schema>
               <ns1:_operation>select</ns1:_operation>
            </ns1:queryDef>
         </ns1:entity>
      </ns1:ExecuteQuery>
   </ns0:Body>
</SOAP-ENV:Envelope>

There is no complexType definition of "Element" that I can use with client.factory.create, so I'm stuck as to how I form the payload I need.

0

There are 0 answers