SUDS生成的XML不正确

时间:2010-05-10 13:29:11

标签: python soap wsdl suds

我正在尝试使用SUDS和Python与SOAP Web服务进行交流。经过大量学习Python的麻烦(是的,我是新手),并研究如何使用SUDS,我遇到了一个问题。

根据suds的说法,我正在调用的Web方法的签名是

(FWTCaseCreate){
ClassificationEventCode = None
Priority = None
Title = None
Description = None
Queue = None
DueDate = None
AssociatedObject = 
  (FWTObjectBriefDetails){
     ObjectID = 
        (FWTObjectID){
           ObjectType = None
           ObjectReference[] = <empty>
        }
     ObjectDescription = None
     Details = None
     Category = None
  }
Form = 
  (FWTCaseForm){
     FormField[] = <empty>
     FormName = None
     FormKey = None
  }
Internal = None
InteractionID = None
XCoord = None
YCoord = None
}

所以我使用SUDS创建我想要的类并将其发送给方法。但是我收到了一个错误。所以我开启登录,我可以看到正在发送的XML不正确,导致反序列化错误。 SOAP包如下所示

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://www.CRM.com/wsdl/FLTypes"    xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
   <wsse:Security>
      <wsse:BinarySecurityToken>eaadf1ddff99a8</wsse:BinarySecurityToken>
   </wsse:Security>
</SOAP-ENV:Header>
<ns1:Body>
   <ns0:FWTCaseCreate>
      <ClassificationEventCode>
         <ClassificationEventCode>2000023</ClassificationEventCode>
         <Priority>1</Priority>
         <Title>testing</Title>
         <Description>testing</Description>
         <Queue/>
         <Internal>True</Internal>
         <XCoord>356570</XCoord>
         <YCoord>168708</YCoord>
      </ClassificationEventCode>
   </ns0:FWTCaseCreate>
</ns1:Body>

正如你所看到的那样     'ClassificationEventCode' 围绕所有其他元素的元素,这不应该存在。如果我将此xml剪切并粘贴到SOAPUI中,首先删除此元素,然后将其直接发布到Web服务,它就能成功运行。

以下是我用于拨打电话的代码

client = Client(url)

#Add a header for the security
ssnns = ('wsse', 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd')

ssn = Element('BinarySecurityToken', ns=ssnns).setText(binaryKey)

ssn1 = Element('Security',ns=ssnns)

ssn1.append(ssn)

client.set_options(soapheaders=ssn1) 

newCase = client.factory.create('ns1:FWTCaseCreate')

classEventCode = client.factory.create('ns1:FWTEventCode')
classEventCode.value = 2000023

newCase.ClassificationEventCode = classEventCode
newCase.Priority = 1
#optional
newCase.AssociatedObject = None
#optional
newCase.Form = None
#optional
newCase.Internal = None
#optional
newCase.InteractionID =  None
#optional
newCase.DueDate = None
#optional
newCase.Queue = None

newCase.Title = 'Title'

newCase.Description = 'description'

newCase.XCoord = '356570'

newCase.YCoord = '168708'

caseID = client.service.createCase(newCase)

有没有人知道为什么会这样?我猜SUDS认为它应该基于WSDL。

感谢。

5 个答案:

答案 0 :(得分:6)

得到了完全相同的问题。我的SOAP请求中的参数序列被包装在一个与第一个参数同名的元素中。 e.g。

....
   <ns0:Body>
      <ns1:CreationReq>
         <ReqType>
            <ReqType>1</ReqType>
            <Title>Mr</Title>
            ....
         </ReqType>
      </ns1:CreationReq>
   </ns0:Body>
....

我已经检查了WSDL以确保它没有问题。

看起来问题是因为我使用client.factory.create方法创建了一个CreationReq对象。通过打印检查客户端显示我正在调用的方法不将该对象作为参数。而是需要一个名为args的列表。

所以我的代码是:

req = client.factory.create('CreationReq')
req.ReqType = 1
req.Title = 'Mr'
resp = client.service.Create(req)

现在是:

req = {}
req['ReqType'] = 1
req['Title'] = 'Mr'
resp = client.service.Create(**req)

答案 1 :(得分:1)

如果您为suds服务创建客户端,则可以看到一些属性,以确定需要将哪些对象传递到服务调用中。

例如:

import suds
client = suds.Client(url)
for a in client.sd: #print the whole service definition
    print a

这应该显示前缀,带方法的端口和类型。 对于您的代码,您应该能够看到在对createCase的服务调用中需要传递的内容。尽管WSDL可能将方法定义为需要'FWTCaseCreate',但是suds可能会为createCase定义需要ClassificationEventCode,Priority,Title类型等。

因此你不想这样做:(在第一个参数中传递newCase,将所有细节放在该标记下)

newCase = client.factory.create('ns1:FWTCaseCreate')
caseID = client.service.createCase(newCase)

但是这样调用服务:(基于服务定义)

newCase = client.factory.create('ns1:FWTCaseCreate')
caseID = client.service.createCase(newCase.ClassificationEventCode, newCase.Priority, ...)

或者也许:

newCase = client.factory.create('ns1:FWTCaseCreate')
caseID = client.service.createCase(*[getattr(newCase,a) for a in newCase.__keylist__])

传入服务调用所需的args列表。

我不知道为什么服务调用定义被错误地解析为它是什么,但传入正确的对象不会自动扩展到所需的正确参数列表。也许阅读suds来源(http://jortel.fedorapeople.org/suds/doc/)将有助于泄露答案。

答案 2 :(得分:0)

  

你打算用这个吗?   配置文件,或存储信息。   或者这是通过发送数据   网络

好吧那么,如果是这样,那么为什么不使用json或json-rpc,据说它们更快,更容易解析,更容易阅读。 XML是一种可靠的数据类型,我个人不能等到它死了,如果你寻找发送它的数据将非常值得使用json。

答案 3 :(得分:0)

您要两次创建元素。删除它:

classEventCode = client.factory.create('ns1:FWTEventCode') 
classEventCode.value = 2000023 

并改变这一点:

newcase.ClassificationEventCode = 2000023

这应删除该额外标签。

答案 4 :(得分:0)

我发现这个帖子正在寻找同样问题的解决方案。到目前为止,我研究过只有将工厂创建的对象直接传递给服务方法才会发生。并且仅使用wsdl数据类型使用扩展(继承)。

我能想到更多解决方案。

  • 根本不使用工厂作为顶级类型。
  • 生成
  • 后写suds插件更改xml
  • 重写wsdl以不使用继承(扩展标记)
  • 在传递给服务方法之前更改对象类型

我选择了最后一个,因为这是最简单的方法。所以有代码。

def sudsToDict(data):
    return dict([(str(key),val) for key,val in data])

像这样使用。

data = client.factory.create('wsdl_data_type')
# now fill with values and then
data = sudsToDict(data)
client.service.some_method(**data)