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

问题描述:

我使用python/suds来实现客户端,并且在wsdl中由element ref=定义的参数类型的参数的发送SOAP头中出现错误的名称空间前缀。python在SOAP请求中产生错误的名称空间前缀

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

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请求来检查服务是否接受“好”前缀。

UPDATE

我插手与SUDS源代码和下述经验修正力与ref=属性的所有元件承担REF-ED命名空间(先前,他们采取在架构根名称空间或任何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

这显然是在栈中的错误; “自动”是什么意思?例如,您是否愿意与您的工具配合使用不同但同等的XSD?从你所说的话来看,如果你想用本地定义的元素替换ref,它就可以工作;对于所有XSD关心,生成的XML将是相同的。如果你考虑改变航班,比如通过代理使用某种XSLT,那将是一种不同的方法。我可以推荐一个解决方案,它会自动重构您的XSD以替换本地元素。 – 2012-04-18 16:04:56

+0

我真的试图移动和变化的定义,但因为我不是专家,也许我coudn't找准正确的语法,泡沫不停地把错误的命名空间存在。我也不喜欢这些,因为它们是由外部供应商提供的,并且可能会发生变化。请参阅UPDATE以获取迄今为止发现的非最佳解决方案。 – 2012-04-19 09:18:41

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()]) 

报价肥皂水文档:

整理()
提供了机会,检查/发送之前修改信封文档插件。

+1

对于这个特定的情况,这将工作正常。然而,由于在不同的树位置有很多这样的参数,所以用手修复它们并不是最佳的。我希望_prefix ns0这样的东西适用于ref = _的所有元素,并且可以有理由地解析整个xml树,我相信context.envelope不会保留'ref ='信息。 – 2012-04-20 08:06:18

+0

另一种选择是延伸'DocumentPlugin'修改WSDL/XSD目的,'解析()'方法(参见文档)将被调用两次(一个用于WSDL,另一个用于XSD)。 – dusan 2012-04-20 17:17:05

+0

辉煌,谢谢!有趣的是,我必须在与最初的例子完全相同的地方(结构上)更正信封。这里有模式吗? – Gesias 2013-03-15 03:16:37

你可以建立自己的SOAP消息,并使用SoapClient发送消息:

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

我用肥皂水访问的BizTalk/IIS SOAP服务时,有完全相同的问题。 从我可以从时,有一个“复杂类型”是不是“目标名称”(它有它自己的),其中有一个孩子,这也是一个复杂类型的组成部分,但没有命名空间的设置它发生的WSDL告诉。在BizTalk中,这意味着孩子应该和父母一样属于同一个命名空间,但是Sud似乎认为它应该是目标命名空间的一部分......

源代码中的修复解决了“正确的”,但因为我希望能够不用每次我去另一个解决方案时应用补丁升级....

我的解决办法是跳过肥皂水和刚才复制的原始XML,用它作为模板,将值复制到它中...不是很美,但至少很简单。 在我看来,添加插件的解决方案同样是硬编码的,可能更难以维护。

我喜欢的正则表达式:)

import re 

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

您的方法doens't工作得很好:WebFault:服务器引发错误:'请求的根元素无法确定。 – Allen 2013-10-02 14:06:26

+0

mmhhh ...所以插件策略是... – 2013-10-08 08:06:09