Question

I have a SOAP API and I'm trying to call a method via suds (python):

DoSomething(ns1:DoSomethingRequest Input, )

DoSomethingRequest looks something like this:

    (DoSomethingRequest){
   Person = 
      (Person){
         Name = "Joe"
         Age = 32
      }
   ActionOne = None
   ActionTwo = None
   ActionThree = None
 }

In the type definition, the action params are all optional. To invoke a specific action, you set DoSomethingRequest.ActionOne = [an instance of ActionOneRequest]. This is all fine (I can perform ActionOne), except that I'm trying to call ActionThree, and ActionThreeRequest is an empty complex element. When I set DoSomethingRequest.ActionThree = ActionThreeRequest, a print on DoSomethingRequest gives:

    (DoSomethingRequest){
   Person = 
      (Person){
         Name = "Joe"
         Age = 32
      }
   ActionOne = None
   ActionTwo = None
   ActionThree = <empty>
 }

and the XML sent to the server excludes ActionThree. If I intercept the code with pdb and add an empty element <ActionThree></ActionThree>, it works.

Looking at the code, for suds:

class ObjectAppender(Appender):
    """
    An L{Object} appender.
    """

    def append(self, parent, content):
        object = content.value
        if self.optional(content) and footprint(object) == 0:
            return
        child = self.node(content)
        parent.append(child)
        for item in object:
            cont = Content(tag=item[0], value=item[1])
            Appender.append(self, child, cont)

and

def footprint(sobject):
    """
    Get the I{virtual footprint} of the object.
    This is really a count of the attributes in the branch with a significant value.
    @param sobject: A suds object.
    @type sobject: L{Object}
    @return: The branch footprint.
    @rtype: int
    """
    n = 0
    for a in sobject.__keylist__:
        v = getattr(sobject, a)
        if v is None: continue
        if isinstance(v, Object):
            n += footprint(v)
            continue
        if hasattr(v, '__len__'):
            if len(v): n += 1
            continue
        n +=1
    return n

I don't use SOAP often, so I assume I'm either using the API incorrectly, or am using suds incorrectly. Or, maybe the service API is nonstandard.

Do you know why there's a problem and how best to solve it?

Strangely, the opposite question is on SO: Suds generates empty elements; how to remove them? Unfortunately, it's a lot easier to remove empty elements than to figure out which elements were removed and re-add them.

Thanks!

Was it helpful?

Solution

After reading the specs and talking to experts, I didn't see anything that indicated that it's okay for a SOAP library to strip out optional, empty elements.

There's a patched version of suds on github.

OTHER TIPS

In case someone else comes across this question, and doesn't find an answer. A similar situation happened to me. I was attempting to send the following body in a SOAP request,

<ns0:list><ns0:filter xsi:type="ns0:UserFilter"/></ns0:list>

My first attempt, I created the element using the suds.client.factory and send that with nothing configured. That resulted in the following body,

<ns0:list><filter/></ns0:list>

I next tried creating an Element by hand and setting the type attribute manually. That got me the same envelope body.

After digging through the source code, I figured out that the SoapClient.send() method was stripping my attribute in the sax.Document.plain() method.

Looking at the code, I figured out that I could set the prettyxml=True option on the suds client and that wouldn't strip the attribute.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top