【问题标题】:Remove the namespace from Spyne response variables从 Spyne 响应变量中删除命名空间
【发布时间】:2015-03-03 13:24:27
【问题描述】:

根据特定的 WSDL 实现 WebService。客户端无法更改。正确处理来自客户端的请求,但由于变量中的命名空间,客户端抱怨响应。

我想要什么(基于 WSDL 的soapUI 响应):

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cal="http://callback.foo.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <cal:foo_statusResponse>
         <result>SUCCESS</result>
         <notify>Thanks!</notify>
      </cal:foo_statusResponse>
   </soapenv:Body>
</soapenv:Envelope>

我得到了什么(通知 tns: 关于导致验证问题的变量):

<senv:Envelope xmlns:tns="http://callback.foo.com/" xmlns:senv="http://schemas.xmlsoap.org/soap/envelope/">
  <senv:Body>
    <tns:foo_statusResponse>
      <tns:result>SUCCESS</tns:result>
      <tns:notify>Thanks!</tns:notify>
    </tns:foo_statusResponse>
  </senv:Body>
</senv:Envelope>

Java 客户端抛出此异常:

[com.sun.istack.SAXParseException2;行号:2;列号:162; 意外元素(uri:“http://callback.foo.com/”,本地:“结果”)。 预期元素是 、]

实现sn-p:

class fooStatusRS(ComplexModel):
    result = Unicode()
    notify = Unicode()

class foo_callback(ServiceBase):
    @srpc(Unicode, Unicode, Unicode, Unicode, statusbarInfo, anotherResponse, 
            _out_header=None, 
            _out_variable_names=("result", "notify"), 
            _returns=(Unicode, Unicode), 
            _out_message_name="foo_statusResponse",
            _operation_name="foo_status_rq")
    def foo_status(foo_id, reply, ref, status, statusbar, another):
        if foo_id:
            print foo_id

        return fooStatusRS(result="SUCCESS", notify="Foo received!")

【问题讨论】:

    标签: python soap wsdl spyne


    【解决方案1】:

    这是不可能的(目前),维护者在类似的问题here 中回答了这个问题。

    解决方法是为“method_return_string”添加监听器到 event_manager,然后执行一些字符串操作。

    def _method_return_string(ctx):
        ctx.out_string[0] = ctx.out_string[0].replace("tns:result>", "result>")
        ctx.out_string[0] = ctx.out_string[0].replace("tns:notify>", "notify>")
    

    【讨论】:

      【解决方案2】:

      它可以通过覆盖 application.interface 中的 nsmap 来修复

          def fix_nsmap(application):
              conversion_dict = {
                  'tns': None,
                  'senv': 'soap',
              }
              nsmap = application.interface.nsmap
              for k, v in conversion_dict.iteritems():
                  nsmap[v] = nsmap[k]
                  del nsmap[k]
      
              application.interface.nsmap = nsmap
      
          application_security2 = Application(
              [Security2Service],
              tns=NS,
              name='Security2',
              in_protocol=Soap11(),
              out_protocol=Soap11()
          )
      
          fix_nsmap(application_security2)
      

      nsmap[None] 设置默认NS

      【讨论】:

      【解决方案3】:

      如果您想知道如何为 method_return_string 添加监听器到 event_manager,请参阅下面的完整示例:

      from spyne import Application, rpc, ServiceBase, Iterable, Integer, Unicode
      
      from spyne.protocol.soap import Soap11
      from spyne.server.wsgi import WsgiApplication
      
      
      class HelloWorldService(ServiceBase):
          @rpc(Unicode, Integer, _returns=Iterable(Unicode))
          def say_hello(ctx, name, times):
              for i in range(times):
                  yield u'Hello, %s' % name
      
      
      def on_method_return_string(ctx):
          ctx.out_string[0] = ctx.out_string[0].replace(b'Hello>', b'Good by')
      
      HelloWorldService.event_manager.add_listener('method_return_string', 
                                                    on_method_return_string)
      
      application = Application([HelloWorldService], 'spyne.examples.hello.soap',
                                in_protocol=Soap11(validator='lxml'),
                                out_protocol=Soap11())
      
      wsgi_application = WsgiApplication(application)
      
      
      if __name__ == '__main__':
          import logging
      
          from wsgiref.simple_server import make_server
          server = make_server('127.0.0.1', 8000, wsgi_application)
          server.serve_forever()
      

      从 Spyne 2.12 开始,这仍然是从响应变量中删除命名空间的唯一方法。

      【讨论】: