The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

SOAP::Lite - Library for SOAP clients and servers in Perl

SYNOPSIS

  use SOAP::Lite;
  print SOAP::Lite 
    -> uri('http://simon.fell.com/calc')
    -> proxy('http://www.razorsoft.net/ssss4c/soap.asp')
    -> doubler([10,20,30,50,100])
    -> result ->[1];
 

  The same code with autodispatch: 

  use SOAP::Lite +autodispatch => (
    uri => 'http://simon.fell.com/calc',
    proxy => 'http://www.razorsoft.net/ssss4c/soap.asp'
  );

  print doubler([10,20,30,50,100])->[2];                             


  Code for SOAP server (CGI) looks like: 

  use SOAP::Transport::HTTP;
  SOAP::Transport::HTTP::CGI
    -> dispatch_to('/Your/Path/To/Deployed/Modules', 'Module::Name', 'Module::method') 
    -> handle;

DESCRIPTION

SOAP::Lite for Perl 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.

To learn more about SOAP, visit the FAQ at http://www.develop.com/soap/soapfaq.htm.

This version of SOAP::Lite supports the SOAP 1.1 specification. See http://www.w3.org/TR/SOAP for details.

The main features of the library are:

  • Supports SOAP 1.1 spec.

  • Provides full namespace support for SOAP 1.1.

  • Contains various reusable components (modules) that can be used separately or together, like SOAP::Serializer and SOAP::Deserializer.

  • Provides an object oriented interface for serializing/deserializing and sending/receiving SOAP packets.

  • Supports serialization/deserialization of sophisticated object graphs which may have cycles (a circular queue would serialize just fine, as well as $a=\$a. See test.pl and documentation for more examples).

  • Has more than 20 tests that access public test servers with different implementations: Apache SOAP, Frontier, Perl, XSLT, COM and VB6.

  • Support for extensibility of the serialization/deserialization architecture has been included; see SOAP::Data for details.

  • Supports blessed object references.

  • Supports arrays (both serialization and deserialization with autotyping).

  • Supports ordered hashes (as working example of user-defined data types).

  • Custom/user-defined types (see SOAP::Data::as_ordered_hash for example).

  • Customizable auto type definitions.

  • Supports Base64 encoding.

  • Supports XML entity encoding.

  • Supports header attributes.

  • Supports out parameters binding.

  • Supports transparent SOAP calls with autodispatch feature.

  • Supports dynamic/static class/method binding.

  • Provides CGI/daemon server implementation

  • Supports HTTPS protocol

  • Supports SMTP protocol

  • Provides POP3 server implementation

  • Supports Basic/Digest server authentication

  • Provides shell for interactive SOAP sessions. See SOAPsh.pl.

  • Easy services deployment. Just put module in specified directory and it'll be accessible.

WHERE TO FIND EXAMPLES

