The class can be found in the file soap.py which we have made available for download here . In order to use this class, you will need to have lxml installed in your Python environment.
Here's a quick example. The first step is to extend the Soap class to consume a particular web service. In this example, we have setup a class that consumes the cdyne.com spellcheck service. This service is free and publicly available (without an API key), so it's the perfect candidate for an example.
>>> class CheckSpelling(Soap):
>>> def __init__(self):
... theDomain = "ws.cdyne.com"
... theURL = "/spellchecker/check.asmx"
... theNamespace = "http://ws.cdyne.com/"
... theServiceName = SOAP_NO_NAME
... super(CheckSpelling,self).__init__(theDomain,theURL,theNamespace,theServiceName)
>>> def buildRequestElement(self,text):
... em = ElementMaker(namespace=self.namespace, nsmap={None: self.namespace})
... elementCheckBody = em.CheckTextBody
... elementBodyText = em.BodyText
... return elementCheckBody(elementBodyText(text))
>>> def parseResponse(self,responseXML):
... misspellings = self.XPathWithQuery('//thens:MisspelledWord')
... suggestions = self.XPathWithQuery('//thens:Suggestions/text()')
... word = self.XPathWithQuery('//thens:word/text()')
... suggestioncount = self.XPathWithQuery('//thens:SuggestionCount/text()')
... return [ {'Suggestions':suggestions(m),'for word':word(m),'count':suggestioncount(m)} for m in
... misspellings(responseXML) ]
>>> def lookupWord(self,word):
... methodname = "CheckTextBody"
... return self.parseResponse(self.makeRequest(methodname,self.buildRequestElement(word)))
In the __init__ of the subclass we identify the service details including the domain, URL, namespace and service name. Many web services, such as this one, do not include a method name in the SOAP action. In this case you should set the service name to be SOAP_NO_NAME.
Because our goal is to keep this solution as simple as possible, we do not parse the WSDL file. Therefore, with each method on the web service that you would like to consume, you will need to create 3 methods in your SOAP subclass. The first method will build the request, the second will parse the response, and the third is a wrapper method that will put the request and response together.
Method 1: The buildRequestElement method creates the XML that will be posted inside the SOAP Envelope. To create this XML we utilize the lxml ElementMaker. In order to construct the XML with the ElementMaker, you will need to know the XML structure that is expected by the web service. The XML structure can be discovered by using SoapUI. SoapUI is a tool that makes it easy to perform test interactions with a web service. If you give it a WSDL URL, it will identify all of the methods on the webservice and provide you with the exact XML request objects. You can download the platform independent bin zip file (the first one in the list) from its project page (explode the zip and run the 'soapui.sh' file in the bin folder).
Method 2: The parseResponse method is used to parse out the data that is returned from the web service. To do so, we use the lxml XPath library. With XPath, we pull out the data and organize it into an easy to use dictionary. Much like the buildRequestElement method discussed above, the parseResponse method will need to have special knowledge about the XML structure of the response. By invoking a quick test of the web service with SoapUI, the tool will return the exact XML of the response. You can use this response XML from SoapUI as a guide for selecting out the data with XPath.
Method 3: Finally, the lookupWord method uses the request builder and the response parser and actually invokes the SOAP call on the web service. Creating this method gives us an easy-to-use Python interface to our web service method. As such, we can consume the web service with just 3 lines of code:
>>> from testspellingexample import CheckSpelling
>>> checkit = CheckSpelling()
>>> print checkit.lookupWord("recieved")
[{'count': ['25'], 'Suggestions': ['relieved', 'received', 'reserved', 'receiver',
'receive', 'receives', 'sieved', 'severed', 'reserve', 'resurvey', 'receivers',
'deserved', 'reserver', 'served', 'reserves', 'unreceived', 'surveyed',
"receiver's", 'suffered', 'unserved', 'saved', 'Cepheid', 'Recife', 'unsaved',
'sieve'], 'for word': ['recieved']}]
