python在SOAP请求中使用了错误的命名空间前缀

python在SOAP请求中使用了错误的命名空间前缀,python,soap,xsd,wsdl,suds,Python,Soap,Xsd,Wsdl,Suds,我使用python/suds实现一个客户机,在发送的SOAP头中,对于wsdl中由element ref=定义的特定类型的参数,我得到了错误的名称空间前缀 .wsdl正在引用一个数据类型.xsd文件,请参见下文。问题在于函数GetRecordAttributes及其类型为gbt:recordReferences的第一个参数 文件:browse2.wsdl <xsd:schema targetNamespace="http://www.grantadesign.com/10/10/Brows

我使用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>
对我的服务有用,但我不确定它是否会破坏其他东西。我更喜欢一个不改变肥皂水源代码的智能解决方案

谢谢

Alex

在发送XML之前编写一个修改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文档:

编组()
为插件提供在发送信封文档之前检查/修改信封文档的机会


您可以自己构建soap消息,并使用
SoapClient
发送消息:

sc = SoapClient(cli.service.XXXMethod.client,cli.service.XXXMethod.method)
sc.send(some_soap_doc)

我在使用sud访问BizTalk/IIS SOAP服务时遇到了完全相同的问题。 从WSDL中可以看出,当有一个“complexType”不是“targetNamespace”的一部分(它有自己的名称空间)时,它会发生,它有一个子类型也是complexType,但没有设置名称空间。在BizTalk中,这意味着子项应该与父项属于同一名称空间,但SUD似乎认为它应该是targetNamespace的一部分

源代码中的修复“正确地”解决了问题,但由于我希望能够升级,而无需每次使用另一个解决方案时都应用修复

我的解决方案是跳过肥皂水,只复制原始XML,将其用作模板并将值复制到其中。。。不漂亮,但至少简单。
在我看来,添加插件的解决方案同样是硬编码的,而且可能更难维护。

我更喜欢正则表达式:)


这显然是您堆栈中的一个bug;你说的“自动”是什么意思?例如,您是否愿意使用与您的工具兼容的不同但等效的XSD?从您所说的,如果您将ref替换为本地定义的元素,它将工作;对于所有XSD,生成的XML都是相同的。如果您考虑在飞行中进行更改,比如通过代理使用某种XSLT,那将是一种不同的方法。我可以推荐一种自动重构XSD的解决方案,用本地元素替换引用。我实际上尝试过移动和更改定义,但由于我不是专家,可能无法确定正确的语法,SUD总是在那里放置错误的名称空间。我也不想玩弄这些,因为它们是由外部供应商提供的,可能会发生变化。请参阅更新,了解我迄今为止找到的非最佳解决方案。这将适用于此特定情况。然而,由于在不同的树位置有很多这样的参数,手动固定它们并不是最优的。我希望对ref=的所有元素添加类似于前缀ns0的内容,虽然可以分析整个xml树,但我相信context.envelope不会保留
ref=
信息。另一个选项是扩展
DocumentPlugin
来修改WSDL/XSD对象,即
parsed()
方法(参见文档)将被调用两次(一个用于WSDL,另一个用于XSD)。太棒了,谢谢!!有趣的是,我必须在与初始示例完全相同的位置(结构上)更正信封。这里有模式吗?正如我所看到的,ns命名顺序(ns{x}和uri映射)是随机的,每个客户端实例都会发生变化。所以我添加了这个:
array_ns={v:k代表k,v在context.envelope.nsprefixes.items()中['http://mylonguri“]
是的,它成功了。在大多数情况下,正文的第二个子项将是方法定义。因此,您可以检查
context.envelope.getChild('Body').getChild('MyMethod')
对象,如果该请求确实针对您想要修复或不想要修复的方法,并且您可以有条件地访问其他字段。您的方法工作不太好:WebFault:Server-raised-fault:'无法确定请求的根元素。
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
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()])
sc = SoapClient(cli.service.XXXMethod.client,cli.service.XXXMethod.method)
sc.send(some_soap_doc)
import re

class EnvelopeFixer(MessagePlugin):
    def sending(self, context):
        # rimuovi i prefissi
        context.envelope = re.sub( 'ns[0-9]:', '', context.envelope )
        return context.envelope