1

I need to interact with a SOAP service and am having a lot of trouble doing so; would really appreciate any pointers on this. The original error message was:

org.apache.axis2.databinding.ADBException: Any type element type has not been given

After some research, it turns out that this is a disagreement between SUDS and the server has to how deal with

type="xsd:anyType"

on the element in question.

I've confirmed using SOAPUI and after advice that the problem can be fixed by taking these steps:

  1. Adding xsi:type="xsd:string" to each element which causes problems
  2. Adding xmlns:xsd="http://www.w3.org/2001/XMLSchema" to the SOAP Envelope

So, where SUDS currently does this:

<SOAP-ENV:Envelope ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<ns3:Body>
  <ns0:method>
     <parameter>
        <values>
           <table>
              <key>EMAIL_ADDRESS</key>
              <value>example@example.org</value>
           </table>
        </values>
     </parameter>
  </ns0:method>

it should instead produce this:

<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" ... xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">

  <ns3:Body>
  <ns0:method>
     ...
     <parameter>
        <values>
           <table>
              <key xsi:type="xsd:string">EMAIL_ADDRESS</key>
              <value xsi:type="xsd:string">example@example.org</value>
           </table>
        </values>
     </parameter>
  </ns0:method>

Is there a correct way to do this? I've seen suggestions of using ImportDoctor or MessagePlugins, but haven't really grokked how to achieve the desired effect.

somewhatoff
  • 971
  • 1
  • 11
  • 25

2 Answers2

10

The solution I found was to use a MessagePlugin to essentially manually fix up the XML just before sending. I'd hoped there was something more elegant, but at least this works:

class SoapFixer(MessagePlugin):

    def marshalled(self, context):
        # Alter the envelope so that the xsd namespace is allowed
        context.envelope.nsprefixes['xsd'] = 'http://www.w3.org/2001/XMLSchema'
        # Go through every node in the document and apply the fix function to patch up incompatible XML. 
        context.envelope.walk(self.fix_any_type_string)

    def fix_any_type_string(self, element):
        """Used as a filter function with walk in order to fix errors.
        If the element has a certain name, give it a xsi:type=xsd:string. Note that the nsprefix xsd must also
         be added in to make this work."""
        # Fix elements which have these names
        fix_names = ['elementnametofix', 'anotherelementname']
        if element.name in fix_names:
            element.attributes.append(Attribute('xsi:type', 'xsd:string'))
somewhatoff
  • 971
  • 1
  • 11
  • 25
  • 1
    This worked for me, however, I hope someone finds a better fix to the actual framework itself so we don't have to work around the problem. – trinth Jul 09 '12 at 22:01
  • 1
    hero! took me hours to figure this out – Willian Sep 20 '13 at 17:04
  • Hello, I am very interested in using a SoapFixer. But how do you implement the plugin, I have tried by calling client = Client(wsdl, plugins=['SoapFixer()'])but that don't seems to work – Khalil TABBAL Dec 10 '15 at 20:17
  • It's been a long time, but as I remember that should work. Do you get an error message? – somewhatoff Dec 10 '15 at 22:48
1

It's sad and hilarious, like a lot of things about this particular library, but here's the exact answer:

http://lists.fedoraproject.org/pipermail/suds/2011-September/001519.html

from the above:

soapenv = soapenv.encode('utf-8')
plugins.message.sending(envelope=soapenv)

becomes:

soapenv = soapenv.encode('utf-8')
ctx = plugins.message.sending(envelope=soapenv)
soapenv = ctx.envelope

basically, it's a bug in the implementation, and you can patch it yourself by editing the line that runs the plugin to actually return the plugin's results, but I'm not aware of a patched and updated version of SUDS that fixes this yet (tho I haven't looked closely for it).

Eli Albért
  • 686
  • 1
  • 6
  • 16
  • this didn't work for me... but not down voting just yet. I could have screwed up something. Anyone else get this solution to work? – FlipMcF Dec 03 '12 at 22:11
  • not sure what tell you - I use it in production for a project I'm on, so I'm pretty sure it works. Have you stepped thru and examined values of soapenv, ctx, and then soapenv again? have you validated that your plugins are doing what they are supposed to __and are returning a result__? – Eli Albért Dec 04 '12 at 17:16
  • I went a different direction - repairing my server-side code :) http://stackoverflow.com/questions/13593950/suds-write-request-missing-datatype/13736235#13736235 I did step through.. I can't quite remember, but I didn't see much happen to soapenv IIRC. I could be totally wrong tho. – FlipMcF Dec 06 '12 at 03:07
  • wow is all I can say. wish I'd had access to the server side of the equation with the particular api integration that dragged me thru this particular patch of mud. – Eli Albért Dec 06 '12 at 19:51
  • I'm not sure who is correct here. Should the client type all the request parameters, or should the server know the types of the request and not complain. I mean, if the WSDL says "send me an int for foo" why would we do 5 if the contract is already made? I think this is a lazy server, and in that case, the client must "le sigh" and give it what it wants. I think suds is working 'as designed' and the server is not. – FlipMcF Dec 14 '12 at 01:58
  • 1
    yup - in magento's case, which is what i was working on, pretty much everything is 'le sigh'. – Eli Albért Dec 14 '12 at 16:45