[Major Edit based on experience since 1st post two days ago.]
I am building a Python SOAP/XML script using Suds, but am struggling to get the code to generate SOAP/X
I know this one was closed a long time ago, but after working on the problem personally I find the current answers lacking.
Using the sending method on the MessagePlugin won't work, because despite what the documentation heavily implies, you cannot actually change the message string from there. You can only retrieve the final result.
The marshalled method, as previously mentioned, is best for this, as it does allow you to affect the XML. I created the following plugin to fix the issue for myself:
class ClearEmpty(MessagePlugin):
def clear_empty_tags(self, tags):
for tag in tags:
children = tag.getChildren()[:]
if children:
self.clear_empty_tags(children)
if re.match(r'^<[^>]+?/>$', tag.plain()):
tag.parent.remove(tag)
def marshalled(self, context):
self.clear_empty_tags(context.envelope.getChildren()[:])
This will eliminate all empty tags. You can tailor this as needed if you only need to remove some empty tags from some place, but this recursive function works and (unless your XML schema is so unspeakably bad as to have nesting greater than the call depth of Python), shouldn't cause a problem. Note that we copy the lists here because using remove() mangles them as we're iterating and causes problems.
On an additional note, the regex that has been given by other answers is bad-- \s+<.*?/> used on will match , and not just as you might expect. This is because > is considered 'any character' by .. If you really need to use regex to fix this problem on rendered XML (Note: XML is a complex syntax that is better handled by a lexer), the correct one would be <[^>]*/>.
We use it here because I could not figure out the most correct way to ask the lexer 'is this a stand alone empty tag', other than to examine that tag's rendered output and regex against that. In such case I also added the ^ and $ tokens because rendering the tag in this method renders its entire context, and so that means that any blank tag underneath a particular tag would be matched. We just want the one particular tag to be matched so we can tell the API to remove it from the tree.
Finally, to help those searching for what might have prompted this question in the first place, the issue came up for me when I received an error message like this:
cvc-enumeration-valid: Value '' is not facet-valid with respect to enumeration
This is because the empty tag causes the server to interpret everything that would be under that tag as null values/empty strings.