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

NAME

SOAP::XML::Client - Simple frame work for talking with web services

DESCRIPTION

This package is the base class for talking with web services, there are specific modules to use depending on the type of service you are calling, e.g. SOAP::XML::Client::DotNet or SOAP::XML::Client::Generic

This package helps in talking with web services, it just needs a bit of XML thrown at it and you get some XML back. It's designed to be REALLY simple to use.

SYNOPSIS

  See SOAP::XML::Client::DotNet or SOAP::XML::Client::Generic for usage example.

  If you are creating a child class you just need to
  impliment the actual _call() - see pod below.

METHODS

new()

  my $soap_client = SOAP::XML::Client::DotNet->new(
    {   uri   => 'http://www.yourdomain.com/services',
        proxy => 'http://www.yourproxy.com/services/services.asmx',
        xmlns => 'http://www.yourdomain.com/services',
        soapversion         => '1.1',    # defaults to 1.1
        timeout             => '30',     # defaults to 30 seconds
        strip_default_xmlns => 1,        # defaults to 1
        encoding => 'utf-8',    # defaults to 'utf-8' (see 'Encoding' below)
    }
  );

This constructor requires uri, proxy and xmlns to be supplied, otherwise it will croak.

strip_default_xmlns is used to remove xmlns="http://.../" from returned XML, it will NOT alter xmlns:FOO="http//.../" set to '0' if you do not wish for this to happen.

To stop SOAP::Lite being overly keen to encode values as Base64, pass in disable_base64:

   ...
     disable_base64 => 1,
   ...

header()

   my $header = SOAP::Header->name(
          SomeDomain => {
              Username => "a_user",
              Password => 'xxxxx',
          }
      )->uri('http://www.thedomain.com/')->prefix('');

    $soap_client->header($header);

Add a soap header to the soap call, probably useful if there is credential based authenditcation

fetch()

  # Generate the required XML, this is the bit after the Method XML element
  # in the services.asmx descriptor for this method (see SOAP::XML::Client::DotNet SYNOPSIS).
  my $user_id = '900109';
  my $xml = "<userId _value_type='long'>$user_id</userId>";

  if($soap_client->fetch({ method => 'GetActivity', xml => $xml }) {
      # Get result as a string
      my $xml_string = $soap_client->result();

      # Get result as a XML::LibXML object
      my $xml_libxml_object = $soap_client->result_xml();

  } else {
      # There was some sort of error
      print $soap_client->error() . "\n";
      print "Status: " . $soap_client->status();
  }

This method actually calls the web service, it takes a method name and an xml string. If there is a problem with either the XML or the SOAP transport (e.g. web server error/could not connect etc) undef will be returned and the error() will be set.

Each node in the XML supplied (either by string or from a filename) needs to have _value_type defined or the submitted format will default to 'string'.

You can supply 'filename' rather than 'xml' and it will read in from the file.

We check for Fault/faultstring in the returned XML, anything else you'll need to check for yourself.

error()

  $soap_client->error();

If fetch returns undef then check this method, it will either be that the filename you supplied couldn't be read, the XML you supplied was not correctly formatted (XML::LibXML could not parse it), there was a transport error with the web service or Fault/faultstring was found in the XML returned.

status()

  $soap_client->status();
  

This is set to the http status after fetch has been called

results();

  my $results = $soap_client->results();

Can be called after fetch() to get the raw XML, if fetch was sucessful.

results_xml();

  my $results_as_xml = $soap_client->results_xml();

Can be called after fetch() to get the XML::LibXML Document element of the returned xml, as long as fetch was sucessful.

HOW TO DEBUG

At the top of your script, before 'use SOAP::XML::Client::<TYPE>' add:

use SOAP::Lite ( +trace => 'all', readable => 1, outputxml => 1, );

It may or may not help, not all web services give you many helpful error messages! At least you can see what's being submitted and returned. It can be the smallest thing that causes a problem, mis-typed data (see _value_type in xml), or typo in xmlns line.

If the type of module (e.g. SOAP::XML::Client::DotNet) doesn't work, switch to one of the other ones and see if that helps.

_call()

  This should be implimented by the child class

  package SOAP::XML::Client::<PACKAGE NAME>;

  use base qw(SOAP::XML::Client);

  sub _call {
        my ($self,$method) = @_;

        # Impliment it! - below is the code from SOAP::XML::Client::DotNet

        # This code is the .NET specific way of calling SOAP,
        # it might work for other stuff as well        
        my $soap_action = sub {return $self->uri() . '/' . $method};
        
        my $caller = $self->{soap}
                        ->uri($self->uri())
                        ->proxy($self->proxy(), timeout => $self->timeout())
                        ->on_action( $soap_action );
        
        $caller->soapversion($self->soapversion());

        # Create a SOAP::Data node for the method name
        my $method_name = SOAP::Data->name($method)->attr({'xmlns' => $self->xmlns()});
  
        # Execute the SOAP Request and get the resulting XML
        my $res = $caller->call( $method_name => $self->{sdb}->to_soap_data());

        return $res;
  }

  1;

ENCODING

Encoding defaults to UTF-8, but can be overidden by the 'encoding' argument to the constructor. The encoding setting is used to flag the SOAP message (e.g. <?xml version="1.0" encoding="utf-8"?>), and to decode the received data between the chosen character encoding and internal Perl string format.

Field values and attribute values are no longer encoded (as in v2.2), since this now appears to be handled correctly by XML::LibXML and SOAP::Lite.

Note that this currently expects that the returned message will be in the same character encoding - it does not parse the response for an 'encoding' attribute.

BUGS

You may encounter problems with twice encoded or decoded characters if code using this package is encoding data prior to the call or decoding the response.

SEE ALSO

<SOAP::XML::Client::DotNet> <SOAP::XML::Client::Generic>

AUTHOR

Leo Lapworth <LLAP@cuckoo.org>

REPOSITORY

http://github.com/ranguard/soap-xml-client

THANKS

Thanks to Foxtons for letting me develope this on their time and to Aaron for his help with understanding SOAP a bit more and the London.pm list for ideas.