The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

XML::Compile::SOAP - base-class for SOAP implementations

SYNOPSIS

 # There are quite some differences between SOAP1.1 and 1.2
 my $soap = XML::Compile::SOAP::SOAP11->new;

 $soap->schemas->importDefinitions(...);   # load extra schema's

 # Request, answer, and call usually created via WSDL
 my $request = $soap->compile
   ('CLIENT', 'INPUT'               # client to server
   , header   => [ h1 => 'h1type' ]
   , body     => [ b1 => 'b1type' ]
   , destination    => [ h1 => 'NEXT' ]
   , mustUnderstand => 'h1'
   );

 my $answer = $soap->compile
   ('CLIENT', 'OUTPUT'              # server to client
   , header   => [ h2 => 'h2type' ]
   , body     => [ b2 => 'b2type' ]
   , headerfault => [ ... ]
   , fault    => [ ... ]
   );

 my $call  = $soap->call($request, $answer, address => $endpoint);

 my $result = $call->(h1 => ..., b1 => ...);
 print $result->{h2}->{...};
 print $result->{b2}->{...};

DESCRIPTION

**WARNING** Implementation not finished: not usable!!

This module handles the SOAP protocol. The first implementation is SOAP1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/), which is still most often used. The SOAP1.2 definition (http://www.w3.org/TR/soap12/) are different; this module tries to define a sufficiently abstract interface to hide the protocol differences.

Limitations

On the moment, the following limitations exist:

.

Only qualified header and body elements are supported.

.

Only document/literal use is supported, not XML-RPC.

METHODS

Constructors

$obj->new(OPTIONS)

     Option     --Default
     encoding_ns  <required>
     envelope_ns  <required>
     media_type   application/soap+xml
     schemas      created internally

    . encoding_ns => URI

    . envelope_ns => URI

    . media_type => MIMETYPE

    . schemas => XML::Compile::Schema object

      Use this when you have already processed some schema definitions. Otherwise, you can add schemas later with $soap->schames->importDefinitions()

Accessors

$obj->encodingNS

$obj->envelopeNS

$obj->schemas

SOAPAction

$obj->compile(('CLIENT'|'SERVER'),('INPUT'|'OUTPUT'), OPTIONS)

    The payload is defined explicitly, where all headers and bodies are specified as ARRAY containing key-value pairs (ENTRIES). When you have a WSDL file, these ENTRIES are generated automatically.

    As role, you specify whether your application is a CLIENT (creates INPUT messages to the server, accepts OUTPUT messages), or a SERVER (accepting INPUT queries, producing OUTPUT messages). The combination of the first and second parameter determine whether an XML reader or XML writer is to be created. NB: a CLIENT INPUT message is a message which is sent by the client as input to the server, according the WSDL terminology definition.

    To make your life easy, the ENTRIES use a label (a free to choose key, the part in WSDL terminology), to ease relation of your data with the type where it belongs to. The type of an entry (the value) is defines as an any type in the schema and therefore you will need to explicitly specify the type of the element to be processed.

     Option        --Default
     body            undef
     destination     []
     fault           []
     header          undef
     mustUnderstand  []
     role            ULTIMATE
     roles           []

    . body => ENTRIES

    . destination => ARRAY

      Writers only. Indicate who the target of the header entry is. By default, the end-point is the destination of each header element.

      The ARRAY contains a LIST of key-value pairs, specifing an entry label followed by an actor (soap1.1) or role (soap1.2) URI. You may use the predefined actors/roles, like 'NEXT'. See roleAbbreviation().

    . fault => ENTRIES

      The SOAP1.1 and SOAP1.2 protocols define fault entries in the answer. Both have a location to add your own additional information: the type(-processor) is to specified here, but the returned information structure is larger and differs per SOAP implementation.

    . header => ENTRIES

      ARRAY of PAIRS, defining a nice LABEL (free of choice but unique) and an element reference. The LABEL will appear in your code only, to refer to the element in a simple way.

    . mustUnderstand => STRING|ARRAY-OF-STRING

      Writers only. The specified header entry labels specify which elements must be understood by the destination. These elements will get the mustUnderstand attribute set to 1 (soap1.1) or true (soap1.2).

    . role => URI|ARRAY-OF-URI

      Readers only. One or more URIs, specifying the role(s) you application has in the process. Only when your role contains ULTIMATE, the body is parsed. Otherwise, the body is returned as uninterpreted XML tree. You should not use the role NEXT, because every intermediate node is a NEXT.

      All understood headers are parsed when the actor (soap1.1) or role (soap1.2) attribute address the specified URI. When other headers emerge which are not understood but carry the mustUnderstood attribute, an fault is returned automatically. In that case, the call to the compiled subroutine will return undef.

    . roles => ARRAY-OF-URI

      Alternative for option role

$obj->direction(ROLE, INOUT)

    Based on the ROLE of the application (CLIENT or SERVER) and the direction indication (INPUT or OUTPUT from the WSDL), this returns whether a READER or WRITER needs to be generated.

$obj->roleAbbreviation(STRING)

    Translates actor/role/destination abbreviations into URIs. Various SOAP protocol versions have different pre-defined URIs, which can be abbreviated for readibility. Returns the unmodified STRING in all other cases.

DETAILS

Do it yourself, no WSDL

Does this all look too complicated? It isn't that bad. The following example is used as test-case t/82soap11.t, directly taken from the SOAP11 specs section 1.3 example 1.

 # for simplification
 my $TestNS   = 'http://test-types';
 my $SchemaNS = 'http://www.w3.org/2001/XMLSchema';

First, the schema (hopefully someone else created for you, because they can be quite hard to create correctly) is in file myschema.xsd

 <schema targetNamespace="$TestNS"
   xmlns="$SchemaNS">

 <element name="GetLastTradePrice">
   <complexType>
      <all>
        <element name="symbol" type="string"/>
      </all>
   </complexType>
 </element>

 <element name="GetLastTradePriceResponse">
   <complexType>
      <all>
         <element name="price" type="float"/>
      </all>
   </complexType>
 </element>

 <element name="Transaction" type="int"/>
 </schema>

Ok, now the program you create the request:

 my $soap   = XML::Compile::SOAP::SOAP11->new;
 $soap->schemas->importDefinitions('myschema.xsd');

 my $get_price = $soap->compile
  ( 'CLIENT', 'INPUT'
  , header => [ transaction => "{$TestNS}Transaction" ]
  , body =>   [ request => "{$TestNS}GetLastTradePrice" ]
  , mustUnderstand => 'transaction'
  , destination => [ 'transaction' => 'NEXT http://actor' ]
  );

INPUT is used in the WSDL terminology, indicating this message is an input message for the server. This $get_price is a WRITER. Above is done only once in the initialization phase of your program.

At run-time, you have to call the CODE reference with a data-structure which is compatible with the schema structure. (See XML::Compile::Schema::template() if you have no clue how it should look) So: let's send this:

 # insert your data
 my %data_in =
   ( Header => {transaction => 5}
   , Body   => {request => {symbol => 'DIS'}}
   );

 # create a XML::LibXML tree
 my $xml  = $get_price->(\%data_in, 'UTF-8');
 print $xml->toString;

And the output is:

 <SOAP-ENV:Envelope
    xmlns:x0="http://test-types"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header>
     <x0:Transaction
       mustUnderstand="1"
       actor="http://schemas.xmlsoap.org/soap/actor/next http://actor">
         5
     </x0:Transaction>
   </SOAP-ENV:Header>
   <SOAP-ENV:Body>
     <x0:GetLastTradePrice>
       <symbol>DIS</symbol>
     </x0:GetLastTradePrice>
   </SOAP-ENV:Body>
 </SOAP-ENV:Envelope>

Some transport protocol will sent this data from the client to the server. See XML::Compile::SOAP::HTTP, as one example.

On the SOAP server side, we will parse the message. The string $soap contains the XML. The program looks like this:

 my $server = $soap->compile       # create once
  ( 'SERVER', 'INPUT'
  , header => [ transaction => "{$TestNS}Transaction" ]
  , body =>   [ request => "{$TestNS}GetLastTradePrice" ]
  );

 my $data_out = $server->($soap);  # call often

Now, the $data_out reference on the server, is stucturally exactly equivalent to the %data_in from the client.

DIAGNOSTICS

Error: an input message does not have faults

Error: headerfault does only exist in SOAP1.1

Error: message is INPUT or OUTPUT, not $inout

Error: option 'destination' only for writers

Error: option 'mustUnderstand' only for writers

Error: option 'role' only for readers

Error: option 'roles' only for readers

Error: role must be CLIENT or SERVER, not $role

SEE ALSO

This module is part of XML-Compile distribution version 0.18, built on June 06, 2007. Website: http://perl.overmeer.net/xml-compile/

LICENSE

Copyrights 2006-2007 by Mark Overmeer. For other contributors see ChangeLog.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See http://www.perl.com/perl/misc/Artistic.html

1 POD Error

The following errors were encountered while parsing the POD:

Around line 81:

Deleting unknown formatting code M<>