XML::C...::SOAP(3pm)
β¨ XML::Compile::SOAP β¨ β the whole manual, bestie edition π
okay so. you're looking at XML::Compile::SOAP(3pm) from the User Contributed Perl Documentation, and let me tell you, this is the base-class for SOAP implementations. it's giving founding mother. it's giving blueprint. the other SOAP modules are literally just standing on her shoulders. π
πΈ NAME πΈ
XML::Compile::SOAP β bestie, it's the base-class for SOAP implementations. that's the whole name. short, iconic, no notes.
π¦ INHERITANCE π¦
so XML::Compile::SOAP is extended by these two:
XML::Compile::SOAP11XML::Compile::SOAP12
like, they're the daughters. the heirs. the ones who actually do the thing. π
β¨ SYNOPSIS β¨
SOAP1.[12] and WSDL1.1 over HTTP
okay here's the whole flow, verbatim, no cap:
# !!! The next steps are only required when you do not have
# !!! a WSDL. See XML::Compile::WSDL11 if you have a WSDL.
# !!! Without WSDL file, you need to do a lot manually
use XML::Compile::SOAP11::Client;
my $client = XML::Compile::SOAP11::Client->new;
$client->schemas->importDefinitions(...);
use XML::Compile::Util qw/pack_type/;
my $h1el = pack_type $myns, $some_element;
my $b1el = "{$myns}$other_element"; # same, less clean
my $encode_query = $client->compileMessage
( 'SENDER'
, style => 'document' # default
, 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 $transport = XML::Compile::Transport::SOAPHTTP
->new(address => $server);
my $http = $transport->compileClient(action => ...);
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; # discover a HASH with h2 and b2!
if($answer->{Fault}) ... # when an error was reported
# Simplify your life: combine above into one call
# Also in this case: if you have a WSDL, this is created
# for you. $wsdl->compileClient('MyFirstCall');
my $call = $client->compileClient
( kind => 'request-response' # default
, name => 'MyFirstCall'
, encode => $encode_query
, decode => $decode_response
, transport => $http
);
# !!! Usage, with or without WSDL file the same
my $result = $call->(@query) # SCALAR only the result
print $result->{h2}->{...};
print $result->{b2}->{...};
my ($result, $trace) = $call->(...); # LIST will show trace
# $trace is an XML::Compile::SOAP::Trace object
β οΈ heads up bestie: those# !!!comments are doing a LOT of heavy lifting. if you do have a WSDL, go look atXML::Compile::WSDL11instead of raw-dogging it manually. this path is the manual one. it's giving DIY. π¨
π DESCRIPTION π
okay so what is this module actually doing. it handles the SOAP protocol. the very first implementation is SOAP1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/), which β real talk β is still the one everyone uses most. and the SOAP1.2 definition (http://www.w3.org/TR/soap12/) ships in a whole separate distribution called XML::Compile::SOAP12. slay, modular queen. π
now, be aware β there are three kinds of SOAP and you need to know which one you're in:
- Document style (literal) SOAP β there's a WSDL file that explicitly types every single out-going and in-coming message. very easy to use. the blessed path. π
- RPC style SOAP literal β the body of the message has an extra element wrapper, but the content is also well defined. still chill.
- RPC style SOAP encoded β the sent data is nowhere described formally. it's constructed in some ad-hoc way. it's giving chaos. it's giving vibes-based serialization. π
don't forget to have a look at the examples in the examples/ directory included in the distribution β genuinely go look, they ate. π
and like, please support the development work by submitting bug-reports, patches, and (if available) a donation. π«Ά bestie behavior π«Ά
π METHODS π
π§Έ Constructors
$obj->new(%options)
creates a new SOAP object. but here's the tea β you have to instantiate either the SOAP11 or the SOAP12 sub-class of this, because there are quite some differences (which can be hidden for you π ).
here's the option table, default column included:
-Option --Default
media_type application/soap+xml
schemas created internally
and the details, one by one:
media_type => MIMETYPEβ the media type. defaults toapplication/soap+xml. πschemas => "XML::Compile::Cache" objectβ use this when you have already processed some schema definitions. otherwise, you can add schemas later with$soap->schemas->importDefinitions(). heads up: the Cache object must haveany_elementandany_attributeset to'ATTEMPT'. that's not optional, that's a requirement.
XML::Compile::SOAP->register($uri, $envns)
declares an operation type β being an (WSDL specific) $uri and an envelope namespace. β¨
π Accessors
$obj->mediaType()
gets you the media type. that's it. that's the whole thing. π
$obj->schemas()
returns the XML::Compile::Cache object which contains the knowledge about the types. that's your type-brain. π§
$obj->version()
gets you the version. short king. π
π¨ Single message
$obj->compileMessage( <'SENDER'|'RECEIVER'>, %options )
so the payload here is defined explicitly, where all headers and bodies are described in detail. when you have a WSDL file, these ENTRIES are generated automatically β but you can still modify and extend them (because WSDL files are often incomplete, no shade, just facts π).
to make your life easy, the ENTRIES use a label (a free to choose key, the part name 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 "any" element in the schema, and therefore you will need to explicitly specify the element to be processed. iykyk. πΈ
as %options, you can specify any listed here, but also anything which is accepted by XML::Compile::Schema::compile(), like sloppy_integers => 1 and hooks. these are applied to all header and body elements (not to the SOAP wrappers). π«Ά
the default table:
-Option --Default
body []
destination []
faults []
header undef
mustUnderstand []
procedure undef
role ULTIMATE
roles []
now the full rundown:
body => ENTRIES|HASHβ an 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. πdestination => ARRAY-OF-PAIRSβ Writers only. indicates 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, specifying an entry label followed by an actor (soap1.1) or role (soap1.2) URI. you may use the predefined actors/roles, like 'NEXT'. see roleURI() and roleAbbreviation(). β¨
faults => ENTRIES|HASHβ 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 be specified here, but the returned information structure is larger and differs per SOAP implementation. so don't assume it's the same shape across versions, bestie.header => ENTRIES|HASHβ an 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. π
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 to1(soap1.1) or"true"(soap1.2). no cap, they will. πprocedure => TYPEβ required in rpc style, when there is no"body"which contains the procedure name (when the RPC info does not come from a WSDL). required, bestie. don't forget it.role => URI|ARRAY-OF-URIβ Readers only. one or more URIs, specifying the role(s) your application has in the process. only when your role contains"ULTIMATE", the body is parsed. otherwise, the body is returned as an 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, a fault is returned automatically. in that case, the call to the compiled subroutine will return undef. so yeah β check for undef, okay?
roles => ARRAY-OF-URIβ alternative for option"role". same energy, different key. π¦
$obj->messageStructure($xml)
XML::Compile::SOAP->messageStructure($xml)
returns a HASH with some collected information from a complete SOAP message (XML::LibXML::Document or XML::LibXML::Element). currently, the HASH contains a "header" and a "body" key, with each an ARRAY of element names which were found in the header resp. body. π¬
π§ Helpers
π Transcoding
$obj->replyMustUnderstandFault($type)
produces an error structure to be returned to the sender. it's the polite way to say "bestie i literally do not understand this header." π
$obj->roleAbbreviation($uri)
translates a role $uri into a simple string, if predefined. see roleURI(). β¨
$obj->roleURI($uri|STRING)
translates actor/role/destination abbreviations into URIs. various SOAP protocol versions have different pre-defined STRINGs, which can be abbreviated for readability. returns the unmodified $uri in all other cases. so if it doesn't know it, it hands it right back to you, untouched. π
SOAP11 only defines "NEXT". SOAP12 defines "NEXT", "NONE", and "ULTIMATE". that's the whole list, that's the canon. π
β¨ DETAILS β¨
πΈ SOAP introduction πΈ
okay so bestie, sit down, hydrate, because we're about to talk about SOAP and it's a whole thing. The specs for SOAP1.1 and WSDL1.1 are, like, thin. But the number of special constructs? astronomical. And obviously every single one of them is poorly documented. π SOAP 1.2 has a way better specification, no cap β but honestly nobody uses it. And WSDL2? Never seen it in real life. Not once. π
WSDL defines two kinds of messages: document style SOAP and rpc style SOAP.
- Document style SOAP β the messages are described in great detail in the WSDL. Every message component is defined in Schemas. The worst things you can (and will) encounter are
anyschema elements, which require additional manual processing. The way that's gonna be your problem... yeah. - "RPC Literal" β behaves very much the same way as document style soap, but it has one extra wrapper inside the Body of the message.
- "Encoded SOAP-RPC" β okay this one is a very different ball-game. It's simple to use with strongly typed languages, to exchange data when you create both the client software and the server software. You can simply autogenerate the data encoding. But clients written by third parties have to find the documentation on how to use the encoded 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. π«
Encoded RPC messages 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. Periodt.
π§ Supported servers π§
Only the commercial hype speaks about SOAP in very positive words. π However, the "industry quality" of these modern "technologies" clearly demonstrates the lack of education and experience most programmers and designers have. This is clearly visible in many, many bugs you will encounter when working with schemas and WSDLs. It's giving chaos, honestly.
Interoperability of SOAP clients and servers is more "trial and error" and "manually fixing" than it should be. For instance, a server may report internal server errors back to the client... but a WSDL does not tell you which namespace/schema is used for these errors. Both BEA and SharePoint servers produce illegal SOAP responses! It is a sad story. π
To be able to install some fixes, you can specify a server type via XML::Compile::SOAP::Operation::new(server_type), XML::Compile::WSDL11::new(server_type), or [3.06] XML::Compile::WSDL11::operations(server_type).
The following server types are currently understood:
"BEA", Oracle"SharePoint", MicroSoft"XML::Compile::Daemon"
Examples:
my $wsdl = XML::Compile::WSDL11->new($wsdlfn, server_type => 'SharePoint');
my $op = XML::Compile::SOAP11::Operation->new(..., server_type => 'BEA');
my @op = XML::Compile::WSDL11->operations(server_type => 'SharePoint')
[3.17] Be warned: the licenses of some server_type schema's are unknown or unclear. At least, they touch commercial products hence can better not be released in a (Debian) Linux distribution, even not as non-free. Therefore, you need to install XML::Compile::Licensed from CPAN yourself.
π 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 frustrated many projects in the past when they grew over a certain size... at a certain size, it becomes too hard to think of good distinguishable names. In such case, you must be happy when you can place those names in a context, and use the same naming in separate contexts without confusion. Iconic design choice, honestly.
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. In a schema XSD file, look for the "targetNamespace" attribute of the "schema" 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 for the namespace URI. In programs, you can simply assign short variable names to long URIs, so we do not need that trick. π¦
Within your program, you use
$MYNS = '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 XML::Compile::Util module provides a helpful methods and constants, as does the XML::Compile::SOAP::Util.
π Client and Server implementations π
To learn how to create clients in SOAP, read the DETAILS section in XML::Compile::SOAP::Client. The client implementation is platform independent. β¨
Servers can be created with the external XML::Compile::SOAP::Daemon distribution. Those servers are based on Net::Server. Can be used to create a test-server in a few minutes... or production server. Main character energy for real.
Don't forget to have a look at the examples in the examples/ directory included in the distribution. π
π Use of wildcards (any and anyAttribute) π
Start reading about wildcards in XML::Compile. When you receive a message which contains "ANY" elements, an attempt will be made to decode it automatically. Sending messages which contain "ANY" fields is harder... you may try hooks or something more along these lines:
my $doc = XML::LibXML::Document->new('1.0', 'UTF-8');
my $type = pack_type $ns, $local;
my $node = $wsdl->writer($type)->($doc, $value);
my $message = { ..., $type => $node };
my $call = $wsdl->compileClient('myOpToCall');
my ($answer, $trace) = $call->(_doc => $doc, message => $message);
Here, $type is the type of the element which needs to be filled in on a spot where the schema defines an "ANY" element. You need to include the full typename as key in the HASH (on the right spot) and a fully prepared $node, an XML::LibXML::Element, as the value.
You see that the $doc which is created to produce the special node in the message is also passed to the $call. The call produces the message which is sent and needs to use the same document object as the node inside it. The chances are that when you forget to pass the $doc it still works... but you may get into characterset problems and such. π
π SEE ALSO π
This module is part of XML-Compile-SOAP distribution version 3.28, built on August 01, 2022. Website: http://perl.overmeer.net/CPAN/
π«Ά LICENSE π«Ά
Copyrights 2007-2022 by [Mark Overmeer <markov@cpan.org>]. 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://dev.perl.org/licenses/
okay bestie that's a wrap π this one came to you courtesy of perl v5.34.0 on 2022-08-04, filed under XML::C...::SOAP(3pm) β go forth and fix those illegal SOAP responses, you've got this πβ¨
π¦ where this page comes from
- debian bookworm: libxml-compile-soap-perl 3.28+ds-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libxml-compile-soap-perl 3.28+ds-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libxml-compile-soap-perl 3.28+ds-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libxml-compile-soap-perl 3.28+ds-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libxml-compile-soap-perl 3.28+ds-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms