SOAP::Lite - Perl's Web Services Toolkit
SOAP::Lite is a collection of Perl modules which provides a simple and
lightweight interface to the Simple Object Access Protocol (SOAP) both on
client and server side.
As of version SOAP::Lite version 1.05, no perl versions before 5.8 will be supported.
SOAP::Lite 0.71 will be the last version of SOAP::Lite running on perl 5.005
Future versions of SOAP::Lite will require at least perl 5.6.0
If you have not had the time to upgrade your perl, you should consider this now.
- lib/SOAP/Lite.pm
-
the SOAP::Lite manpage - Main class provides all logic
the SOAP::Transport manpage - Transport backend
the SOAP::Data manpage - Data objects
the SOAP::Header manpage - Header Data Objects
the SOAP::Serializer manpage - Serializes data structures to SOAP messages
the SOAP::Deserializer manpage - Deserializes SOAP messages into SOAP::SOM objects
the SOAP::SOM manpage - SOAP Message objects
the SOAP::Constants manpage - Provides access to common constants and defaults
the SOAP::Trace manpage - Tracing facilities
the SOAP::Schema manpage - Provides access and stub(s) for schema(s)
SOAP::Schema::WSDL - WSDL implementation for SOAP::Schema
the SOAP::Server manpage - Handles requests on server side
SOAP::Server::Object - Handles objects-by-reference
the SOAP::Fault manpage - Provides support for Faults on server side
the SOAP::Utils manpage - A set of private and public utility subroutines
- lib/SOAP/Packager.pm
-
the SOAP::Packager manpage - Provides an abstract class for implementing custom packagers.
SOAP::Packager::MIME - Provides MIME support to SOAP::Lite
SOAP::Packager::DIME - Provides DIME support to SOAP::Lite
- lib/SOAP/Transport/HTTP.pm
-
SOAP::Transport::HTTP::Client - Client interface to HTTP transport
SOAP::Transport::HTTP::Server - Server interface to HTTP transport
SOAP::Transport::HTTP::CGI - CGI implementation of server interface
SOAP::Transport::HTTP::Daemon - Daemon implementation of server interface
SOAP::Transport::HTTP::Apache - mod_perl implementation of server interface
- lib/SOAP/Transport/POP3.pm
-
SOAP::Transport::POP3::Server - Server interface to POP3 protocol
- lib/SOAP/Transport/MAILTO.pm
-
SOAP::Transport::MAILTO::Client - Client interface to SMTP/sendmail
- lib/SOAP/Transport/LOCAL.pm
-
SOAP::Transport::LOCAL::Client - Client interface to local transport
- lib/SOAP/Transport/TCP.pm
-
SOAP::Transport::TCP::Server - Server interface to TCP protocol
SOAP::Transport::TCP::Client - Client interface to TCP protocol
- lib/SOAP/Transport/IO.pm
-
SOAP::Transport::IO::Server - Server interface to IO transport
All accessor methods return the current value when called with no arguments,
while returning the object reference itself when called with a new value.
This allows the set-attribute calls to be chained together.
- new(optional key/value pairs)
-
$client = SOAP::Lite->new(proxy => $endpoint)
Constructor. Many of the accessor methods defined here may be initialized at
creation by providing their name as a key, followed by the desired value.
The example provides the value for the proxy element of the client.
- transport(optional transport object)
-
$transp = $client->transport( );
Gets or sets the transport object used for sending/receiving SOAP messages.
See the SOAP::Transport manpage for details.
- serializer(optional serializer object)
-
$serial = $client->serializer( )
Gets or sets the serializer object used for creating XML messages.
See the SOAP::Serializer manpage for details.
- packager(optional packager object)
-
$packager = $client->packager( )
Provides access to the SOAP::Packager object that the client uses to manage
the use of attachments. The default packager is a MIME packager, but unless
you specify parts to send, no MIME formatting will be done.
See also: the SOAP::Packager manpage.
- proxy(endpoint, optional extra arguments)
-
$client->proxy('http://soap.xml.info/ endPoint');
The proxy is the server or endpoint to which the client is going to connect.
This method allows the setting of the endpoint, along with any extra
information that the transport object may need when communicating the request.
This method is actually an alias to the proxy method of the SOAP::Transport manpage.
It is the same as typing:
$client->transport( )->proxy(...arguments);
Extra parameters can be passed to proxy() - see below.
- compress_threshold
-
See COMPRESSION in the HTTP::Transport manpage.
- All initialization options from the underlying transport layer
-
The options for
HTTP(S) are the same as for LWP::UserAgent's new() method.
A common option is to create a instance of HTTP::Cookies and pass it as
cookie_jar option:
my $cookie_jar = HTTP::Cookies->new()
$client->proxy('http://www.example.org/webservice',
cookie_jar => $cookie_jar,
);
For example, if you wish to set the HTTP timeout for a SOAP::Lite client to 5
seconds, use the following code:
my $soap = SOAP::Lite
->uri($uri)
->proxy($proxyUrl, timeout => 5 );
See the LWP::UserAgent manpage.
- endpoint(optional new endpoint address)
-
$client->endpoint('http://soap.xml.info/ newPoint')
It may be preferable to set a new endpoint without the additional work of
examining the new address for protocol information and checking to ensure the
support code is loaded and available. This method allows the caller to change
the endpoint that the client is currently set to connect to, without
reloading the relevant transport code. Note that the proxy method must have
been called before this method is used.
- service(service URL)
-
$client->service('http://svc.perl.org/Svc.wsdl');
SOAP::Lite offers some support for creating method stubs from service
descriptions. At present, only WSDL support is in place. This method loads
the specified WSDL schema and uses it as the basis for generating stubs.
- outputxml(boolean)
-
$client->outputxml('true');
When set to a true value, the raw XML is returned by the call to a remote
method.
The default is to return a the SOAP::SOM manpage object (false).
- autotype(boolean)
-
$client->autotype(0);
This method is a shortcut for:
$client->serializer->autotype(boolean);
By default, the serializer tries to automatically deduce types for the data
being sent in a message. Setting a false value with this method disables the
behavior.
- readable(boolean)
-
$client->readable(1);
This method is a shortcut for:
$client->serializer->readable(boolean);
When this is used to set a true value for this property, the generated XML
sent to the endpoint has extra characters (spaces and new lines) added in to
make the XML itself more readable to human eyes (presumably for debugging).
The default is to not send any additional characters.
- headerattr(hash reference of attributes)
-
$obj->headerattr({ attr1 => 'value' });
Allows for the setting of arbitrary attributes on the header object. Keep in mind the requirement that
any attributes not natively known to SOAP must be namespace-qualified.
If using $session->call ($method, $callData, $callHeader), SOAP::Lite serializes information as
<soap:Envelope>
<soap:Header>
<userId>xxxxx</userId>
<password>yyyyy</password>
</soap:Header>
<soap:Body>
<myMethod xmlns="http://www.someuri.com">
<foo />
</myMethod>
</soap:Body>
</soap:Envelope>
The attributes, given to headerattr are placed into the Header as
<soap:Header attr1="value">
- bodyattr(hash reference of attributes)
-
$obj->bodyattr({ attr1 => 'value' });
Allows for the setting of arbitrary attributes on the body object. Keep in mind the requirement that
any attributes not natively known to SOAP must be namespace-qualified.
See headerattr
- default_ns($uri)
-
Sets the default namespace for the request to the specified uri. This
overrides any previous namespace declaration that may have been set using a
previous call to
ns() or default_ns() . Setting the default namespace
causes elements to be serialized without a namespace prefix, like this:
<soap:Envelope>
<soap:Body>
<myMethod xmlns="http://www.someuri.com">
<foo />
</myMethod>
</soap:Body>
</soap:Envelope>
Some .NET web services have been reported to require this XML namespace idiom.
- ns($uri,$prefix=undef)
-
Sets the namespace uri and optionally the namespace prefix for the request to
the specified values. This overrides any previous namespace declaration that
may have been set using a previous call to
ns() or default_ns() .
If a prefix is not specified, one will be generated for you automatically.
Setting the namespace causes elements to be serialized with a declared
namespace prefix, like this:
<soap:Envelope>
<soap:Body>
<my:myMethod xmlns:my="http://www.someuri.com">
<my:foo />
</my:myMethod>
</soap:Body>
</soap:Envelope>
- use_prefix(boolean)
-
Deprecated. Use the
ns() and default_ns methods described above.
Shortcut for serializer->use_prefix() . This lets you turn on/off the
use of a namespace prefix for the children of the /Envelope/Body element.
Default is 'true'.
When use_prefix is set to 'true', serialized XML will look like this:
<SOAP-ENV:Envelope ...attributes skipped>
<SOAP-ENV:Body>
<namesp1:mymethod xmlns:namesp1="urn:MyURI" />
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
When use_prefix is set to 'false', serialized XML will look like this:
<SOAP-ENV:Envelope ...attributes skipped>
<SOAP-ENV:Body>
<mymethod xmlns="urn:MyURI" />
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Some .NET web services have been reported to require this XML namespace idiom.
- soapversion(optional value)
-
$client->soapversion('1.2');
If no parameter is given, returns the current version of SOAP that is being
used by the client object to encode requests. If a parameter is given, the
method attempts to set that as the version of SOAP being used.
The value should be either 1.1 or 1.2.
- envprefix(QName)
-
$client->envprefix('env');
This method is a shortcut for:
$client->serializer->envprefix(QName);
Gets or sets the namespace prefix for the SOAP namespace. The default is
SOAP.
The prefix itself has no meaning, but applications may wish to chose one
explicitly to denote different versions of SOAP or the like.
- encprefix(QName)
-
$client->encprefix('enc');
This method is a shortcut for:
$client->serializer->encprefix(QName);
Gets or sets the namespace prefix for the encoding rules namespace.
The default value is SOAP-ENC.
While it may seem to be an unnecessary operation to set a value that isn't
relevant to the message, such as the namespace labels for the envelope and
encoding URNs, the ability to set these labels explicitly can prove to be a
great aid in distinguishing and debugging messages on the server side of
operations.
- encoding(encoding URN)
-
$client->encoding($soap_12_encoding_URN);
This method is a shortcut for:
$client->serializer->encoding(args);
Where the earlier method dealt with the label used for the attributes related
to the SOAP encoding scheme, this method actually sets the URN to be specified
as the encoding scheme for the message. The default is to specify the encoding
for SOAP 1.1, so this is handy for applications that need to encode according
to SOAP 1.2 rules.
- typelookup
-
$client->typelookup;
This method is a shortcut for:
$client->serializer->typelookup;
Gives the application access to the type-lookup table from the serializer
object. See the section on the SOAP::Serializer manpage.
- uri(service specifier)
-
Deprecated - the
uri subroutine is deprecated in order to provide a more
intuitive naming scheme for subroutines that set namespaces. In the future,
you will be required to use either the ns() or default_ns() subroutines
instead of uri() .
$client->uri($service_uri);
This method is a shortcut for:
$client->serializer->uri(service);
The URI associated with this accessor on a client object is the
service-specifier for the request, often encoded for HTTP-based requests as
the SOAPAction header. While the names may seem confusing, this method
doesn't specify the endpoint itself. In most circumstances, the uri refers
to the namespace used for the request.
Often times, the value may look like a valid URL. Despite this, it doesn't
have to point to an existing resource (and often doesn't). This method sets
and retrieves this value from the object. Note that no transport code is
triggered by this because it has no direct effect on the transport of the
object.
- multirefinplace(boolean)
-
$client->multirefinplace(1);
This method is a shortcut for:
$client->serializer->multirefinplace(boolean);
Controls how the serializer handles values that have multiple references to
them. Recall from previous SOAP chapters that a value may be tagged with an
identifier, then referred to in several places. When this is the case for a
value, the serializer defaults to putting the data element towards the top of
the message, right after the opening tag of the method-specification. It is
serialized as a standalone entity with an ID that is then referenced at the
relevant places later on. If this method is used to set a true value, the
behavior is different. When the multirefinplace attribute is true, the data
is serialized at the first place that references it, rather than as a separate
element higher up in the body. This is more compact but may be harder to read
or trace in a debugging environment.
- parts( ARRAY )
-
Used to specify an array of the MIME::Entity manpage's to be attached to the
transmitted SOAP message. Attachments that are returned in a response can be
accessed by
SOAP::SOM::parts() .
- self
-
$ref = SOAP::Lite->self;
Returns an object reference to the default global object the SOAP::Lite
package maintains. This is the object that processes many of the arguments
when provided on the use line.
The following method isn't an accessor style of method but neither does it fit
with the group that immediately follows it:
- call(arguments)
-
$client->call($method => @arguments);
As has been illustrated in previous chapters, the SOAP::Lite client objects
can manage remote calls with auto-dispatching using some of Perl's more
elaborate features. call is used when the application wants a greater degree
of control over the details of the call itself. The method may be built up
from a the SOAP::Data manpage object, so as to allow full control over the namespace
associated with the tag, as well as other attributes like encoding. This is
also important for calling methods that contain characters not allowable in
Perl function names, such as A.B.C.
The next four methods used in the SOAP::Lite class are geared towards
handling the types of events than can occur during the message lifecycle. Each
of these sets up a callback for the event in question:
- on_action(callback)
-
$client->on_action(sub { qq("$_[0]") });
Triggered when the transport object sets up the SOAPAction header for an
HTTP-based call. The default is to set the header to the string, uri#method,
in which URI is the value set by the uri method described earlier, and method
is the name of the method being called. When called, the routine referenced
(or the closure, if specified as in the example) is given two arguments, uri
and method, in that order.
.NET web services usually expect / as separator for uri and method .
To change SOAP::Lite's behaviour to use uri/method as SOAPAction header, use
the following code:
$client->on_action( sub { join '/', @_ } );
- on_fault(callback)
-
$client->on_fault(sub { popup_dialog($_[1]) });
Triggered when a method call results in a fault response from the server.
When it is called, the argument list is first the client object itself,
followed by the object that encapsulates the fault. In the example, the fault
object is passed (without the client object) to a hypothetical GUI function
that presents an error dialog with the text of fault extracted from the object
(which is covered shortly under the the SOAP::SOM manpage methods).
- on_nonserialized(callback)
-
$client->on_nonserialized(sub { die "$_[0]?!?" });
Occasionally, the serializer may be given data it can't turn into SOAP-savvy
XML; for example, if a program bug results in a code reference or something
similar being passed in as a parameter to method call. When that happens, this
callback is activated, with one argument. That argument is the data item that
could not be understood. It will be the only argument. If the routine returns,
the return value is pasted into the message as the serialization. Generally,
an error is in order, and this callback allows for control over signaling that
error.
- on_debug(callback)
-
$client->on_debug(sub { print @_ });
Deprecated. Use the global +debug and +trace facilities described in
the SOAP::Trace manpage
Note that this method will not work as expected: Instead of affecting the
debugging behaviour of the object called on, it will globally affect the
debugging behaviour for all objects of that class.
This chapter guides you to writing a SOAP client by example.
The SOAP service to be accessed is a simple variation of the well-known
hello world program. It accepts two parameters, a name and a given name,
and returns ``Hello $given_name $name''.
We will use ``Martin Kutter'' as the name for the call, so all variants will
print the following message on success:
Hello Martin Kutter!
There are three common (and one less common) variants of SOAP messages.
These address the message style (positional parameters vs. specified message
documents) and encoding (as-is vs. typed).
The different message styles are:
- rpc/encoded
Typed, positional parameters. Widely used in scripting languages.
The type of the arguments is included in the message.
Arrays and the like may be encoded using SOAP encoding rules (or others).
- rpc/literal
As-is, positional parameters. The type of arguments is defined by some
pre-exchanged interface definition.
- document/encoded
Specified message with typed elements. Rarely used.
- document/literal
Specified message with as-is elements. The message specification and
element types are defined by some pre-exchanged interface definition.
As of 2008, document/literal has become the predominant SOAP message
variant. rpc/literal and rpc/encoded are still in use, mainly with scripting
languages, while document/encoded is hardly used at all.
You will see clients for the rpc/encoded and document/literal SOAP variants in
this section.
Rpc/encoded is most popular with scripting languages like perl, php and python
without the use of a WSDL. Usual method descriptions look like this:
Method: sayHello(string, string)
Parameters:
name: string
givenName: string
Such a description usually means that you can call a method named ``sayHello''
with two positional parameters, ``name'' and ``givenName'', which both are
strings.
The message corresponding to this description looks somewhat like this:
<sayHello xmlns="urn:HelloWorld">
<s-gensym01 xsi:type="xsd:string">Kutter</s-gensym01>
<s-gensym02 xsi:type="xsd:string">Martin</s-gensym02>
</sayHello>
Any XML tag names may be used instead of the ``s-gensym01'' stuff - parameters
are positional, the tag names have no meaning.
A client producing such a call is implemented like this:
use SOAP::Lite;
my $soap = SOAP::Lite->new( proxy => 'http://localhost:81/soap-wsdl-test/helloworld.pl');
$soap->default_ns('urn:HelloWorld');
my $som = $soap->call('sayHello', 'Kutter', 'Martin');
die $som->faultstring if ($som->fault);
print $som->result, "\n";
You can of course use a one-liner, too...
Sometimes, rpc/encoded interfaces are described with WSDL definitions.
A WSDL accepting ``named'' parameters with rpc/encoded looks like this:
<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:s0="urn:HelloWorld"
targetNamespace="urn:HelloWorld"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema targetNamespace="urn:HelloWorld">
</s:schema>
</types>
<message name="sayHello">
<part name="name" type="s:string" />
<part name="givenName" type="s:string" />
</message>
<message name="sayHelloResponse">
<part name="sayHelloResult" type="s:string" />
</message>
<portType name="Service1Soap">
<operation name="sayHello">
<input message="s0:sayHello" />
<output message="s0:sayHelloResponse" />
</operation>
</portType>
<binding name="Service1Soap" type="s0:Service1Soap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="rpc" />
<operation name="sayHello">
<soap:operation soapAction="urn:HelloWorld#sayHello"/>
<input>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="HelloWorld">
<port name="HelloWorldSoap" binding="s0:Service1Soap">
<soap:address location="http://localhost:81/soap-wsdl-test/helloworld.pl" />
</port>
</service>
</definitions>
The message corresponding to this schema looks like this:
<sayHello xmlns="urn:HelloWorld">
<name xsi:type="xsd:string">Kutter</name>
<givenName xsi:type="xsd:string">Martin</givenName>
</sayHello>
A web service client using this schema looks like this:
use SOAP::Lite;
my $soap = SOAP::Lite->service("file:say_hello_rpcenc.wsdl");
eval { my $result = $soap->sayHello('Kutter', 'Martin'); };
if ($@) {
die $@;
}
print $som->result();
You may of course also use the following one-liner:
perl -MSOAP::Lite -e 'print SOAP::Lite->service("file:say_hello_rpcenc.wsdl")\
->sayHello('Kutter', 'Martin'), "\n";'
A web service client (without a service description) looks like this.
use SOAP::Lite;
my $soap = SOAP::Lite->new( proxy => 'http://localhost:81/soap-wsdl-test/helloworld.pl');
$soap->default_ns('urn:HelloWorld');
my $som = $soap->call('sayHello',
SOAP::Data->name('name')->value('Kutter'),
SOAP::Data->name('givenName')->value('Martin')
);
die $som->faultstring if ($som->fault);
print $som->result, "\n";
SOAP web services using the document/literal message encoding are usually
described by some Web Service Definition. Our web service has the following
WSDL description:
<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:s0="urn:HelloWorld"
targetNamespace="urn:HelloWorld"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema targetNamespace="urn:HelloWorld">
<s:complexType name="sayHello">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="name"
type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="givenName"
type="s:string" nillable="1" />
</s:sequence>
</s:complexType>
<s:complexType name="sayHelloResponse">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="sayHelloResult"
type="s:string" />
</s:sequence>
</s:complexType>
</s:schema>
</types>
<message name="sayHello">
<part name="parameters" type="s0:sayHello" />
</message>
<message name="sayHelloResponse">
<part name="parameters" type="s0:sayHelloResponse" />
</message>
<portType name="Service1Soap">
<operation name="sayHello">
<input message="s0:sayHello" />
<output message="s0:sayHelloResponse" />
</operation>
</portType>
<binding name="Service1Soap" type="s0:Service1Soap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="rpc" />
<operation name="sayHello">
<soap:operation soapAction="urn:HelloWorld#sayHello"/>
<input>
<soap:body use="literal" namespace="urn:HelloWorld"/>
</input>
<output>
<soap:body use="literal" namespace="urn:HelloWorld"/>
</output>
</operation>
</binding>
<service name="HelloWorld">
<port name="HelloWorldSoap" binding="s0:Service1Soap">
<soap:address location="http://localhost:80//helloworld.pl" />
</port>
</service>
</definitions>
The XML message (inside the SOAP Envelope) look like this:
<ns0:sayHello xmlns:ns0="urn:HelloWorld">
<parameters>
<name>Kutter</name>
<givenName>Martin</givenName>
</parameters>
</ns0:sayHello>
<sayHelloResponse xmlns:ns0="urn:HelloWorld">
<parameters>
<sayHelloResult>Hello Martin Kutter!</sayHelloResult>
</parameters>
</sayHelloResponse>
This is the SOAP::Lite implementation for the web service client:
use SOAP::Lite +trace;
my $soap = SOAP::Lite->new( proxy => 'http://localhost:80/helloworld.pl');
$soap->on_action( sub { "urn:HelloWorld#sayHello" });
$soap->autotype(0)->readable(1);
$soap->default_ns('urn:HelloWorld');
my $som = $soap->call('sayHello', SOAP::Data->name('parameters')->value(
\SOAP::Data->value([
SOAP::Data->name('name')->value( 'Kutter' ),
SOAP::Data->name('givenName')->value('Martin'),
]))
);
die $som->fault->{ faultstring } if ($som->fault);
print $som->result, "\n";
SOAP web services using the document/literal message encoding are usually
described by some Web Service Definition. Our web service has the following
WSDL description:
<definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:s0="urn:HelloWorld"
targetNamespace="urn:HelloWorld"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema targetNamespace="urn:HelloWorld">
<s:element name="sayHello">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="name" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="givenName" type="s:string" nillable="1" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="sayHelloResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="sayHelloResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
</types>
<message name="sayHelloSoapIn">
<part name="parameters" element="s0:sayHello" />
</message>
<message name="sayHelloSoapOut">
<part name="parameters" element="s0:sayHelloResponse" />
</message>
<portType name="Service1Soap">
<operation name="sayHello">
<input message="s0:sayHelloSoapIn" />
<output message="s0:sayHelloSoapOut" />
</operation>
</portType>
<binding name="Service1Soap" type="s0:Service1Soap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="sayHello">
<soap:operation soapAction="urn:HelloWorld#sayHello"/>
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="HelloWorld">
<port name="HelloWorldSoap" binding="s0:Service1Soap">
<soap:address location="http://localhost:80//helloworld.pl" />
</port>
</service>
</definitions>
The XML message (inside the SOAP Envelope) look like this:
<sayHello xmlns="urn:HelloWorld">
<name>Kutter</name>
<givenName>Martin</givenName>
</sayHello>
<sayHelloResponse>
<sayHelloResult>Hello Martin Kutter!</sayHelloResult>
</sayHelloResponse>
You can call this web service with the following client code:
use SOAP::Lite;
my $soap = SOAP::Lite->new( proxy => 'http://localhost:80/helloworld.pl');
$soap->on_action( sub { "urn:HelloWorld#sayHello" });
$soap->autotype(0);
$soap->default_ns('urn:HelloWorld');
my $som = $soap->call("sayHello",
SOAP::Data->name('name')->value( 'Kutter' ),
SOAP::Data->name('givenName')->value('Martin'),
);
die $som->fault->{ faultstring } if ($som->fault);
print $som->result, "\n";
You may have noticed that there's little difference between the rpc/encoded,
rpc/literal and the document/literal example's implementation. In fact, from
SOAP::Lite's point of view, the only differences between rpc/literal and
document/literal that parameters are always named.
In our example, the rpc/encoded variant already used named parameters (by
using two messages), so there's no difference at all.
You may have noticed the somewhat strange idiom for passing a list of named
parameters in the rpc/literal example:
my $som = $soap->call('sayHello', SOAP::Data->name('parameters')->value(
\SOAP::Data->value([
SOAP::Data->name('name')->value( 'Kutter' ),
SOAP::Data->name('givenName')->value('Martin'),
]))
);
While SOAP::Data provides full control over the XML generated, passing
hash-like structures require additional coding.
See the SOAP::Server manpage, or the SOAP::Transport manpage.
SOAP::Lite features support for the SOAP with Attachments specification.
Currently, SOAP::Lite only supports MIME based attachments. DIME based
attachments are yet to be fully functional.
SOAP::Lite clients can specify attachments to be sent along with a request
by using the SOAP::Lite::parts() method, which takes as an argument an
ARRAY of MIME::Entity 's.
use SOAP::Lite;
use MIME::Entity;
my $ent = build MIME::Entity
Type => "image/gif",
Encoding => "base64",
Path => "somefile.gif",
Filename => "saveme.gif",
Disposition => "attachment";
my $som = SOAP::Lite
->uri($SOME_NAMESPACE)
->parts([ $ent ])
->proxy($SOME_HOST)
->some_method(SOAP::Data->name("foo" => "bar"));
A client accessing attachments that were returned in a response by using the
SOAP::SOM::parts() accessor.
use SOAP::Lite;
use MIME::Entity;
my $soap = SOAP::Lite
->uri($NS)
->proxy($HOST);
my $som = $soap->foo();
foreach my $part (${$som->parts}) {
print $part->stringify;
}
Servers, like clients, use the SOAP::SOM module to access attachments
transmitted to it.
package Attachment;
use SOAP::Lite;
use MIME::Entity;
use strict;
use vars qw(@ISA);
@ISA = qw(SOAP::Server::Parameters);
sub someMethod {
my $self = shift;
my $envelope = pop;
foreach my $part (@{$envelope->parts}) {
print "AttachmentService: attachment found! (".ref($part).")\n";
}
# do something
}
Servers wishing to return an attachment to the calling client need only return
MIME::Entity objects along with SOAP::Data elements, or any other data
intended for the response.
package Attachment;
use SOAP::Lite;
use MIME::Entity;
use strict;
use vars qw(@ISA);
@ISA = qw(SOAP::Server::Parameters);
sub someMethod {
my $self = shift;
my $envelope = pop;
my $ent = build MIME::Entity
'Id' => "<1234>",
'Type' => "text/xml",
'Path' => "some.xml",
'Filename' => "some.xml",
'Disposition' => "attachment";
return SOAP::Data->name("foo" => "blah blah blah"),$ent;
}
Though this feature looks similar to
autodispatch they have (almost)
nothing in common. This capability allows you specify default settings so that
all objects created after that will be initialized with the proper default
settings.
If you wish to provide common proxy() or uri() settings for all
SOAP::Lite objects in your application you may do:
use SOAP::Lite
proxy => 'http://localhost/cgi-bin/soap.cgi',
uri => 'http://my.own.com/My/Examples';
my $soap1 = new SOAP::Lite; # will get the same proxy()/uri() as above
print $soap1->getStateName(1)->result;
my $soap2 = SOAP::Lite->new; # same thing as above
print $soap2->getStateName(2)->result;
# or you may override any settings you want
my $soap3 = SOAP::Lite->proxy('http://localhost/');
print $soap3->getStateName(1)->result;
Any SOAP::Lite properties can be propagated this way. Changes in object
copies will not affect global settings and you may still change global
settings with SOAP::Lite->self call which returns reference to global
object. Provided parameter will update this object and you can even set it to
undef :
SOAP::Lite->self(undef);
The use SOAP::Lite syntax also lets you specify default event handlers for
your code. If you have different SOAP objects and want to share the same
on_action() (or on_fault() for that matter) handler. You can specify
on_action() during initialization for every object, but you may also do:
use SOAP::Lite
on_action => sub {sprintf '%s#%s', @_};
and this handler will be the default handler for all your SOAP objects. You
can override it if you specify a handler for a particular object. See t/*.t
for example of on_fault() handler.
Be warned, that since use ... is executed at compile time all use
statements will be executed before script execution that can make
unexpected results. Consider code:
use SOAP::Lite proxy => 'http://localhost/';
print SOAP::Lite->getStateName(1)->result;
use SOAP::Lite proxy => 'http://localhost/cgi-bin/soap.cgi';
print SOAP::Lite->getStateName(1)->result;
Both SOAP calls will go to 'http://localhost/cgi-bin/soap.cgi' . If you
want to execute use at run-time, put it in eval :
eval "use SOAP::Lite proxy => 'http://localhost/cgi-bin/soap.cgi'; 1" or die;
Or alternatively,
SOAP::Lite->self->proxy('http://localhost/cgi-bin/soap.cgi');
One feature of SOAP::Lite is the ability to control the maximum size of a
message a SOAP::Lite server will be allowed to process. To control this
feature simply define $SOAP::Constants::MAX_CONTENT_SIZE in your code like
so:
use SOAP::Transport::HTTP;
use MIME::Entity;
$SOAP::Constants::MAX_CONTENT_SIZE = 10000;
SOAP::Transport::HTTP::CGI
->dispatch_to('TemperatureService')
->handle;
SOAP::Lite gives you access to all parameters (both in/out and out) and
also does some additional work for you. Lets consider following example:
<mehodResponse>
<res1>name1</res1>
<res2>name2</res2>
<res3>name3</res3>
</mehodResponse>
In that case:
$result = $r->result; # gives you 'name1'
$paramout1 = $r->paramsout; # gives you 'name2', because of scalar context
$paramout1 = ($r->paramsout)[0]; # gives you 'name2' also
$paramout2 = ($r->paramsout)[1]; # gives you 'name3'
or
@paramsout = $r->paramsout; # gives you ARRAY of out parameters
$paramout1 = $paramsout[0]; # gives you 'res2', same as ($r->paramsout)[0]
$paramout2 = $paramsout[1]; # gives you 'res3', same as ($r->paramsout)[1]
Generally, if server returns return (1,2,3) you will get 1 as the result
and 2 and 3 as out parameters.
If the server returns return [1,2,3] you will get an ARRAY reference from
result() and undef from paramsout() .
Results can be arbitrary complex: they can be an array references, they can be
objects, they can be anything and still be returned by result() . If only
one parameter is returned, paramsout() will return undef .
Furthermore, if you have in your output parameters a parameter with the same
signature (name+type) as in the input parameters this parameter will be mapped
into your input automatically. For example:
Server Code:
sub mymethod {
shift; # object/class reference
my $param1 = shift;
my $param2 = SOAP::Data->name('myparam' => shift() * 2);
return $param1, $param2;
}
Client Code:
$a = 10;
$b = SOAP::Data->name('myparam' => 12);
$result = $soap->mymethod($a, $b);
After that, $result == 10 and $b->value == 24 ! Magic? Sort of.
Autobinding gives it to you. That will work with objects also with one
difference: you do not need to worry about the name and the type of object
parameter. Consider the PingPong example (examples/My/PingPong.pm
and examples/pingpong.pl):
Server Code:
package My::PingPong;
sub new {
my $self = shift;
my $class = ref($self) || $self;
bless {_num=>shift} => $class;
}
sub next {
my $self = shift;
$self->{_num}++;
}
Client Code:
use SOAP::Lite +autodispatch =>
uri => 'urn:',
proxy => 'http://localhost/';
my $p = My::PingPong->new(10); # $p->{_num} is 10 now, real object returned
print $p->next, "\n"; # $p->{_num} is 11 now!, object autobinded
Let us scrutinize the deployment process. When designing your SOAP server you
can consider two kind of deployment: static and dynamic. For both,
static and dynamic, you should specify MODULE , MODULE::method ,
method or PATH/ when creating use ing the SOAP::Lite module. The
difference between static and dynamic deployment is that in case of 'dynamic',
any module which is not present will be loaded on demand. See the
SECURITY section for detailed description.
When statically deploying a SOAP Server, you need to know all modules handling
SOAP requests before.
Dynamic deployment allows extending your SOAP Server's interface by just
installing another module into the dispatch_to path (see below).
use SOAP::Transport::HTTP;
use My::Examples; # module is preloaded
SOAP::Transport::HTTP::CGI
# deployed module should be present here or client will get
# 'access denied'
-> dispatch_to('My::Examples')
-> handle;
For static deployment you should specify the MODULE name directly.
You should also use static binding when you have several different classes in
one file and want to make them available for SOAP calls.
use SOAP::Transport::HTTP;
# name is unknown, module will be loaded on demand
SOAP::Transport::HTTP::CGI
# deployed module should be present here or client will get 'access denied'
-> dispatch_to('/Your/Path/To/Deployed/Modules', 'My::Examples')
-> handle;
For dynamic deployment you can specify the name either directly (in that case
it will be require d without any restriction) or indirectly, with a PATH. In
that case, the ONLY path that will be available will be the PATH given to the
dispatch_to() method). For information how to handle this situation see
SECURITY section.
dispatch_to(
# dynamic dispatch that allows access to ALL modules in specified directory
PATH/TO/MODULES
# 1. specifies directory
# -- AND --
# 2. gives access to ALL modules in this directory without limits
# static dispatch that allows access to ALL methods in particular MODULE
MODULE
# 1. gives access to particular module (all available methods)
# PREREQUISITES:
# module should be loaded manually (for example with 'use ...')
# -- OR --
# you can still specify it in PATH/TO/MODULES
# static dispatch that allows access to particular method ONLY
MODULE::method
# same as MODULE, but gives access to ONLY particular method,
# so there is not much sense to use both MODULE and MODULE::method
# for the same MODULE
);
In addition to this SOAP::Lite also supports an experimental syntax that
allows you to bind a specific URL or SOAPAction to a CLASS/MODULE or object.
For example:
dispatch_with({
URI => MODULE, # 'http://www.soaplite.com/' => 'My::Class',
SOAPAction => MODULE, # 'http://www.soaplite.com/method' => 'Another::Class',
URI => object, # 'http://www.soaplite.com/obj' => My::Class->new,
})
URI is checked before SOAPAction . You may use both the dispatch_to()
and dispatch_with() methods in the same server, but note that
dispatch_with() has a higher order of precedence. dispatch_to() will be
checked only after URI and SOAPAction has been checked.
See also:
EXAMPLE APACHE::REGISTRY USAGE,
SECURITY
SOAP::Lite provides you option to enable transparent compression over the
wire. Compression can be enabled by specifying a threshold value (in the form
of kilobytes) for compression on both the client and server sides:
Note: Compression currently only works for HTTP based servers and clients.
Client Code
print SOAP::Lite
->uri('http://localhost/My/Parameters')
->proxy('http://localhost/', options => {compress_threshold => 10000})
->echo(1 x 10000)
->result;
Server Code
my $server = SOAP::Transport::HTTP::CGI
->dispatch_to('My::Parameters')
->options({compress_threshold => 10000})
->handle;
For more information see COMPRESSION in
the HTTP::Transport manpage.
For security reasons, the existing path for Perl modules (@INC ) will be
disabled once you have chosen dynamic deployment and specified your own
PATH/ . If you wish to access other modules in your included package you
have several options:
-
Switch to static linking:
use MODULE;
$server->dispatch_to('MODULE');
Which can also be useful when you want to import something specific from the
deployed modules:
use MODULE qw(import_list);
-
Change
use to require . The path is only unavailable during the
initialization phase. It is available once more during execution. Therefore,
if you utilize require somewhere in your package, it will work.
-
Wrap
use in an eval block:
eval 'use MODULE qw(import_list)'; die if $@;
-
Set your include path in your package and then specify
use . Don't forget to
put @INC in a BEGIN{} block or it won't work. For example,
BEGIN { @INC = qw(my_directory); use MODULE }
In order to use a .NET client with a SOAP::Lite server, be sure you use fully
qualified names for your return values. For example:
return SOAP::Data->name('myname')
->type('string')
->uri($MY_NAMESPACE)
->value($output);
In addition see comment about default encoding in .NET Web Services below.
If experiencing problems when using a SOAP::Lite client to call a .NET Web
service, it is recommended you check, or adhere to all of the following
recommendations:
- Declare a proper soapAction in your call
-
For example, use
on_action( sub { 'http://www.myuri.com/WebService.aspx#someMethod'; } ) .
- Disable charset definition in Content-type header
-
Some users have said that Microsoft .NET prefers the value of
the Content-type header to be a mimetype exclusively, but SOAP::Lite specifies
a character set in addition to the mimetype. This results in an error similar
to:
Server found request content type to be 'text/xml; charset=utf-8',
but expected 'text/xml'
To turn off this behavior specify use the following code:
use SOAP::Lite;
$SOAP::Constants::DO_NOT_USE_CHARSET = 1;
# The rest of your code
- Use fully qualified name for method parameters
-
For example, the following code is preferred:
SOAP::Data->name(Query => 'biztalk')
->uri('http://tempuri.org/')
As opposed to:
SOAP::Data->name('Query' => 'biztalk')
- Place method in default namespace
-
For example, the following code is preferred:
my $method = SOAP::Data->name('add')
->attr({xmlns => 'http://tempuri.org/'});
my @rc = $soap->call($method => @parms)->result;
As opposed to:
my @rc = $soap->call(add => @parms)->result;
# -- OR --
my @rc = $soap->add(@parms)->result;
- Disable use of explicit namespace prefixes
-
Some user's have reported that .NET will simply not parse messages that use
namespace prefixes on anything but SOAP elements themselves. For example, the
following XML would not be parsed:
<SOAP-ENV:Envelope ...attributes skipped>
<SOAP-ENV:Body>
<namesp1:mymethod xmlns:namesp1="urn:MyURI" />
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
SOAP::Lite allows users to disable the use of explicit namespaces through the
use_prefix() method. For example, the following code:
$som = SOAP::Lite->uri('urn:MyURI')
->proxy($HOST)
->use_prefix(0)
->myMethod();
Will result in the following XML, which is more palatable by .NET:
<SOAP-ENV:Envelope ...attributes skipped>
<SOAP-ENV:Body>
<mymethod xmlns="urn:MyURI" />
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
- Modify your .NET server, if possible
-
Stefan Pharies <stefanph@microsoft.com>:
SOAP::Lite uses the SOAP encoding (section 5 of the soap 1.1 spec), and
the default for .NET Web Services is to use a literal encoding. So
elements in the request are unqualified, but your service expects them to
be qualified. .Net Web Services has a way for you to change the expected
message format, which should allow you to get your interop working.
At the top of your class in the asmx, add this attribute (for Beta 1):
[SoapService(Style=SoapServiceStyle.RPC)]
Another source said it might be this attribute (for Beta 2):
[SoapRpcService]
Full Web Service text may look like:
<%@ WebService Language="C#" Class="Test" %>
using System;
using System.Web.Services;
using System.Xml.Serialization;
[SoapService(Style=SoapServiceStyle.RPC)]
public class Test : WebService {
[WebMethod]
public int add(int a, int b) {
return a + b;
}
}
Another example from Kirill Gavrylyuk <kirillg@microsoft.com>:
``You can insert [SoapRpcService()] attribute either on your class or on
operation level''.
<%@ WebService Language=CS class="DataType.StringTest"%>
namespace DataType {
using System;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Services.Description;
[SoapRpcService()]
public class StringTest: WebService {
[WebMethod]
[SoapRpcMethod()]
public string RetString(string x) {
return(x);
}
}
}
Example from Yann Christensen <yannc@microsoft.com>:
using System;
using System.Web.Services;
using System.Web.Services.Protocols;
namespace Currency {
[WebService(Namespace="http://www.yourdomain.com/example")]
[SoapRpcService]
public class Exchange {
[WebMethod]
public double getRate(String country, String country2) {
return 122.69;
}
}
}
Special thanks goes to the following people for providing the above
description and details on .NET interoperability issues:
Petr Janata <petr.janata@i.cz>,
Stefan Pharies <stefanph@microsoft.com>,
Brian Jepson <bjepson@jepstone.net>, and others
- SOAP::Lite serializes "18373" as an integer, but I want it to be a string!
-
SOAP::Lite guesses datatypes from the content provided, using a set of
common-sense rules. These rules are not 100% reliable, though they fit for
most data.
You may force the type by passing a SOAP::Data object with a type specified:
my $proxy = SOAP::Lite->proxy('http://www.example.org/soapservice');
my $som = $proxy->myMethod(
SOAP::Data->name('foo')->value(12345)->type('string')
);
You may also change the precedence of the type-guessing rules. Note that this
means fiddling with SOAP::Lite's internals - this may not work as
expected in future versions.
The example above forces everything to be encoded as string (this is because
the string test is normally last and always returns true):
my @list = qw(-1 45 foo bar 3838);
my $proxy = SOAP::Lite->uri($uri)->proxy($proxyUrl);
my $lookup = $proxy->serializer->typelookup;
$lookup->{string}->[0] = 0;
$proxy->serializer->typelookup($lookup);
$proxy->myMethod(\@list);
See SOAP::Serializer for more details.
- +autodispatch doesn't work in Perl 5.8
-
There is a bug in Perl 5.8's
UNIVERSAL::AUTOLOAD functionality that
prevents the +autodispatch functionality from working properly. The
workaround is to use dispatch_from instead. Where you might normally do
something like this:
use Some::Module;
use SOAP::Lite +autodispatch =>
uri => 'urn:Foo'
proxy => 'http://...';
You would do something like this:
use SOAP::Lite dispatch_from(Some::Module) =>
uri => 'urn:Foo'
proxy => 'http://...';
- Problems using SOAP::Lite's COM Interface
-
- Can't call method "server" on undefined value
-
You probably did not register Lite.dll using
regsvr32 Lite.dll
- Failed to load PerlCtrl Runtime
-
It is likely that you have install Perl in two different locations and the
location of ActiveState's Perl is not the first instance of Perl specified
in your PATH. To rectify, rename the directory in which the non-ActiveState
Perl is installed, or be sure the path to ActiveState's Perl is specified
prior to any other instance of Perl in your PATH.
- Dynamic libraries are not found
-
If you are using the Apache web server, and you are seeing something like the
following in your webserver log file:
Can't load '/usr/local/lib/perl5/site_perl/.../XML/Parser/Expat/Expat.so'
for module XML::Parser::Expat: dynamic linker: /usr/local/bin/perl:
libexpat.so.0 is NEEDED, but object does not exist at
/usr/local/lib/perl5/.../DynaLoader.pm line 200.
Then try placing the following into your httpd.conf file and see if it
fixes your problem.
<IfModule mod_env.c>
PassEnv LD_LIBRARY_PATH
</IfModule>
- SOAP client reports "500 unexpected EOF before status line seen
-
See Apache is crashing with segfaults
- Apache is crashing with segfaults
-
Using
SOAP::Lite (or the XML::Parser::Expat manpage) in combination with mod_perl
causes random segmentation faults in httpd processes. To fix, try configuring
Apache with the following:
RULE_EXPAT=no
If you are using Apache 1.3.20 and later, try configuring Apache with the
following option:
./configure --disable-rule=EXPAT
See http://archive.covalent.net/modperl/2000/04/0185.xml for more details and
lot of thanks to Robert Barta <rho@bigpond.net.au> for explaining this weird
behavior.
If this doesn't address the problem, you may wish to try -Uusemymalloc ,
or a similar option in order to instruct Perl to use the system's own malloc .
Thanks to Tim Bunce <Tim.Bunce@pobox.com>.
- CGI scripts do not work under Microsoft Internet Information Server (IIS)
-
CGI scripts may not work under IIS unless scripts use the
.pl extension,
opposed to .cgi .
- Java SAX parser unable to parse message composed by SOAP::Lite
-
In some cases SOAP messages created by
SOAP::Lite may not be parsed
properly by a SAX2/Java XML parser. This is due to a known bug in
org.xml.sax.helpers.ParserAdapter . This bug manifests itself when an
attribute in an XML element occurs prior to the XML namespace declaration on
which it depends. However, according to the XML specification, the order of
these attributes is not significant.
http://www.megginson.com/SAX/index.html
Thanks to Steve Alpert (Steve_Alpert@idx.com) for pointing on it.
- Processing of XML encoded fragments
-
SOAP::Lite is based on the XML::Parser manpage which is basically wrapper around
James Clark's expat parser. Expat's behavior for parsing XML encoded string
can affect processing messages that have lot of encoded entities, like XML
fragments, encoded as strings. Providing low-level details, parser will call
char() callback for every portion of processed stream, but individually for
every processed entity or newline. It can lead to lot of calls and additional
memory manager expenses even for small messages. By contrast, XML messages
which are encoded as base64Binary, don't have this problem and difference in
processing time can be significant. For XML encoded string that has about 20
lines and 30 tags, number of call could be about 100 instead of one for
the same string encoded as base64Binary.
Since it is parser's feature there is NO fix for this behavior (let me know
if you find one), especially because you need to parse message you already
got (and you cannot control content of this message), however, if your are
in charge for both ends of processing you can switch encoding to base64 on
sender's side. It will definitely work with SOAP::Lite and it may work with
other toolkits/implementations also, but obviously I cannot guarantee that.
If you want to encode specific string as base64, just do
SOAP::Data->type(base64 => $string) either on client or on server
side. If you want change behavior for specific instance of SOAP::Lite, you
may subclass SOAP::Serializer , override as_string() method that is
responsible for string encoding (take a look into as_base64Binary() ) and
specify new serializer class for your SOAP::Lite object with:
my $soap = new SOAP::Lite
serializer => My::Serializer->new,
..... other parameters
or on server side:
my $server = new SOAP::Transport::HTTP::Daemon # or any other server
serializer => My::Serializer->new,
..... other parameters
If you want to change this behavior for all instances of SOAP::Lite, just
substitute as_string() method with as_base64Binary() somewhere in your
code after use SOAP::Lite and before actual processing/sending:
*SOAP::Serializer::as_string = \&SOAP::XMLSchema2001::Serializer::as_base64Binary;
Be warned that last two methods will affect all strings and convert them
into base64 encoded. It doesn't make any difference for SOAP::Lite, but it
may make a difference for other toolkits.
-
No support for multidimensional, partially transmitted and sparse arrays
(however arrays of arrays are supported, as well as any other data structures,
and you can add your own implementation with SOAP::Data).
-
Limited support for WSDL schema.
-
XML::Parser::Lite relies on Unicode support in Perl and doesn't do entity decoding.
-
Limited support for mustUnderstand and Actor attributes.
- MacOS
-
Information about XML::Parser for MacPerl could be found here:
http://bumppo.net/lists/macperl-modules/1999/07/msg00047.html
Compiled XML::Parser for MacOS could be found here:
http://www.perl.com/CPAN-local/authors/id/A/AS/ASANDSTRM/XML-Parser-2.27-bin-1-MacOS.tgz
SOAP::Lite allows one to add support for additional transport protocols, or
server handlers, via separate modules implementing the SOAP::Transport::*
interface. The following modules are available from CPAN:
You can download the latest version SOAP::Lite for Unix or SOAP::Lite for
Win32 from the following sources:
* CPAN: http://search.cpan.org/search?dist=SOAP-Lite
You are welcome to send e-mail to the maintainers of SOAP::Lite with your
comments, suggestions, bug reports and complaints.
Special thanks to Randy J. Ray, author of
Programming Web Services with Perl, who has contributed greatly to the
documentation effort of SOAP::Lite.
Special thanks to O'Reilly publishing which has graciously allowed SOAP::Lite
to republish and redistribute the SOAP::Lite reference manual found in
Appendix B of Programming Web Services with Perl.
And special gratitude to all the developers who have contributed patches,
ideas, time, energy, and help in a million different forms to the development
of this software.
Latest development takes place on GitHub.com. Come on by and fork it.
git@github.com:redhotpenguin/perl-soaplite.git
Also see the HACKING file.
Actively recruiting maintainers for this module. Come and get it on!
Please use rt.cpan.org or github to report bugs. Pull requests are preferred.
Copyright (C) 2000-2007 Paul Kulchenko. All rights reserved.
Copyright (C) 2007-2008 Martin Kutter
Copyright (C) 2013 Fred Moyer
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
This text and all associated documentation for this library is made available
under the Creative Commons Attribution-NoDerivs 2.0 license.
http://creativecommons.org/licenses/by-nd/2.0/
Paul Kulchenko (paulclinger@yahoo.com)
Randy J. Ray (rjray@blackperl.com)
Byrne Reese (byrne@majordojo.com)
Martin Kutter (martin.kutter@fen-net.de)
Fred Moyer (fred@redhotpenguin.com)
|