我使用python / suds来实现客户端,并且在发送的SOAP头中我得到错误的名称空间前缀,用于wsdl中由element ref=
定义的特定类型的参数。
.wsdl引用了一个数据类型.xsd文件,见下文。问题在于函数GetRecordAttributes
及其第一个类型为gbt:recordReferences
的参数。
文件:browse2.wsdl
<xsd:schema targetNamespace="http://www.grantadesign.com/10/10/Browse" xmlns="http://www.grantadesign.com/10/10/Browse" xmlns:gbt="http://www.grantadesign.com/10/10/GrantaBaseTypes" elementFormDefault="qualified" attributeFormDefault="qualified">
<xsd:import schemaLocation="grantabasetypes2.xsd" namespace="http://www.grantadesign.com/10/10/GrantaBaseTypes"/>
<xsd:element name="GetRecordAttributes">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="gbt:recordReferences">
</xsd:element>
参考文件:grantabasetypes2.xsd
<element name="recordReferences">
<complexType>
<sequence>
<element name="record" minOccurs="0" maxOccurs="unbounded" type="gbt:MIRecordReference"/>
</sequence>
</complexType>
</element>
suds发送的SOAP请求:
<SOAP-ENV:Envelope xmlns:ns0="http://www.grantadesign.com/10/10/GrantaBaseTypes" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://www.grantadesign.com/10/10/Browse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns1:Body>
<ns2:GetRecordAttributes>
<ns2:recordReferences>
<ns0:record>
</ns0:record>
</ns2:recordReferences>
</ns2:GetRecordAttributes>
</ns1:Body>
</SOAP-ENV:Envelope>
问题:<ns2:recordReferences>
前缀错误,应为<ns0:recordReferences>
,因为它属于.xsd中定义的名称空间...GrantaBaseTypes
。
这适用于wsdl中ref=
定义的所有参数。如何自动修复?
注意:我通过curl手动发送xml SOAP请求,检查了服务是否接受了“good”前缀。
更新
我干预了SUDS源代码,并且以下经验修正强制所有具有ref=
属性的元素假定引用的命名空间(以前,它们采用模式根命名空间或tns
为止) :
文件:/suds/xsd/sxbase.py
class SchemaObject(object):
....
def namespace(self, prefix=None):
ns = self.schema.tns
#FIX BEGIN
if self.ref and self.ref in self.schema.elements.keys():
ns = self.ref
#FIX END
使用我的服务,但我不确定它是否会破坏其他内容。我更喜欢更智能的解决方案,它不会改变SUDS源代码。
谢谢,
亚历
答案 0 :(得分:8)
编写Suds plugin以在发送之前修改XML。
from suds.client import Client
from suds.plugin import MessagePlugin
class MyPlugin(MessagePlugin):
def marshalled(self, context):
#modify this line to reliably find the "recordReferences" element
context.envelope[1][0][0].setPrefix('ns0')
client = Client(WSDL_URL, plugins=[MyPlugin()])
引用Suds文档:
<强>编组()强>
为插件提供在发送之前检查/修改信封文档的机会。
答案 1 :(得分:2)
使用suds访问BizTalk / IIS SOAP服务时,我遇到了完全相同的问题。 从我从WSDL中可以看出,当有一个“complexType”不属于“targetNamespace”(它有自己的一部分)时,就会发生这种情况,它有一个子类,它也是一个complexType,但没有设置名称空间。在BizTalk中,这意味着子项应该与父项属于同一名称空间,但是Suds似乎认为它应该是targetNamespace的一部分....
源代码中的修复解决了“正确”的问题,但是因为我希望每次去另一个解决方案时能够升级而不应用修复....
我的解决方案是跳过Suds并只复制原始XML,将其用作模板并将值复制到其中...不漂亮,但至少简单。 在我看来,添加插件的解决方案同样硬编码,甚至可能更难维护。
答案 2 :(得分:1)
您可以自己构建soap消息并使用SoapClient
发送消息:
sc = SoapClient(cli.service.XXXMethod.client,cli.service.XXXMethod.method)
sc.send(some_soap_doc)
答案 3 :(得分:-1)
我更喜欢正则表达式:)
import re
class EnvelopeFixer(MessagePlugin):
def sending(self, context):
# rimuovi i prefissi
context.envelope = re.sub( 'ns[0-9]:', '', context.envelope )
return context.envelope