I use python/suds to implement a client and I get wrong namespace prefixes in the sent SOAP header for a spefic type of parameters defined by element ref=
in the wsdl.
The .wsdl is referencing a data types .xsd file, see below. The issue is with the function GetRecordAttributes
and its first argument of type gbt:recordReferences
.
File: browse2.wsdl
<xsd:schema targetNamespace="http://www.grantadesign.com/10/10/Browse" xmlns="http://www.grantadesign.com/10/10/Browse" xmlns:gbt="http://www.grantadesign.com/10/10/GrantaBaseTypes" elementFormDefault="qualified" attributeFormDefault="qualified">
<xsd:import schemaLocation="grantabasetypes2.xsd" namespace="http://www.grantadesign.com/10/10/GrantaBaseTypes"/>
<xsd:element name="GetRecordAttributes">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="gbt:recordReferences">
</xsd:element>
Referenced File : grantabasetypes2.xsd
<element name="recordReferences">
<complexType>
<sequence>
<element name="record" minOccurs="0" maxOccurs="unbounded" type="gbt:MIRecordReference"/>
</sequence>
</complexType>
</element>
SOAP Request sent by suds:
<SOAP-ENV:Envelope xmlns:ns0="http://www.grantadesign.com/10/10/GrantaBaseTypes" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://www.grantadesign.com/10/10/Browse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
<ns2:GetRecordAttributes>
<ns2:recordReferences>
<ns0:record>
</ns0:record>
</ns2:recordReferences>
</ns2:GetRecordAttributes>
</ns1:Body>
</SOAP-ENV:Envelope>
Problem : <ns2:recordReferences>
has wrong prefix, should be <ns0:recordReferences>
since it belongs to the namespace ...GrantaBaseTypes
defined in the .xsd.
This happens for all arguments defined by ref=
in the wsdl. How can this be automatically fixed?
Note: I checked that the "good" prefix is accepted by the service by manually sending the xml SOAP request via curl.
UPDATE
I meddled with SUDS source code and the following empirical fix forces all elements with ref=
attribute to assume the ref-ed namespace (previously, they take on the schema root namespace or whatever tns
is):
File: /suds/xsd/sxbase.py
class SchemaObject(object):
....
def namespace(self, prefix=None):
ns = self.schema.tns
#FIX BEGIN
if self.ref and self.ref in self.schema.elements.keys():
ns = self.ref
#FIX END
Works with my service, but I'm not sure if it'll break other things. I would prefer a smarter solution that does not change SUDS source code.
Thanks,
Alex
Write a Suds plugin to modify the XML before it is sent.
from suds.client import Client
from suds.plugin import MessagePlugin
class MyPlugin(MessagePlugin):
def marshalled(self, context):
#modify this line to reliably find the "recordReferences" element
context.envelope[1][0][0].setPrefix('ns0')
client = Client(WSDL_URL, plugins=[MyPlugin()])
Quoting Suds documentation:
marshalled()
Provides the plugin with the opportunity to inspect/modify the envelope Document before it is sent.