Python Suds的MessagePlugin似乎没有更新我的输出

时间:2013-08-22 17:36:48

标签: python xml soap xml-namespaces suds

我正在尝试使用suds向远程SOAP服务发出请求。我需要在参数上设置命名空间:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="http://myemployer.com/"    xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header>
      <AuthHeader xmlns="http://myemployer.com/">
            <Token>blah</Token>
      </AuthHeader>
   </SOAP-ENV:Header>
   <ns1:Body>
      <ns0:AwardBadgesBatch>
          <ns0:badgeAwards>
              <AwardBadge>
                  <EnterpriseID>jhoov11</EnterpriseID>
                  ...
              </AwardBadge>
         </ns0:badgeAwards>
         <ns0:includeSuccessStatus>false</ns0:includeSuccessStatus>
      </ns0:AwardBadgesBatch>
   </ns1:Body>   
</SOAP-ENV:Envelope>

请注意badgeAwards和includeSuccessStatus元素上的“ns0”。我还需要在badgeAwards内的东西上没有前缀。

我正在使用此代码发出请求:

from suds.client import Client
from suds.sax.element import Element
from suds.sax.attribute import Attribute
from suds.plugin import MessagePlugin
import logging
logging.getLogger('suds.client').setLevel(logging.DEBUG)
logging.getLogger('suds.transport').setLevel(logging.DEBUG)
logging.basicConfig(level=logging.DEBUG)
url='https://myemployer.com/BadgingServices.asmx?wsdl'

c = Client(url)
t = c.service.Authenticate('blah')
t = t.Authenticate.Status.Token

header_root = Element('AuthHeader')
header_token = Element('Token').setText(t)
header_attribute = Attribute('xmlns', "http://myemployer.com/")
soap_header = header_root.insert(header_token)
soap_header.append(header_attribute)

class NamespaceFixer(MessagePlugin):
    ''' must add namespace prefix to all parameters '''
    def marshalled(self, context):
        body = context.envelope[1]
        for i in body[0]:
            i.setPrefix('ns0')
            print "******* element after setting prefix: %s ********" % i.plain()

nsf = NamespaceFixer()
c.set_options(soapheaders=soap_header, plugins=[nsf])

from suds.sax.element import Element

ba2 = Element('badgeAwards')
ba = Element('AwardBadge')
ba2.append(ba)
entid = Element('EnterpriseID').setText('jhoov11')
ba.append(entid)
...

includeSuccess = Element('includeSuccessStatus').setText('false')

c.service.AwardBadgesBatch(badgeAwards= ba2, includeSuccessStatus=includeSuccess)

现在,当我这样做时,我会在marshall()调用之前看到xml文本输出,并且我看到该调用的输出:

******* element after setting prefix: <ns0:badgeAwards/> ********
******* element after setting prefix: <ns0:includeSuccessStatus/> ********

但另一方面的人坚持(坚持!)在接收到这些元素时没有设置前缀。

有两个问题浮现在脑海中:

  1. 我在MessagePlugin中做错了什么?
  2. 有没有办法在发送之前显示最终修改后的XML文本?我想我正在设置它,但是当我看不到我发送的最终全文时,我只能对他们说这么多。
  3. 编辑:

    c.last_sent().plain()
    u'<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:ns0="http://pebble.searshc.com/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    
    <SOAP-ENV:Header><AuthHeader xmlns="http://myemployer.com/"><Token>blah</Token></AuthHeader></SOAP-ENV:Header>
    <ns1:Body><ns0:AwardBadgesBatch><ns0:badgeAwards/><ns0:includeSuccessStatus/></ns0:AwardBadgesBatch></ns1:Body></SOAP-ENV:Envelope>'
    

    所以badgeAwards和includeSuccessStatus被发送为空。 ???

    编辑:尝试工厂。这个wsdl很奇怪(对我来说) - 它将调用本身定义为一个类型,因此:

    <s:element name="AwardBadgesBatch">
      <s:complexType>
        <s:sequence>
          <s:element minOccurs="0" maxOccurs="1" name="badgeAwards">
             <s:complexType mixed="true">
               <s:sequence>
                  <s:any/>
               </s:sequence>
             </s:complexType>
          </s:element>
          <s:element minOccurs="1" maxOccurs="1" name="includeSuccessStatus" type="s:boolean"/>
        </s:sequence>
      </s:complexType>
    </s:element>
    
    
    ...
    
    <wsdl:operation name="AwardBadgesBatch">
      <soap:operation soapAction="http://pebble.searshc.com/AwardBadgesBatch" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
        <soap:header message="tns:AwardBadgesBatchAuthHeader" part="AuthHeader" use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
        <soap:header message="tns:AwardBadgesBatchAuthHeader" part="AuthHeader" use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    

    它没有定义AwardBadge类型。所以我就这样做了我的AwardBadge:

    ba = Element('AwardBadge')
    
    entid = Element('EnterpriseID').setText('jhoov11')
    ba.append(entid)
    btype = Element('badgeTypeID').setText('30')
    ba.append(btype)
    startdate = Element('startDate').setText('2013-8-22')
    ba.append(startdate)
    enddate = Element('endDate').setText('9999-12-31')
    ba.append(enddate)
    isdeleted = Element('isDeleted').setText('0')
    ba.append(isdeleted)
    

    我在通话中设置了值

    call = c.factory.create('AwardBadgesBatch')
    call.badgeAwards= [ba]
    call.includeSuccessStatus= False
    

    我打电话给服务

    c.service.AwardBadgesBatch(call)
    

    并得到一些错误。当我看到我发送的内容时,我看到了

    c.last_sent().plain()
    u'<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:ns0="http://myemployer.com/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
      <SOAP-ENV:Header>
          <AuthHeader xmlns="http://myemployer.com/"><Token>blah</Token></AuthHeader>
      </SOAP-ENV:Header>
      <ns1:Body>
         <ns0:AwardBadgesBatch>
            <ns0:badgeAwards>
               <AwardBadge/>
               <ns0:includeSuccessStatus>false</ns0:includeSuccessStatus>
             </ns0:badgeAwards>
             <ns0:includeSuccessStatus/>
         </ns0:AwardBadgesBatch>
      </ns1:Body>
      </SOAP-ENV:Envelope>'
    

    所以,有三个问题:

    1. AwardBadge是空的。
    2. includeSuccessStatus是重复的,一个在badgeAwards内,它不属于。
    3. 位于正确位置的includeSuccessStatus为空。
    4. 将badgeAwards设置为ba或[ba]是没有区别的。

      更多见解?

2 个答案:

答案 0 :(得分:0)

Suds为服务类型提供工厂 - client.service.factory.create(type_name)。那给你python对象。这是演示,也许你可以根据你的情况进行调整:

...
client = Client(...)
award = client.factory.create("ns0:AwardBadgesBatch")
award.includeSuccessStatus = True
...

Suds有两个不错的方法 - client.last_sent()和client.last_received()。在请求后使用它们您可以看到您发送和接收的确切内容。此外,您可以了解服务打印suds客户端的很多信息:

client = Client(...)
print client

答案 1 :(得分:0)

我认为这是泡沫0.4中的一个错误。在MessagePlugins中完成的任何更新都不会被应用,而是发送原始消息。

您可以通过在suds中修补client.py来修复它:

function show() {
  $('#button').show();
}

另一种选择可能是切换到可能切换到jurko fork of suds,这也修复了这个错误。但是,我自己还没有尝试过这个选项。

这个问题也提到了这个问题:Suds Client ignores modification done by plugins into sending method