=head1 NAME
XML::Compile::SOAP - base-class for SOAP implementations
=head1 INHERITANCE
XML::Compile::SOAP has extra code in
XML::Compile::SOAP::Encoding
XML::Compile::SOAP is extended by
XML::Compile::SOAP11
XML::Compile::SOAP12
=head1 SYNOPSIS
** Only use SOAP1.1 and WSDL1.1; SOAP1.2/WSDL1.2 not working!
** See TODO, at the end of this page
use XML::Compile::SOAP11::Client;
use XML::Compile::Util qw/pack_type/;
my $client = XML::Compile::SOAP11::Client->new;
# load extra schemas always explicitly
$client->importDefinitions(...);
# !!! The next steps are only required when you do not have
# !!! a WSDL. See XML::Compile::WSDL11 if you have a WSDL.
my $h1el = pack_type $myns, $some_element;
my $b1el = "{$myns}$other_element"; # same, less clean
my $encode_query = $client->compileMessage
( 'SENDER'
, header => [ h1 => $h1el ]
, body => [ b1 => $b1el ]
, destination => [ h1 => 'NEXT' ]
, mustUnderstand => 'h1'
);
my $decode_response = $client->compileMessage
( 'RECEIVER'
, header => [ h2 => $h2el ]
, body => [ b2 => $b2el ]
, faults => [ ... ]
);
my $http = XML::Compile::Transport::SOAPHTTP
->new(address => $server);
my $http = $transport->compileClient(action => ...);
# Combine into one message exchange:
my @query = (h1 => ..., b1 => ...);
my $request = $encode_query->($query);
my ($response, $trace) = $http->($request);
my $answer = $decode_response->($response);
use Data::Dumper;
warn Dumper $answer; # see: a HASH with h2 and b2!
if($answer->{Fault}) ... # error was reported
# Simplify your life
# also in this case: if you have a WSDL, this is created for you.
# This is Document-style SOAP
my $call = $client->compileClient
( kind => 'request-response' # default
, name => 'my first call'
, encode => $encode_query
, decode => $decode_response
, transport => $http
);
# With or without WSDL file the same
my $result = $call->(h1 => ..., b1 => ...);
print $result->{h2}->{...};
print $result->{b2}->{...};
my ($result, $trace) = $call->(...); # LIST will show trace
# $trace is an XML::Compile::SOAP::Trace object
=head1 DESCRIPTION
This module handles the SOAP protocol. The first implementation is
SOAP1.1 (F), which is still
most often used. The SOAP1.2 definition (F)
is quite different; this module tries to define a sufficiently abstract
interface to hide the protocol differences.
Be aware that there are three kinds of SOAP:
=over 4
=item 1.
Document style (literal) SOAP, where there is a WSDL file which explicitly
types all out-going and incoming messages. Very easy to use.
=item 2.
RPC style SOAP literal. The WSDL file is not explicit about the
content of the messages, but all messages must be schema defined types.
=item 3.
RPC style SOAP encoded. The sent data is nowhere described formally.
The data is transported in some ad-hoc way.
=back
=head1 METHODS
=head2 Constructors
$obj-EB(OPTIONS)
=over 4
Create a new SOAP object. You have to instantiate either the SOAP11 or
SOAP12 sub-class of this, because there are quite some differences (which
can be hidden for you)
Option --Default
encoding_ns
envelope_ns
media_type application/soap+xml
schema_instance_ns $schema_ns . '-instance'
schema_ns
schemas created internally
version
. encoding_ns => URI
. envelope_ns => URI
. media_type => MIMETYPE
. schema_instance_ns => URI
. schema_ns => URI
. schemas => C object
=over 4
Use this when you have already processed some schema definitions. Otherwise,
you can add schemas later with C<< $soap->schemas->importDefinitions() >>
=back
. version => STRING
=over 4
The simple string representation of the protocol.
=back
=back
=head2 Accessors
$obj-EB
=over 4
=back
$obj-EB
=over 4
=back
$obj-EB(TABLE, NEW, [USED])
=over 4
NEW is a HASH or ARRAY-of-PAIRS which define prefix-to-uri relations,
which are added to the list defined in the TABLE (a HASH-of-HASHes).
When USED is set, then it will show-up in the output message. At
compile-time, the value of USED is auto-detect.
This method is called for the soap specification preferred namespaces,
and for your L.
=back
$obj-EB(() {shift->{schemains}})
=over 4
=back
$obj-EB
=over 4
=back
$obj-EB
=over 4
Returns the L object which contains the
knowledge about the types.
=back
$obj-EB
=over 4
=back
=head2 Single messages
$obj-EB(('SENDER'|'RECEIVER'), OPTIONS)
=over 4
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.
To make your life easy, the ENTRIES use a label (a free to choose key,
the I in WSDL terminology), to ease relation of your data with
the type where it belongs to. The element of an entry (the value) is
defined as an C element in the schema, and therefore you will need
to explicitly specify the element to be processed.
As OPTIONS, you can specify any listed here, but also anything which is
accepted by L, like
C<< sloppy_integers => 1 >> and hooks. These are applied to all header
and body elements (not to the SOAP wrappers)
Option --Default
body []
destination []
faults []
header undef
mustUnderstand []
prefixes {}
role ULTIMATE
roles []
style 'document'
. body => ENTRIES
=over 4
ARRAY of PAIRS, defining a nice LABEL (free of choice but unique, also
w.r.t. the header and fault ENTRIES) and an element type name or CODE
reference. The LABEL will appear in the Perl HASH only, to be able to
refer to a body element in a simple way.
=back
. destination => ARRAY
=over 4
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 I (soap1.1) or I (soap1.2) URI. You may use
the predefined actors/roles, like 'NEXT'. See L and
L.
=back
. faults => ENTRIES
=over 4
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.
=back
. header => ENTRIES
=over 4
ARRAY of PAIRS, defining a nice LABEL (free of choice but unique)
and an element type name. The LABEL will appear in the Perl HASH, to
refer to the element in a simple way.
The element type is used to construct a reader or writer. You may also
create your own reader or writer, and then pass a compatible CODE reference.
=back
. mustUnderstand => STRING|ARRAY-OF-STRING
=over 4
Writers only. The specified header entry labels specify which elements
must be understood by the destination. These elements will get the
C attribute set to C<1> (soap1.1) or C (soap1.2).
=back
. prefixes => HASH
=over 4
For the sender only: add additional prefix definitions. All provided
names will be used always.
=back
. role => URI|ARRAY-OF-URI
=over 4
Readers only.
One or more URIs, specifying the role(s) you application has in the
process. Only when your role contains C, the body is
parsed. Otherwise, the body is returned as uninterpreted XML tree.
You should not use the role C, because every intermediate
node is a C.
All understood headers are parsed when the C (soap1.1) or
C (soap1.2) attribute address the specified URI. When other
headers emerge which are not understood but carry the C
attribute, an fault is returned automatically. In that case, the
call to the compiled subroutine will return C.
=back
. roles => ARRAY-OF-URI
=over 4
Alternative for option C
=back
. style => 'document'|'rpc-literal'|'rpc-encoded'
=back
$obj-EB(XMLDATA, OPTIONS)
=over 4
Add definitions to the schema. Simply calls
L for this SOAP object's
schema with all the parameters provided. XMLDATA can be everything
accepted by L plus an ARRAY of these things.
=back
$obj-EB(XML)
XML::Compile::SOAP-EB(XML)
=over 4
Returns a HASH with some collected information from a complete SOAP
message (XML::LibXML::Document or XML::LibXML::Element). Currenty,
the HASH contains a C and a C key, with each an ARRAY
of element names which where found in the header resp. body.
=back
=head2 Sender (internals)
$obj-EB(ARGS)
=over 4
=back
$obj-EB(BODY-DEFS, NAMESPACE-TABLE, OPTS)
=over 4
=back
$obj-EB(FAULT-DEFS, NAMESPACE-TABLE, FAULTTYPE)
=over 4
=back
$obj-EB(HEADER-DEFS, NS-TABLE, UNDERSTAND, DESTINATION, OPTS)
=over 4
=back
$obj-EB(NAMESPACE-TABLE)
=over 4
Create a handler which understands RPC encoded specifications.
=back
$obj-EB(NAMESPACE-TABLE)
=over 4
Create a handler which understands RPC literal specifications.
=back
$obj-EB(NAMESPACE-TABLE)
=over 4
=back
$obj-EB(NAMESPACE, LOCAL, ACTIONS)
=over 4
=back
=head2 Receiver (internals)
$obj-EB
=over 4
=back
$obj-EB(NAMESPACE, LOCAL, ACTIONS)
=over 4
=back
$obj-EB(BODYDEF, OPTS)
=over 4
=back
$obj-EB(FAULTSDEF)
=over 4
=back
$obj-EB(HEADERDEF, OPTS)
=over 4
=back
$obj-EB(ARGS)
=over 4
=back
=head2 Helpers
=head2 Transcoding
$obj-EB(TYPE)
=over 4
Produce an error structure to be returned to the sender.
=back
$obj-EB(URI)
=over 4
Translate a role URI into a simple string, if predefined. See
L.
=back
$obj-EB(URI|STRING)
=over 4
Translates actor/role/destination abbreviations into URIs. Various
SOAP protocol versions have different pre-defined STRINGs, which can
be abbreviated for readibility. Returns the unmodified URI in
all other cases.
SOAP11 only defines C. SOAP12 defines C, C, and
C.
=back
=head1 DETAILS
=head2 SOAP introduction
Although the specification of SOAP1.1 and WSDL1.1 are thin, the number
of special constructs are many. And, of course, all poorly documented.
Both SOAP and WSDL have 1.2 versions, which will clear things up a lot,
but not used that often yet.
WSDL defines two kinds of messages: B style SOAP and B
style SOAP. In I, the messages are described in
great detail in the WSDL: the message components are all defined in
Schema's; the worst things you can (will) encounter are C schema
elements which require additional manual processing.
I would like to express my personal disgust over I.
In this case, the body of the message is I clearly specified in the
WSDL... which violates the whole purpose of using interface descriptions
in the first place! In a client-server interface definition, you really
wish to be very explicit in the data you communicate. Gladly, SOAP1.2
shares my feelings a little, and speaks against RPC although still
supporting it.
Anyway, we have to live with this feature. SOAP-RPC is simple
to use on strongly typed languages, to exchange data when you create both
the client software and the server software. You can simply autogenerate
the data encoding. Clients written by third parties have to find the
documentation on how to use the RPC call in some other way... in text,
if they are lucky; the WSDL file does not contain the prototype of the
procedures, but that doesn't mean that they are free-format.
The B messsages are shaped to the procedures which are
being called on the server. The body of the sent message contains the
ordered list of parameters to be passed as 'in' and 'in/out' values to the
remote procedure. The body of the returned message lists the result value
of the procedure, followed by the ordered 'out' and 'in/out' parameters.
The B messages are half-breed document style message: there is
a schema which tells you how to interpret the body, but the WSDL doesn't
tell you what the options are.
=head2 Naming types and elements
XML uses namespaces: URIs which are used as constants, grouping a set
of type and element definitions. By using name-spaces, you can avoid
name clashes, which have frustrate many projects in history, when they
grew over a certain size... at a certain size, it becomes too hard to
think of good distriguishable names. In such case, you must be happy
when you can place those names in a context, and use the same naming in
seperate contexts without confusion.
That being said: XML supports both namespace- and non-namespace elements
and schema's; and of cause many mixed cases. It is by far preferred to
use namespace schemas only. For a schema xsd file, look for the
C attribute of the C element: if present, it
uses namespaces.
In XML data, it is seen as a hassle to write the full length of the URI
each time that a namespace is addressed. For this reason, prefixes
are used as abbreviations. In programs, you can simply assign short
variable names to long URIs, so we do not need that trick.
Within your program, you use
$MYSN = 'long URI of namespace';
... $type => "{$MYNS}typename" ...
or nicer
use XML::Compile::Util qw/pack_type/;
use constant MYNS => 'some uri';
... $type => pack_type(MYNS, 'typename') ...
The L module provides a helpfull methods and constants,
as does the L.
=head2 Client, Proxy and Server implementations
To learn how to create clients in SOAP, read the DETAILS section in
L. The client implementation is platform
independent.
A proxy is a complex kind of server, which in implemented
by , which is available from the
XML-Compile-SOAP-Daemon distribution. The server is based on
Net::Server, which may have some portability restrictions.
=head1 SEE ALSO
This module is part of XML-Compile-SOAP distribution version 0.77,
built on August 15, 2008. Website: F
All modules in this suite:
L,
L,
L,
L,
L,
L,
L.
Please post questions or ideas to the mailinglist at
F
For life contact with other developers, visit the C<#xml-compile> channel
on C.
=head1 LICENSE
Copyrights 2007-2008 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 F