简体   繁体   English

python suds在SOAP请求中错误的名称空间前缀

[英]python suds wrong namespace prefix in SOAP request

I use python/suds to implement a client and I get wrong namespace prefixes in the sent SOAP header for a spefic type of parameters defined by element ref= in the wsdl. 我使用python / suds来实现一个客户端,我在发送的SOAP头中得到错误的名称空间前缀,用于wsdl中由element ref=定义的特定参数类型。

The .wsdl is referencing a data types .xsd file, see below. .wsdl引用了数据类型.xsd文件,如下所示。 The issue is with the function GetRecordAttributes and its first argument of type gbt:recordReferences . 问题在于GetRecordAttributes函数及其第一个类型为gbt:recordReferences参数。

File: browse2.wsdl 文件: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>

Referenced File : grantabasetypes2.xsd 引用文件:grantabasetypes2.xsd

<element name="recordReferences">
  <complexType>
    <sequence>
      <element name="record" minOccurs="0" maxOccurs="unbounded" type="gbt:MIRecordReference"/>
    </sequence>
  </complexType>
</element>

SOAP Request sent by suds: 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>

Problem : <ns2:recordReferences> has wrong prefix, should be <ns0:recordReferences> since it belongs to the namespace ...GrantaBaseTypes defined in the .xsd. 问题<ns2:recordReferences>有错误的前缀,应该是<ns0:recordReferences>因为它属于命名空间...GrantaBaseTypes定义的...GrantaBaseTypes

This happens for all arguments defined by ref= in the wsdl. 对于wsdl中ref=定义的所有参数,都会发生这种情况。 How can this be automatically fixed? 如何自动修复?

Note: I checked that the "good" prefix is accepted by the service by manually sending the xml SOAP request via curl. 注意:我通过curl手动发送xml SOAP请求,检查了服务是否接受了“good”前缀。

UPDATE UPDATE

I meddled with SUDS source code and the following empirical fix forces all elements with ref= attribute to assume the ref-ed namespace (previously, they take on the schema root namespace or whatever tns is): 我使用SUDS源代码进行干预,并且以下经验修复强制所有带有ref= attribute的元素都假定引用的命名空间(以前,它们采用模式根命名空间或任何tns ):

File: /suds/xsd/sxbase.py 文件:/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

Works with my service, but I'm not sure if it'll break other things. 适用于我的服务,但我不确定它是否会破坏其他东西。 I would prefer a smarter solution that does not change SUDS source code. 我更喜欢更智能的解决方案,它不会改变SUDS源代码。

Thanks, 谢谢,

Alex 亚历克斯

Write a Suds plugin to modify the XML before it is sent. 编写一个Suds插件 ,在发送之前修改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()])

Quoting Suds documentation: 引用Suds文档:

marshalled() 整理()
Provides the plugin with the opportunity to inspect/modify the envelope Document before it is sent. 为插件提供在发送之前检查/修改信封文档的机会。

I had the exact same problem when using suds to access a BizTalk/IIS SOAP service. 使用suds访问BizTalk / IIS SOAP服务时,我遇到了完全相同的问题。 From what I can tell from the WSDL it occurs when there is a "complexType" that is not part of the "targetNamespace" (it has it's own), which has a child that is also a complexType, but with no namespace set. 从我从WSDL中可以看出,当有一个“complexType”不属于“targetNamespace”(它有自己的一部分)时,就会发生这种情况,它有一个子类,它也是一个complexType,但没有设置名称空间。 In BizTalk this means that the child should belong to the same namespace as the parent, but Suds seem to think that it then should be part of the targetNamespace .... 在BizTalk中,这意味着子项应该与父项属于同一名称空间,但是Suds似乎认为它应该是targetNamespace的一部分....

The fix in the source-code solved the thing "correctly", but since I want to be able to upgrade without applying the fix every time I went for another solution.... 源代码中的修复解决了“正确”的问题,但是因为我希望每次去另一个解决方案时能够升级而不应用修复程序....

My solution was to skip Suds and just copy the raw XML, use that as a template and copy the values into it ... Not beautiful, but at least simple. 我的解决方案是跳过Suds并只复制原始XML,将其用作模板并将值复制到其中...不漂亮,但至少简单。 The solution to add a plugin is in my opinion equally hardcoded and perhaps even harder to maintain. 在我看来,添加插件的解决方案同样硬编码,甚至可能更难维护。

You could build soap message yourself and use SoapClient to send the message : 您可以自己构建soap消息并使用SoapClient发送消息:

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

I prefer regular expressions :) 我更喜欢正则表达式:)

import re

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM