=head1 NAME XML::Compile::SOAP::Client - SOAP message initiators =head1 INHERITANCE XML::Compile::SOAP::Client is extended by XML::Compile::SOAP11::Client XML::Compile::SOAP12::Client =head1 SYNOPSIS # never used directly, only via XML::Compile::SOAP1[12]::Client =head1 DESCRIPTION This class defines the methods that each client side of the SOAP message exchange protocols must implement. =head1 METHODS =head2 Constructors This object can not be instantiated, but is only used as secundary base class. The primary must contain the C. =head2 Handlers $obj-EB(OPTIONS) =over 4 Option --Default decode encode kind request-response name or "unnamed" rpcin rpcout undef transport . decode => CODE =over 4 The CODE reference is produced by L, and must be a RECEIVER: translate a SOAP message into Perl data. Even in one-way operation, this decode should be provided: some servers may pass back some XML in case of errors. =back . encode => CODE =over 4 The CODE reference is produced by L, and must be a SENDER: translates Perl data structures into the SOAP message in XML. =back . kind => STRING =over 4 Which kind of client is this. WSDL11 defines four kinds of client-server interaction. Only C (the default) and C are currently supported. =back . name => STRING =over 4 Currently only used in some error messages, but may be used more intensively in the future. When C is a TYPE, then the local name of that type is used as default. =back . rpcin => TYPE|CODE =over 4 The TYPE of the RPC input message (RPC literal style) or a CODE reference which can be created to parse the RPC block (RPC encoded style). If this option is not specified, but there is an C with TYPE value, then the value for this options will default for that type name with C concatenated: a commonly used convension. If this option is not used, but there is an C with CODE reference, then a standard decode routine is called. That routine does use L to get an as simple as possible return structure. This function tries hard, and does some validation as well, however many RPC schemas are horribly broken, and thereby the automatic decoding fails. As alternative, you can try C from XML::LibXML::Simple or XML::Simple (SAX based parser). rpcin => sub { my $soap = shift; [ map { XMLin($_) } @_ ] } Each of the body parts now get decoded. However, this does not resolve references and such: the output datastructure is far more verbose. =back . rpcout => TYPE|CODE =over 4 The TYPE of the RPC output message (RPC literal style) or a CODE reference which can be created to produce the RPC block (RPC encoded style). =back . transport => CODE|OBJECT =over 4 The CODE reference is produced by an extensions of L (usually L. If you pass a L object, the compileClient will be called for you. This is possible in case you do not have any configuration options to pass with the compileClient(). =back =back =head2 Debugging $obj-EB([FAKE|undef]) XML::Compile::SOAP::Client-EB([FAKE|undef]) =over 4 Returns the fake server, if defined: it will be called to simulate an external SOAP server. Use this for debugging and regression test scripts. Usually, you should set your own FAKE server, but simply instantiate a L object. BE WARNED: this FAKE server must be instantiated B the SOAP client handlers are compiled. =back =head1 DETAILS =head2 Client side SOAP =head3 Calling the server (Document style) First, you compile the call either via a WSDL file (see L), or in a few manual steps (which are described in the next section). In either way, you end-up with a CODE references which can be called multiple times. # compile once my $call = $soap->compileClient(...); # and call often my $answer = $call->(%request); # list of pairs my $answer = $call->(\%request); # same, but HASH my $answer = $call->(\%request, 'UTF-8'); # same But what is the structure of C<%request> and C<$answer>? Well, there are various syntaxes possible: from structurally perfect, to user-friendly. First, find out which data structures can be present: when you compiled your messages explicitly, you have picked your own names. When the call was initiated from a WSDL file, then you have to find the names of the message parts which can be used: the part names for header blocks, body blocks, headerfaults, and (body) faults. Do not worry to much, you will get (hopefully understandable) run-time error messages when the structure is incorrect. Let's say that the WSDL defines this (ignoring all name-space issues) , and one body part C. The output message only has one part named C, which is all defined for the message and therefore its name can be omitted. Then, the definitions of the blocks: Now, calling the compiled function can be done like this: my $got = $call->( count => 5, request => {tickerSymbol => 'IBM'} ); = $call->({ count => 5, request => {tickerSymbol => 'IBM'} }); = $call->({ count => 5, request => {tickerSymbol => 'IBM'} } , 'UTF-8'); If the first arguments for the code ref is a HASH, then there may be a second which specifies the required character-set. The default is C, which is very much adviced. =head3 Parameter unpacking (Document Style) In the example situation of previous section, you may simplify the call even further. To understand how, we need to understand the parameter unpacking algorithm. The structure which we need to end up with, looks like this $call->(\%data, $charset); %data = ( Header => {count => 5} , Body => { request => {tickerSymbol => 'IBM'} } ); The structure of the SOAP message is directly mapped on this nested complex HASH. But is inconvenient to write each call like this, therefore the C<$call> parameters are transformed into the required structure according to the following rules: =over 4 =item 1. if called with a LIST, then that will become a HASH =item 2. when a C
and/or C are found in the HASH, those are used =item 3. if there are more parameters in the HASH, then those with names of known header and headerfault message parts are moved to the C
sub-structure. Body and fault message parts are moved to the C sub-structure. =item 4. If the C sub-structure is empty, and there is only one body part expected, then all remaining parameters are put in a HASH for that part. This also happens if there are not parameters: it will result in an empty HASH for that block. =back So, in our case this will also do, because C is a known part, and C gets all left-overs, being the only body part. my $got = $call->(count => 5, tickerSymbol => 'IBM'); This does not work if the block element is a simple type. In most existing Document style SOAP schemas, this simplification probably is possible. =head3 Understanding the output (Document style) The C<$got> is a HASH, which will not be simplified automatically: it may change with future extensions of the interface. The return is a complex nested structure, and Data::Dumper is your friend. $got = { answer => { price => 16.3 } } To access the value use printf "%.2f US\$\n", $got->{answer}->{price}; printf "%.2f US\$\n", $got->{answer}{price}; # same or my $answer = $got->{answer}; printf "%.2f US\$\n", $answer->{price}; =head3 Calling the server (SOAP-RPC style literal) SOAP-RPC style messages which have C<> cannot be used without a little help. However, one extra definition per procedure call suffices. This a complete code example, although you need to fill in some specifics about your environment. If you have a WSDL file, then it will be a little simpler, see L. # You probably need these use XML::Compile::SOAP11::Client; use XML::Compile::Transport::SOAPHTTP; use XML::Compile::Util qw/pack_type/; # Literal style RPC my $outtype = pack_type $MYNS, 'myFunction'; my $intype = pack_type $MYNS, 'myFunctionResponse'; my $style = 'rpc-literal'; # Encoded style RPC (see next section on these functions) my $outtype = \&my_pack_params; my $intype = \&my_unpack_params; my $style = 'rpc-encoded'; # For all RPC calls, you need this only once (or have a WSDL): my $transp = XML::Compile::Transport::SOAPHTTP->new(...); my $http = $transp->compileClient(...); my $soap = XML::Compile::SOAP11::Client->new(...); my $send = $soap->compileMessage('SENDER', style => $style, ...); my $get = $soap->compileMessage('RECEIVER', style => $style, ...); # Per RPC procedure my $myproc = $soap->compileClient ( name => 'MyProc' , encode => $send, decode => $get, transport => $http , rpcout => $outtype, rpcin => $intype ); my $answer = $myproc->(@parameters); # as document style Actually, the C<< @paramers >> are slightly less flexible as in document style SOAP. If you use header blocks, then the called CODE reference will not be able to distinguish between parameters for the RPC block and parameters for the header blocks. Therefore, in that situation, you MUST separate the rpc data explicitly as one argument. my $answer = $trade_price ->( {symbol => 'IBM'} # the RPC package implicit , transaction => 5 # in the header ); my $answer = $trade_price # RPC very explicit ->(rpc => {symbol => 'IBM'}, transaction => 5); When the number of arguments is odd, the first is indicating the RPC element, and the other pairs refer to header blocks. The C<$answer> structure may contain a C entry, or a decoded datastructure with the results of your query. One call using Data::Dumper will show you more than I can explain in a few hundred words. =head3 Calling the server (SOAP-RPC style, encoded) SOAP-RPC is a simplification of the interface description: basically, the interface is not described at all, but left to good communication between the client and server authors. In strongly typed languages, this is quite simple to enforce: the client side and server side use the same method prototypes. However, in Perl we are blessed to go without these strongly typed prototypes. The approach of SOAP::Lite, is to guess the types of the passed parameters. For instance, "42" will get passed as Integer. This may lead to nasty problems: a float parameter "2.0" will get passed as integer "2", or a string representing a house number "8" is passed as an number. This may not be accepted by the SOAP server. So, using SOAP-RPC in L will ask a little more effort from you: you have to state parameter types explicitly. In the F directory, you find a detailed example. You have to create a CODE ref which produces the message, using methods defined provided by L. =head3 Faults (Document and RPC style) Faults and headerfaults are a slightly different story: the type which is specified with them is not of the fault XML node itself, but of the C sub-element within the standard fault structure. When producing the data for faults, you must be aware of the fact that the structure is different for SOAP1.1 and SOAP1.2. When interpreting faults, the same problems are present, although the implementation tries to help you by hiding the differences. Check whether SOAP1.1 or SOAP1.2 is used by looking for a C (SOAP1.1) or a C (SOAP1.2) field in the data: if(my $fault = $got->{Fault}) { if($fault->{faultcode}) { ... SOAP1.1 ... } elsif($fault->{Code}) { ... SOAP1.2 ... } else { die } } In either protocol case, the following will get you at a compatible structure in two steps: if(my $fault = $got->{Fault}) { my $decoded = $got->{$fault->{_NAME}}; print $decoded->{code}; ... } See the respective manuals L and L for the hairy details. But one thing can be said: when the fault is declared formally, then the C<_NAME> will be the name of that part. =head2 SOAP without WSDL (Document style) See the manual page of L to see how simple you can use this module when you have a WSDL file at hand. The creation of a correct WSDL file is NOT SIMPLE. When using SOAP without WSDL file, it gets a little bit more complicate to use: you need to describe the content of the messages yourself. The following example is used as test-case C, directly taken from the SOAP11 specs section 1.3 example 1. # for simplification my $TestNS = 'http://test-types'; use XML::Compile::Util qw/SCHEMA2001/; my $SchemaNS = SCHEMA2001; First, the schema (hopefully someone else created for you, because they can be quite hard to create correctly) is in file C Ok, now the program you create the request: use XML::Compile::SOAP11; use XML::Compile::Util qw/pack_type/; my $soap = XML::Compile::SOAP11->new; $soap->schemas->importDefinitions('myschema.xsd'); my $get_price = $soap->compileMessage ( 'SENDER' , header => [ transaction => pack_type($TestNS, 'Transaction') ] , body => [ request => pack_type($TestNS, 'GetLastTradePrice') ] , mustUnderstand => 'transaction' , destination => [ transaction => 'NEXT http://actor' ] ); C is used in the WSDL terminology, indicating this message is an input message for the server. This C<$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 L if you have no clue how it should look) So: let's send this: # insert your data my %data_in = (transaction => 5, request => {symbol => 'DIS'}); my %data_in = (transaction => 5, symbol => 'DIS'); # alternative # create a XML::LibXML tree my $xml = $get_price->(\%data_in, 'UTF-8'); print $xml->toString; And the output is: 5 DIS Some transport protocol will sent this data from the client to the server. See L, as one example. On the SOAP server side, we will parse the message. The string C<$soap> contains the XML. The program looks like this: my $server = $soap->compileMessage # create once ( 'RECEIVER' , header => [ transaction => pack_type($TestNS, 'Transaction') ] , body => [ request => pack_type($TestNS, 'GetLastTradePrice') ] ); my $data_out = $server->($soap); # call often Now, the C<$data_out> reference on the server, is stucturally exactly equivalent to the C<%data_in> from the client. =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