2010-05-10 63 views
2

我正在尝试使用SUDS和Python与SOAP Web服务交谈。在学习了很多Python之后(是的,我对此很陌生)以及如何使用SUDS,我遇到了一个问题。SUDS生成的XML错误

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 
} 

所以我用肥皂水创造我想要的课程,并将其发送给方法。但是我得到一个错误。所以我打开日志记录,我可以看到正在发送的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。

谢谢。

+0

我认为我们需要一个用于创建此结构的代码示例。这很可能是你以错误的方式设置它,这会让SUDS感​​到困惑。 – 2010-05-10 13:43:00

+0

好点,代码现在已被添加 – itworkedonmachine 2010-05-10 13:48:44

回答

5

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

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

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

这个问题似乎是因为我使用client.factory.create方法创建了一个CreationReq对象。通过打印来检查客户端显示我所调用的方法不会将该对象作为参数。相反,它需要一个命名参数列表。

所以我的代码是:

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) 
+0

我有同样的问题。这个解决方案为我工作。我仍然不知道为什么,但至少它工作:) – Kai 2010-11-23 14:16:18

0

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

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

+0

这是通过网络发送数据。 – itworkedonmachine 2010-05-10 13:40:56

+0

我同意XML是可怕的,但SOAP Web服务由第三方供应商提供,因此我无法控制如何将接口实现到他们的产品中。我如何使用JSON-rpc来调用SOAP Web服务? – itworkedonmachine 2010-05-10 13:56:18

+0

您的程序需要做什么以及第三方供应商是什么,如果您的第三方供应商支持soap,它将支持可能支持json。 – Taos 2010-05-10 14:09:53

0

您创建元素两次。删除此:

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

并改变这一点:

newcase.ClassificationEventCode = 2000023 

这应该删除多余的标签。

+0

这没有什么区别。命令classEventCode = client.factory.create('ns1:FWTEventCode')只是基于wsdl创建一个新对象,然后将其分配给传递给Web方法的对象。 但是这不会增加两次。 感谢您的建议。 – itworkedonmachine 2010-05-12 18:44:32

+0

@Abbott - 我没有什么可以测试这个最简单的,但是阅读这个文档http://jortel.fedorapeople.org/suds/doc/suds.sax.element.Element-class.html,detach选项可能很有用。但不确定,你可能已经阅读过这个。 – chrissygormley 2010-05-18 13:06:44

1

如果您肥皂水服务创建一个客户端,也有一些属性,你可以看到,以确定哪些对象是需要通过服务电话。

例如:

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

这应该告诉你的前缀,端口,方法,和类型。 对于您的代码,您应该能够看到在createCase的服务调用中需要传递的内容。尽管WSDL可能会将方法定义为需要'FWTCaseCreate',但泡沫可能会提取createCase的定义以需要ClassificationEventCode,优先级,标题类型等。

因此您不想这么做:(通过在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__]) 

传递服务调用所需的参数列表。

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

0

我发现此线程正在搜索相同问题的解决方案。到目前为止,我已经研究过,只有当你将工厂创建的对象直接传递给服务方法时才会发生。只有使用扩展(继承)的wsdl数据类型。

我能想到更多的解决方案。

  • 完全不使用工厂的顶级类型。
  • 写插件泡产生
  • 重新编写WSDL来传递给服务方法之前不使用继承(扩展标签)
  • 变化类型的对象后更改的XML

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

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)