See test.pl, examples/*.pl and module documentation for a client-side examples that show the serialization of a SOAP request, sending it over HTTP and receiving a response, and the deserialization of the response. See examples/soap.cgi, examples/soap.daemon and examples/My/Apache.pm for server implementations.

OVERVIEW OF CLASSES AND PACKAGES

This table should give you a quick overview of the classes provided by the library.

 SOAP::Lite.pm
 -- SOAP::Lite         -- Main class provides all logic
 -- SOAP::Transport    -- Supports transport architecture
 -- SOAP::Data         -- Provides extensions for serialization architecture
 -- SOAP::Header       -- Provides extensions for Header serialization
 -- SOAP::Serializer   -- Serializes data structures to SOAP package
 -- SOAP::Parser       -- Parse XML file into object tree
 -- SOAP::Deserializer -- Deserializes result of SOAP::Parser into objects
 -- SOAP::SOM          -- Provides access to deserialized object tree
 -- SOAP::Constants    -- Provides access to common constants

 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

 SOAP::Transport::POP3.pm
 -- SOAP::Transport::POP3::Server  -- Server interface to POP3 protocol

 SOAP::Transport::MAILTO.pm
 -- SOAP::Transport::MAILTO::Client -- Client interface to SMTP/sendmail

SOAP::Lite

All methods that SOAP::Lite gives you access to can be used for both setting and retrieving values. If you provide no parameters, you'll get current value, and if you'll provide parameter(s), new value will be assigned and method will return object (if not stated something else). This is suitable for stacking these calls like:

  $lite = SOAP::Lite
    -> uri('http://simon.fell.com/calc')
    -> proxy('http://www.razorsoft.net/ssss4c/soap.asp')
  ;

Order is insignificant and you may call new() method first. If you don't do it, SOAP::Lite will do it for you. However, new() method gives you additional syntax:

  $lite = new SOAP::Lite
    uri => 'http://simon.fell.com/calc',
    proxy => 'http://www.razorsoft.net/ssss4c/soap.asp'
  ;

new() accepts hash with method names and values, and will call appropriate method with passed value.

Since new() is optional it won't be mentioned anymore.

Other available methods are:

transport()

Provides access to SOAP::Transport object. Object will be created for you. You can reassign it (but generally you should not).

serializer()

Provides access to "SOAP::Serialization" object. Object will be created for you. You can reassign it (but generally you should not).

proxy()

Shortcut for transport->proxy(). Lets you specify endpoint and load required module at the same time. Required for dispatching SOAP calls. Name of the module will be defined depending on protocol specified for endpoint. Prefix SOAP::Transport will be appended, module loaded and object of class (with appended ::Client) will be created. For example, for 'http://localhost/' class for create object will look like SOAP::Transport:HTTP::Client;

endpoint()

Lets you specify endpoint without changing/loading protocol module. Usable for changing endpoints without changing protocols. You should call proxy() first. No checks for protocol equality will be made.

outputxml()

Lets you specify output from all methods call. If true, all methods will return unprocessed raw xml. You can parsed it with XML::Parser, SOAP::Deserializer or any other module that will work for you.

autotype()

Shortcut for serializer->autotype(). Lets you specify will serializer try to make autotyping for you or not. Default setting is true.

readable()

Shortcut for serializer->readable(). Lets you specify format for generated xml code. Carriage returns and indentation will be added for readability. Usable when you want to see generated code in debugger. By default there are no additional characters in generated xml code.

namespace()

Shortcut for serializer->namespace(). Lets you specify default namespace for generated envelope. 'SOAP-ENV' by default.

encodingspace()

Shortcut for serializer->encodingspace(). Lets you specify default encoding namespace for generated envelope. 'SOAP-ENC' by default.

encoding()

Shortcut for serializer->encoding(). Lets you specify encoding for generated envelope. For now it won't actually change envelope encoding, it'll just modify xml header. 'ISO-8859-1' by default.

typelookup()

Shortcut for serializer->typelookup(). Gives you access to typelookup table that used for autotyping. For more information see "SOAP::Serializer".

uri()

Shortcut for serializer->uri(). Lets you specify uri for SOAP method. Default value is provided, however you call will definitely fail if you don't specify required uri.

multirefinplace()

Shortcut for serializer->multirefinplace(). If true, serializer will put value for multireferences in the first occurence of the reference. Otherwise it will be encoded as top intependent element, right after Body. Default value is 'false'.

header()

DEPRECATED. Use SOAP::Header instead.

Shortcut for serializer->header(). Lets you specify header for generated envelope. You can specify root, mustUnderstand or any other header using SOAP::Data class:

  $serializer = SOAP::Serializer->envelope('method' => 'mymethod', 1,
    SOAP::Header->name(t1 => 5)->attr({'~V:mustUnderstand' => 1}),
    SOAP::Header->name(t2 => 7)->mustUnderstand(2),
  );

will be serialized into:

  <SOAP-ENV:Envelope ...attributes skipped>
    <SOAP-ENV:Header>
      <t1 xsi:type="xsd:int" SOAP-ENV:mustUnderstand="1">5</t1>
      <t2 xsi:type="xsd:int" SOAP-ENV:mustUnderstand="1">7</t2>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
      <namesp1:mymethod xmlns:namesp1="urn:SOAP__Serializer">
        <c-gensym6 xsi:type="xsd:int">1</c-gensym6>
      </namesp1:mymethod>
    </SOAP-ENV:Body>
  </SOAP-ENV:Envelope>

You can mix SOAP::Header parameters with other parameters and also you can return SOAP::Header parameters as result of remote call and they will be placed in header. See My::Parameters::addheader as example.

on_action()

Lets you specify handler for on_action event. Triggered for creating SOAPAction. Default handler will make SOAPAction as "uri#method". You can change this behavior globally (see "DEFAULT HANDLERS") or locally, for particular object.

on_fault()

Lets you specify handler for on_fault event. Default behavior is die on transport error and does nothing on others. You can change this behavior globally (see "DEFAULT HANDLERS") or locally, for particular object.

on_debug()

Lets you specify handler for on_debug event. Default behavior is do nothing.

on_nonserialized()

Lets you specify handler for on_nonserialized event. Default behavior is produce warning if warnings are on for everything that cannot be properly serialized (like CODE references or GLOBs).

SOAP::Data

You can use this class if you want to specify value, name, type, uri or attributes for SOAP elements (use 'value', 'name', 'type', 'uri' and 'attr' methods correspondingly). For example, SOAP::Data->name('abc')->value(123) will be serialized to '<abc>123</abc>', as well as SOAP::Data->name(abc => 123). Each of them except 'value' method can have value as second parameter. All methods return current value if you call them without parameters and return object otherwise, so you can stack them. See test.pl for more examples. You can import these methods with:

  SOAP::Data->import('name'); 

or

  import SOAP::Data 'name'; 

and then use name(abc => 123) for brevity.

SOAP::Serializer

Usually you don't need to interact directly with this module. The only case when you need it, it's autotyping. This feature lets you specify types for your data according to your needs as well as introduce new data types (like ordered hash for example).

You can specify type with SOAP::Data->type(float = 123)> and during serialization stage module will try to serialize you data with as_float method, then call typecast method (you can override it or inherit your own class from SOAP::Data) and only then will try to serialize it as usual data structure. For example:

  SOAP::Data->type('ordered_hash' => [a => 1, b => 2]) 

will be serialized as ordered hash, using as_ordered_hash method.

If you do not specify type directly serialization module will try to autodefine type for you according to typelookup hash. It contains type name as key and following 3-element array as value:

  priority, 
  check_function (CODE reference), 
  typecast function (METHOD name or CODE reference)

For example, if you want to add uriReference to autodefined types, you should add something like this:

  $s->typelookup({
    %{$s->typelookup},
    uriReference => [11, sub { shift =~ m!^http://! }, 'as_uriReference']
  });

and add as_uriReference method to "SOAP::Serializer" class:

  sub SOAP::Serializer::as_uriReference {
    my $self = shift;
    my($value, $name, $type, $attr) = @_;
    return [$name, {%{$attr || {}}, 'xsi:type' => 'xsd:uriReference'}, $value];
  }

Specified methods will work for both autotyping and direct typing, so you can use either SOAP::Data->type(uriReference => 'http://yahoo.com') or just 'http://yahoo.com' and it'll be serialized into the same type.

For more examples see as_* methods in SOAP::Serializer.

SOAP::Serializer provides you with autotype(), readable(), namespace(), encodingspace(), encoding(), typelookup(), uri(), multirefinplace() and envelope() methods. All methods except envelope() are described in "SOAP::Lite" section.

envelope()

Allows you build three kind of envelopes depenfing on the first parameter:

method
  envelope(method => 'methodname', @parameters);

Lets you build request/response envelope.

fault
  envelope(fault => 'faultcode', 'faultstring', 'details');

Lets you build fault envelope.

freeform
  envelope(freeform => 'something that I want to serialize');

Reserved for nonRPC calls. Lets you build you own payload inside SOAP envelope. All specification rules are applied, except method specific.

For more examples see test.pl and SOAP::Transport::HTTP.pm

SOAP::SOM

SOM gives you access to deserialized enveloped with several methods. All methods accepts node path (similar to XPath notations). SOM understands '/' as a root node, '//' as relative location path ('//Body' will find all bodies in document, as well as '/Envelope//nums' will find all 'nums' nodes under Envelope node), '[num]' as node number and '[opnum]' that can be operation ('<', '>', '<=', '>=', '!', '=') followed by node number. All nodes in nodeset will be returned in document order.

match()

Accepts path to node and return true/false in boolean context and SOM object otherwise. valueof() and dataof() can be used to get value(s) of matched node(s).

valueof()

Returns value of (previously) matched node. Can accept node path. In that case return value of matched node, but do not change current node. Suitable when you want to match node and then navigate through node childs:

  $som->match('/Envelope/Body/[1]'); # match method
  $som->valueof('[1]');              # result
  $som->valueof('[2]');              # first out parameter (if present)

Return value depends on context. In scalar context will return first element from matched nodeset.

dataof()

Same as valueof(), but returns SOAP::Data object, so you can get access to name, type and attributes of element.

headerof()

Same as dataof(), but returns SOAP::Header object, so you can get access to name, type and attributes of element.

namespaceuriof()

Returns uri associated with matched element. This uri can be inherited.

SOAP::SOM also provides you methods for quick access to Envelope, Body, method and parameters (both in and out). All these methods return real values (in most cases it'll be reference to hash), if called as object method. Return value also depends on context: in array context it'll return you array of values and in scalar context it'll return first element. So if you want to access first output parameter, you can call $param = $som->paramsout; and you'll get it disregarding real number of output parameters. If you call it as class function (for example, SOAP::SOM::method) it returns Xpath string that match current element ('/Envelope/Body/[1]' in case of 'method'). Method will return undef if not present OR if you try to access element that has xsi:null="1" attribute. To distinguish between these two cases you can first access match method that'll return true/false in boolean context and then get the real value:

  if ($som->match('//myparameter')) {
    $value = $som->valueof; # can be undef too
  } else {
    # doesn't exist
  }
envelope()

Returns hash with deserialized envelope. Keys in this hash will be 'Header' (if present) and 'Body'. Values will be deserialized header and body correspondingly. If called as function (SOAP::SOM::envelope) will return Xpath string that match envelope content. Usable when you want just match it and then iterate content by yourself. Example:

  if ($som->match(SOAP::SOM::envelope)) {
    $som->valueof('Header'); # should give access to header if present
    $som->valueof('Body');   # should give access to body
  } else {
    # hm, are we doing SOAP or what?
  }
header()

Returns hash with deserialized header. If you want to get access to all attributes in header use:

  # get element as SOAP::Data object 
  $transaction = $som->match(join '/', SOAP::SOM::header, 'transaction')->dataof;
  # then you can access all attributes of 'transaction' element
  $transaction->attr; 
headers()

Returns nodeset of deserialized headers. Difference between header() and headers() methods is that former gives you access to the whole header and later to the headers inside 'Header' tag:

  $som->headerof(join '/', SOAP::SOM::header, '[1]');
  # gives you first header as SOAP::Header object

  ($som->headers)[0];
  # gives you value of the first header, same as
  $som->valueof(join '/', SOAP::SOM::header, '[1]');

  $som->header->{name_of_your_header_here}
  # gives you value of name_of_your_header_here
body()

Returns hash with deserialized body.

fault()

Returns value (hash) of Fault elements: faultcode, faultstring and detail. If Fault element is present, result, paramsin, paramsout and methods will return undef value.

faultcode()

Returns value of faultcode element if present and undef otherwise.

faultstring()

Returns value of faultstring element if present and undef otherwise.

faultactor()

Returns value of faultactor element if present and undef otherwise.

faultdetail()

Returns value of detail element if present and undef otherwise.

method()

Returns value of method element (all input parameters if you call it on desetialized request envelope, and result/output parameters if you call it on deserialized response envelope). Return undef if Fault element is present.

result()

Returns value of result from method call. In fact, it'll return first child element (in document order) of method element.

paramsin()

Return value(s) of all passed parameters.

paramsout()

Return value(s) of output parameters. See following section for details and examples.

IN/OUT, OUT PARAMETERS AND AUTOBINDING

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'll get 1 as result and 2 and 3 as out parameters.

If server returns return [1,2,3] you'll get ARRAY from result() and undef from paramsout() . Result can be arbitrary complex: it can be array of something, it can be object, it can be anything and it still be in result() . If only one parameter is returned paramsout() will return undef.

But there is more. If you have in your output parameters parameter with the same signature (name+type) as in input parameters it'll be mapped automatically. Example:

server:

  sub mymethod {
    shift; # object/class reference
    my $param1 = shift;
    my $param2 = SOAP::Data->name('myparam' => shift() * 2);
    return $param1, $param2;
  }

client:

  $a = 10;
  $b = SOAP::Data->name('myparam' => 12);
  $result = $soap->mymethod($a, $b);

After that, $result == 10 and $b->value == 24! Magic? Kind of. Autobinding gives it to you. That'll work with objects also with one difference: you don't need to worry about name and type of object parameter. Consider PingPong example (My/PingPong.pm and examples/pingpong.pl):

server:

  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:

  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

AUTODISPATCHING

SOAP::Lite provides autodispatching feature that let your create code that will look similar for local and remote access.

For example:

  use SOAP::Lite +autodispatch 
    => (uri => 'urn:/My/Examples', proxy => 'http://localhost/');

tells autodispatch all calls to 'http://localhost/' endpoint with 'urn:/My/Examples' uri. All consequent call can look like:

  print getStateName(1), "\n\n";
  print getStateNames(12,24,26,13), "\n\n";
  print getStateList([11,12,13,42])->[0], "\n\n";
  print getStateStruct({item1 => 10, item2 => 4})->{item2}, "\n\n";

As you can see, there is no SOAP specific coding at all.

The same logic will work for objects also:

  my $e = new Chatbot::Eliza 'Your name';
  print "Talk, please\n> ";
  while (<>) {
    print $e->transform;
  } continue {
    print "\n> ";
  }

will access remote Chatbot::Eliza module, get object, and then call remote method again. Object will be transferred there, method executed and result (and modified object!) will be transferred back.

Autodispatch will work only if you don't have the same method in your code. For example, if you have use Chatbot::Eliza somewhere in your code for previous example all methods will be resolved locally with no SOAP calls. If you want to get access to remote objects/methods even in that case, use SOAP:: prefix to your methods, like:

  print $p->SOAP::next, "\n";  

See pingpong.pl for example of script, that work with the same object locally and remotely.

You can mix autodispatch and usual SOAP calls in the same code if you need it.

DEFAULT HANDLERS

use SOAP::Lite syntax also lets you specify default event handlers for your code. Imagine you have different SOAP objects and want to share same on_action() (or on_fault() ) handler. You can specify on_action() during initialization for every object, but also you can do:

  use SOAP::Lite on_action => sub {sprintf '%s#%s', @_};

and this handler will be default handler for all your SOAP objects. You can override it if you specify handler for particular object.

See test.pl as example of on_fault() handler.

BUGS AND LIMITATIONS

  • Library currently supports only HTTP protocol with no M-POST requests.

  • 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").

  • No support for xsd schemas.

PLATFORMS

MacOS

Information about XML::Parser for MacPerl is here: http://bumppo.net/lists/macperl-modules/1999/07/msg00047.html

Compiled XML::Parser for MacOS is here: http://www.perl.com/CPAN-local/authors/id/A/AS/ASANDSTRM/XML-Parser-2.27-bin-1-MacOS.tgz

AVAILABILITY

You can download the latest version SOAP::Lite for Unix or SOAP::Lite for Win32 ( http://geocities.com/paulclinger/soap.html ). SOAP::Lite is available also from CPAN ( http://search.cpan.org/search?dist=SOAP-Lite ). You are very welcome to write mail to author (paulclinger@yahoo.com) with your comments, suggestions, bug reports and complains.

SEE ALSO

You can get SOAP/Perl library from Keith Brown ( http://www.develop.com/soap/ ) or directly from CPAN. I tried introduced as little interactions as possible and hopefully you'll be able to use both libraries simultaneously. Let me know if I did something wrong and you cannot use them at the same time.

COPYRIGHT

Copyright (C) 2000 Paul Kulchenko. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

AUTHOR

Paul Kulchenko (paulclinger@yahoo.com)