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.
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!
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.