Our customer appears to have set things up correctly at their end. Regrettably, SOAP::Lite is a bit, er, confusing. It's retrieving everything correctly, but it's being coy and refusing to actually let me have the data. I think I'll buy it flowers.
returning multiple items?
lachoy on 2004-10-13T19:27:23
If the SOAP method returns multiple items (e.g., returns a Vector) see
a recent blog entry I wrote after running into this. It is possible to make SOAP::Lite behave, just takes a little work...
Re:returning multiple items?
Ovid on 2004-10-13T19:58:22
I note that you state it only returns the last item when fetching multiple items. I am fetching multiple items, but I get nothing.
use the SOM
ChrisDolan on 2004-10-15T15:30:12
I agree that SOAP::Lite is quite opaque. In my work, I usually skip the "handy" wrappers that SOAP::Lite offers and dig into the XML. Here's a snippet like what I use in my unreleased SOAPClient package
sub call
{
my ($uri, $proxy, $timeout, $method, $args, $want) = @_;
my @args = map {SOAP::Data->name($_, $args->{$_})} keys %$args;
my $som = SOAP::Lite
->uri($uri)
->proxy($proxy, timeout => $timeout)
->call($method, @args);
for (@$want) {
my $wantArray = (s/^\@//);
my @vals;
if ($som->match("/Envelope/Body/[1]/$_")) {
@vals = $som->valueof();
push @rets, $wantArray ? [@vals], $vals[0];
}
return @rets;
}
Then use this like as follows (fictional service):
my ($temp, $humid) = call($uri, $proxy, 30, "getWeather", {zip => 53711}, ["temp", "humidity]);
This works best if the server looks like this:
our @ISA = qw(SOAP::Server::Parameters);
sub getWeather
{
my %data;
if ($_[-1] && UNIVERSAL::isa($_[-1] => 'SOAP::SOM') {
%data = %{$_[-1]->method() || {}};
} else {
push @_, undef if (@_ %2 != 0); # need even number of elements
%data = @_;
}
if (!$data{zip}) {
die SOAP::Fault->faultcode("MissingData")->faultstring("Zip not provided");
}
my ($temp, $windspeed, $humidity) = weather($data{zip});
return SOAP::Data->name(temperature => $temp),
SOAP::Data->name(windspeed => $wind),
SOAP::Data->name(humidity => $humidity);
}
That server can be specified by the following WSDL (which is
incomplete since it lacks a service tag):
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<definitions targetNamespace="urn:Weather" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="urn:Weather" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<documentation>
Partial WSDL auto-generated from soap.pod by /perl/bin/pod2wsdl
</documentation>
<message name="getWeatherRequest">
<part name="zip" type="xsd:integer"/>
</message>
<message name="getWeatherResponse">
<part name="temperature" type="xsd:float"/>
<part name="windspeed" type="xsd:float"/>
<part name="humidity" type="xsd:float"/>
</message>
<portType name="WeatherInterface">
<operation name="getWeather">
<input message="tns:getWeatherRequest"/>
<output message="tns:getWeatherResponse"/>
</operation>
</portType>
<binding name="WeatherBinding" type="tns:WeatherInterface">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getWeather">
<soap:operation soapAction="http://weather.foo.com/Weather#getWeather"/>
<input>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://weather.foo.com/Weather" use="encoded"/>
</input>
<output>
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://weather.foo.com/Weather" use="encoded"/>
</output>
</operation>
</binding>
</definitions>