使用SUDS时添加xsi:type和信封命名空间


问题内容

我需要与SOAP服务进行交互,但是这样做很麻烦;非常感谢对此提出任何建议。原始错误消息是:

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

经过一些研究,结果表明这是SUDS之间的分歧,服务器必须如何处理

type="xsd:anyType"

在有问题的元素上。

我已经确认使用SOAPUI,并在提出建议后可以采取以下步骤来解决此问题:

  1. 将xsi:type =“ xsd:string”添加到每个会导致问题的元素
  2. 将xmlns:xsd =“ http://www.w3.org/2001/XMLSchema”添加到SOAP信封

因此,SUDS当前在何处执行此操作:

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

它应改为产生以下内容:

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

有正确的方法吗?我已经看到了使用ImportDoctor或MessagePlugins的建议,但是还没有真正了解如何实现所需的效果。


问题答案:

我发现的解决方案是使用MessagePlugin在发送前实质上手动修复XML。我希望有一些更优雅的东西,但这至少可以起作用:

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'))