OK, to get this out of the way. I know SOAP isn’t cool. However, there may still be times when you need to query data from a SOAP web service. This is an attempt to document the process of retrieving and working with that data.
In this example I will describe how to query the WSDL to get a list of methods and parameters, and use that to submit the method call. I will be calling a web service method called ‘webMethod’ that accepts one parameter called ‘publishDate’. If you don’t already know this information about the web service you are communicating with, there is a free tool called SoapUI that works pretty well. It’s written in Java, so you should be able to get it to work on about any platform.
Depending on the version of Ruby you are running, the first thing that may be required is to install soap4r:
gem install soap4r
Next is to set the location of the WSDL file on the web server, set the encoding, and instantiate the driver:
require 'soap/wsdlDriver'
wsdl = 'http://server/WebService.asmx?WSDL'
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
XSD::Charset.encoding = 'UTF8'
This next line will create two logs in the directory of the process called devLog_webMethod_response.xml and devLog_webMethod_request.xml that will show the raw request and response each time the process is called. In place of webMethod will be the actual method name of the web service being called. This can be commented out when the application is moved to production.
driver.wiredump_file_base = "devLog"
Now it’s time to retrieve the data:
@response = driver.webMethod(:publishDate => '2008-09-01')
At this point @response contains the XML response from the web service. In order to retrieve the data we will need to know a little bit about the structure of the XML. We can find out this information by opening the log file created by the previous step. Let’s open devLog_webMethod_response.xml:
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<WebMethodResponse xmlns="WebMethod">
<WebMethodResult>
<Article>
<Name>Example 1</Name>
<Headline>Poor Excuse For An Article</Headline>
<Body>Nothing to see here, move along please.</Body>
</Article>
<Article>
<Name>Example 2</Name>
<Headline>Woot! I Made Headlines</Headline>
<Body>Yeah, OK. Another poorly written example article.</Body>
</Article>
</WebMethodResult>
</WebMethodResponse>
</soap:Body>
</soap:Envelope>
OK, so here we have two articles that contain the data we are after and they are both inside the WebMethodResult tags. So to access those bits we might do something like:
@response.webMethodResult.article.each do |article|
puts article["Name"]
puts article["Headline"]
puts article["Body"]
end
That works great as long as there is always more than one article. If, on the other hand, there is only one article in the result, it is no longer an array and the .each method will fail. So to get around this we can move our logic to a method and then test the article first to see which way we should handle it. So the previous code might be rewritten as:
def print_article(article)
puts article["Name"]
puts article["Headline"]
puts article["Body"]
end
if(@response.webMethodResult.article.is_a?(Array))
@response.webMethodResult.article.each do |article|
print_article(article)
end
else
print_article(@response.webMethodResult.article)
end
If you are asked to do some work with SOAP based web services, hopefully this makes it a little easier to get up and running.