1

Actually i have a python script and soap server running using soap spyne and i need to call that soap api using c++ gsoap client so that the python script will run and get the output as a response to client i am able to call the api using SOAP UI and python zeep client but when i try to call the client using gsoap it gave me error

DEBUG:spyne.protocol.soap.soap11:ValueError: Deserializing from unicode strings with encoding declaration is not supported by lxml

the generated wsdl file of both gsoap and soap spyne have different namespace also

```python
from spyne import Application, rpc, ServiceBase, Integer,     Unicode,String
from spyne.protocol.soap import Soap11
from spyne.server.wsgi import WsgiApplication
from spyne.model.complex import ComplexModel
from spyne.model.complex import Array
from twisted.internet import reactor
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
from twisted.python import log


import sys
sys.path.insert(1,'../cloud-client/slicing')
import speech as t

class caps__CSoapReqBuf(ComplexModel):
    stringarray=String
    size=Integer


class caps__CSoapResponse(ComplexModel):
    __namespace__ = "spyne.examples.hello.soap"
    nRetCode=Integer
    strResponseData=String

class caps__CSoapRequest(ComplexModel):
    __namespace__ = "spyne.examples.hello.soap"
    nRequestType = Integer
    wstrRequestParam= String

class caps_CCallbackData(ComplexModel):
    __namespace__ = "spyne.examples.hello.soap"
    nPort=Integer
    strFunction = String


class TranscriptionService(ServiceBase):
    @rpc(String, String, caps_CCallbackData, caps__CSoapResponse,     _returns=Integer)
    def caps__SoapRequestString(ctx, function_name, SoapRequest,     CallbackData, SoapResponse):
        parameters = SoapRequest
        list = parameters.split('|')
        d = dict(s.split(':') for s in list)
        filename = d['path']
        samplerate = int(d['sr'])
        outputpath = d['outputpath']

       # samplerate=parameters.samplerate       
            if(function_name=='gettranscription'):
            print("gettranscription")
            out=t.main(filename,samplerate)
            SoapResponse.nRetCode=1
            SoapResponse.wstrResponseData=out
            return 0
        elif(function_name=='getocr'):
            return "Do OCR"
        else:
            return "error"

    @rpc(caps__CSoapResponse,_returns=Unicode)   
    def caps_SoapResponseString(ctx,caps__CSoapResponse):
        response = caps__CSoapResponse.wstrResponseData
        return response




application = Application([TranscriptionService],     '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
    ip = '192.168.0.103'
    port = 8090
    resource = WSGIResource(reactor, reactor, wsgi_application)
    site = Site(resource)
    reactor.listenTCP(port, site,interface=ip)
    logging.basicConfig(level=logging.DEBUG)
    logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)
    logging.info("listening to "+ ip +":"+str(port))
    reactor.run()
```

Updated After updating the code following errors follows in response.

``` Response
'<soap11env:Envelope 
xmlns:soap11env="http://schemas.xmlsoap.org/soap/envelope/">\n  
<soap11env:Body>\n    <soap11env:Fault>\n      
<faultcode>soap11env:Client.ResourceNotFound</faultcode>\n      
<faultstring>Requested resource 
\'{http://tempuri.org/caps.xsd/Service.wsdl}\' not 
found</faultstring>\n      <faultactor></faultactor>\n    
</soap11env:Fault>\n  </soap11env:Body>\n</soap11env:Envelope>\n'
DEBUG:spyne:gc.collect() took around 40ms.
```

2 Answers2

0

On that front, lxml is a bit strict on the kind of stream it thinks it can process.

I'm persuaded that the right thing to do to solve this conflict is to strip the encoding declaration from the xml string.

You can add a handler for the 'wsgi_call' event to implement this. See the events example to see what the relevant API looks like.

Burak Arslan
  • 7,671
  • 2
  • 15
  • 24
0

My solution to this is to let lxml fail and parse the payload manually using WebOb and then place it in the user defined context. You can later access ctx.udc to access the data. So:

...
from webob import Request as WebObRequest
...

HOST = '0.0.0.0'
PORT = 8000

# parse payload manually 
def _on_wsgi_call(ctx):
    req = WebObRequest(ctx.transport.req)
    decoded = req.body.decode('utf-8')
    envelope = Etree.fromstring(decoded)

    # depending on your data, you may need to update this step 
    element = next(envelope.iter())
    ctx.udc = element.text


if __name__ == '__main__':
    application = initialize([YourService])
    wsgi_application = WsgiApplication(application)
    wsgi_application.event_manager.add_listener('wsgi_call', _on_wsgi_call)
    resource = WSGIResource(reactor, reactor, wsgi_application)
    site = Site(resource)
    reactor.listenTCP(PORT, site, interface=HOST)

    logging.info('listening on: %s:%d' % (HOST, PORT))
    logging.info('wsdl is at: http://%s:%d/?wsdl' % (HOST, PORT))

    sys.exit(reactor.run())
Victor
  • 349
  • 4
  • 7