Удалите пространство имен из переменных ответа Spyne.

Реализация WebService в соответствии с конкретным WSDL. Клиент не может быть изменен. Корректно обрабатывает запрос от клиента, но клиент жалуется на ответ из-за пространства имен в переменных.

Что я хочу (ответ soapUI на основе WSDL):

<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/", local:"result") . Ожидаемые элементы: ‹{}result>,‹{}notify>]

Фрагмент реализации:

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!")

person c4talyst    schedule 03.03.2015    source источник


Ответы (3)


Это невозможно (пока) и отвечает на аналогичный вопрос здесь сопровождающим.

Обходной путь заключался в том, чтобы добавить прослушиватель в event_manager для «method_return_string», а затем выполнить некоторые строковые операции.

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>")
person c4talyst    schedule 04.03.2015

это можно исправить, переопределив nsmap в application.interface

    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 по умолчанию

person thebat    schedule 23.06.2015
comment
application.interface устарел по крайней мере с версии 2.10: spyne.io/docs/2.10/reference/ приложение.html - person FelixEnescu; 13.10.2016

Если вам интересно, как добавить слушателя в event_manager для method_return_string, см. ниже полный пример:

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, это по-прежнему единственный способ удалить пространства имен из переменных ответа.

person FelixEnescu    schedule 13.10.2016