import SOAP-WSDL 2.00_11 from CPAN

git-cpan-module:   SOAP-WSDL
git-cpan-version:  2.00_11
git-cpan-authorid: MKUTTER
git-cpan-file:     authors/id/M/MK/MKUTTER/SOAP-WSDL-2.00_11.tar.gz
This commit is contained in:
Martin Kutter
2009-12-12 19:47:49 -08:00
committed by Michael G. Schwern
parent 7ba1959888
commit c2da74b5ae
64 changed files with 5965 additions and 410 deletions
+18 -17
View File
@@ -598,27 +598,14 @@ The following facets have no influence yet:
=head1 SEE ALSO
There are lots of SOAP Clients on CPAN, lately.
You may wish to look at the following:
=head2 Related projects
=over
=item * L<SOAP::Lite|SOAP::Lite>
Full featured SOAP-library, little WSDL support. Supports rpc-encoded style only. Many protocols supported.
=item * L<SOAP::Message|SOAP::Message>
A very basic SOAP library without transport facilities.
Handy if you got your XML message ready and just need an envelope around it.
=item * L<SOAP::MySOAP|SOAP::MySOAP>
An extremely basic SOAP client module - just HTTP support, no encoding / decoding,
HTTP headers have to be set as arguments to 'new'
=item * <XML::Compile::WSDL|XML::Compile::WSDL>
A promising-looking approach derived from a cool functional DOM-based XML schema parser.
@@ -629,6 +616,20 @@ Not yet finished at the time of writing - but you may wish to give it a try, esp
if you need to adhere very closely to the XML Schema / WSDL specs.
=back
=head2 Sources of documentation
=over
=item * SOAP::WSDL homepage at sourceforge.net
L<http://soap-wsdl.sourceforge.net>
=item * SOAP::WSDL forum at CPAN::Forum
L<http://www.cpanforum.com/dist/SOAP-WSDL>
=back
=head1 ACKNOWLEDGMENTS
@@ -661,9 +662,9 @@ Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 143 $
$Rev: 176 $
$LastChangedBy: kutterma $
$Id: WSDL.pm 143 2007-08-13 18:43:20Z kutterma $
$Id: WSDL.pm 176 2007-08-31 15:28:29Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL.pm $
=cut
+4 -1
View File
@@ -78,12 +78,15 @@ sub init {
my @args = @_;
foreach my $value (@args)
{
die $value if (not defined ($value->{ Name }));
die @args if (not defined ($value->{ Name }));
if ($value->{ Name } =~m{^xmlns\:}xms) {
die $xmlns_of{ ident $self }
if ref $xmlns_of{ ident $self } ne 'HASH';
# add namespaces
$xmlns_of{ ident $self }->{ $value->{ Value } } =
$value->{ LocalName };
next;
}
elsif ($value->{ Name } =~m{^xmlns$}xms) {
+149 -54
View File
@@ -8,28 +8,42 @@ use LWP::UserAgent;
use HTTP::Request;
use Scalar::Util qw(blessed);
use SOAP::WSDL::Envelope;
use SOAP::WSDL::Factory::Serializer;
use SOAP::WSDL::Factory::Transport;
use SOAP::WSDL::Expat::MessageParser;
use SOAP::WSDL::SOAP::Typelib::Fault11;
# Package globals for speed...
# Package global for speed and memory savings.
# But should be factored out into serializer/deserializer...
my $PARSER;
my %class_resolver_of :ATTR(:name<class_resolver> :default<()>);
my %no_dispatch_of :ATTR(:name<no_dispatch> :default<()>);
my %outputxml_of :ATTR(:name<outputxml> :default<()>);
my %proxy_of :ATTR(:name<proxy> :default<()>);
my %transport_of :ATTR(:name<transport> :default<()>);
my %endpoint_of :ATTR(:name<endpoint> :default<()>);
my %soap_version_of :ATTR(:get<soap_version> :init_attr<soap_version> :default<'1.1'>);
my %fault_class_of :ATTR(:name<fault_class> :default<SOAP::WSDL::SOAP::Typelib::Fault11>);
my %trace_of :ATTR(:set<trace> :init_arg<trace> :default<()> );
my %on_action_of :ATTR(:name<on_action> :default<()>);
my %content_type_of :ATTR(:name<content_type> :default<text/xml; charset=utf8>);
#/#trick editors
my %content_type_of :ATTR(:name<content_type> :default<text/xml; charset=utf8>); #/#trick editors
my %serializer_of :ATTR(:name<serializer> :default<()>);
# TODO remove when preparing 2.01
sub outputtree { warn 'outputtree is deprecated and'
. 'will be removed before reaching v2.01 !' }
sub BUILD {
my ($self, $ident, $attrs_of_ref) = @_;
if (exists $attrs_of_ref->{ proxy }) {
$self->set_proxy( $attrs_of_ref->{ proxy } );
delete $attrs_of_ref->{ proxy };
}
}
sub get_trace {
my $ident = ident $_[0];
@@ -39,6 +53,44 @@ sub get_trace {
: sub { warn @_ }
: ()
}
sub get_proxy {
return $_[0]->get_transport();
}
sub set_proxy {
my ($self, @args_from) = @_;
my $ident = ident $self;
# remember old value to return it later - Class::Std does so, too
my $old_value = $transport_of{ $ident };
# accept both list and list ref args
@args_from = @{ $args_from[0] } if ref $args_from[0];
# remember endpoint
$endpoint_of{ $ident } = $args_from[0];
# set transport - SOAP::Lite works similar...
$transport_of{ $ident } = SOAP::WSDL::Factory::Transport
->get_transport( @args_from );
return $old_value;
}
sub set_soap_version {
my $ident = ident shift;
# remember old value to return it later - Class::Std does so, too
my $soap_version = $soap_version_of{ $ident };
# re-setting the soap version invalidates the
# serializer object
delete $serializer_of{ $ident };
$soap_version_of{ $ident } = shift;
return $soap_version;
}
# Mimic SOAP::Lite's behaviour for getter/setter routines
SUBFACTORY: {
@@ -69,60 +121,79 @@ sub call {
: (@_>1)
? { @_ }
: $_[0];
my $header = {};
my $soap_action;
my ($soap_action, $operation);
my $trace_sub = $self->get_trace();
my $envelope = SOAP::WSDL::Envelope->serialize( $method, $data );
if (blessed $data
&& $data->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType'))
{
# TODO replace by something derived from binding - this is just a
# workaround...
$soap_action = join '/', $data->get_xmlns(), $method;
}
else {
$envelope = SOAP::WSDL::Envelope->serialize( $method, $data );
# TODO add something like SOAP::Lite's on_action mechanism
$soap_action = $on_action_of{$ident}->( $self, $method ) if ($on_action_of{$ident});
}
if (ref $method eq 'HASH') {
$soap_action = $method->{ soap_action };
$operation = $method->{ operation }
}
else {
$operation = $method;
}
$serializer_of{ $ident } ||= SOAP::WSDL::Factory::Serializer->get_serializer({
soap_version => $self->get_soap_version(),
});
my $envelope = $serializer_of{ $ident }->serialize({
method => $operation,
body => $data,
header => $header,
});
return $envelope if $self->no_dispatch();
# get response via transport layer
# maybe we should return a result with the following methods:
# - result: returns the result of the call (like SOAP::Lite, but as
# object tree)
# - header: returns the content of the SOAP header
# - fault: returns the result of the call if a SOAP fault is sent back
# by the server. Retuns undef (nothing) if the call has been
# processed without errors.
my $ua = LWP::UserAgent->new();
my $request = HTTP::Request->new( 'POST',
$self->get_proxy(),
[ 'Content-Type', $content_type_of{ $ident },
'Content-Length', length($envelope),
'SOAPAction', $soap_action,
],
$envelope );
$trace_sub->( $request->as_string() ) if $trace_of{ $ident }; # if for speed
my $response = $ua->request( $request );
$trace_sub->( $response->as_string() ) if $trace_of{ $ident }; # if for speed
return $response->content() if ($self->outputxml() );
# try to guess soap_action if not given
if (not defined $soap_action) {
$soap_action = (blessed $data
&& $data->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType'))
? $soap_action = join '/', $data->get_xmlns(), $operation
: ($on_action_of{$ident})
? $soap_action = $on_action_of{$ident}->( $self, $operation )
: "";
}
# always quote SOAPAction header.
# WS-I BP 1.0 R1109
$soap_action =~s{\A(:?"|')?}{"}xms;
$soap_action =~s{(:?"|')?\Z}{"}xms;
# get response via transport layer.
# Normally, SOAP::Lite's transport layer is used, though users
# may provide their own.
my $transport = $self->get_transport();
my $response = $transport->send_receive(
endpoint => $self->get_endpoint(),
content_type => $content_type_of{ $ident },
envelope => $envelope,
action => $soap_action,
on_receive_chunk => sub {} # optional, may be used for parsing large responses as they arrive.
# might not be supported by all transport layers...
# and, of course, only is of interest for chunk parsers -
# namely ExpatNB and XML::LibXML's Push parser interface...
);
return $response if ($self->outputxml() );
$PARSER->class_resolver( $self->get_class_resolver() );
# if we had no success (Transport layer error status code)
# if we had no success (Transport layer error status code)
# or if transport layer failed
if ($response->code() != 200) {
if ( ! $transport->is_success() ) {
# Try deserializing response - there may be some
if ($response->content) {
eval { $PARSER->parse( $response->content() ); };
if ( $response ) {
eval { $PARSER->parse( $response ); };
return $PARSER->get_data() if (not $@);
warn "could not deserialize response: $@";
return $fault_class_of{$ident}->new({
faultcode => 'soap:Server',
faultactor => 'urn:localhost',
faultstring => "Error deserializing message: $@. \n"
. "Message was: \n$response"
});
};
# generate & return fault if we cannot serialize response
@@ -131,11 +202,10 @@ sub call {
faultcode => 'soap:Server',
faultactor => 'urn:localhost',
faultstring => 'Error sending / receiving message: '
. $response->message()
#$soap->transport->message()
. $transport->message()
});
}
eval { $PARSER->parse( $response->content() ) };
eval { $PARSER->parse( $response ) };
# return fault if we cannot deserialize response
if ($@) {
@@ -161,6 +231,31 @@ SOAP::WSDL::Client - SOAP::WSDL's SOAP Client
=head1 METHODS
=head2 call
$soap->call( \%method, \@parts );
%method is a hash with the following keys:
Name Description
----------------------------------------------------
operation operation name
soap_action SOAPAction HTTP header to use
style Operation style. One of (document|rpc)
use SOAP body encoding. One of (literal|encoded)
The style and use keys have no influence yet.
@parts is a list containing the elements of the message parts.
For backward compatibility, call may also be called as below:
$soap->call( $method, \@parts );
In this case, $method is the SOAP operation name, and the SOAPAction header
is guessed from the first part's namespace and the operation name (which is
mostly correct, but may fail). Operation style and body encoding are assumed to
be document/literal
=head2 Configuration methods
@@ -286,9 +381,9 @@ Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 139 $
$Rev: 176 $
$LastChangedBy: kutterma $
$Id: Client.pm 139 2007-08-12 19:15:59Z kutterma $
$Id: Client.pm 176 2007-08-31 15:28:29Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Client.pm $
=cut
+49 -7
View File
@@ -21,20 +21,35 @@ sub __create_new {
}
sub __create_methods {
my ($package, %parts_of) = @_;
my ($package, %info_of) = @_;
no strict qw(refs);
for my $method (keys %parts_of){
for my $method (keys %info_of){
my ($soap_action, @parts);
# up to 2.00_10 we had list refs...
if (ref $info_of{ $method }eq 'HASH') {
@parts = @{ $info_of{ $method }->{ parts } };
$soap_action = $info_of{ $method }->{ soap_action };
}
else {
@parts = @{ $info_of{ $method } };
$soap_action = ();
}
*{ "$package\::$method" } = sub {
my $self = shift;
my @param = map {
my $data = shift || {};
eval "require $_";
$_->new( $data );
} @{ $parts_of{ $method } };
} @parts;
return $self->SUPER::call( $method, @param );
return $self->SUPER::call( {
operation => $method,
soap_action => $soap_action,
}, @param );
}
}
}
@@ -47,13 +62,40 @@ __END__
=head1 NAME
SOAP::WSDL::Client::Base - Base client for WSDL-based SOAP access
SOAP::WSDL::Client::Base - Factory class for WSDL-based SOAP access
=head1 SYNOPSIS
package MySoapClient;
package MySoapInterface;
use SOAP::WSDL::Client::Base;
__PACKAGE__->__create_new(
proxy => 'http://somewhere.over.the.rainbow',
class_resolver => 'Typemap::MySoapInterface'
);
__PACKAGE__->__create_methods( qw(one two three) );
1;
=cut
=head1 DESCRIPTION
Factory class for creating interface classes. Should probably be renamed to
SOAP::WSDL::Factory::Interface...
=head1 LICENSE
Copyright 2004-2007 Martin Kutter.
This file is part of SOAP-WSDL. You may distribute/modify it under
the same terms as perl itself
=head1 AUTHOR
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 176 $
$LastChangedBy: kutterma $
$Id: Base.pm 176 2007-08-31 15:28:29Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Client/Base.pm $
=cut
+20 -8
View File
@@ -4,7 +4,7 @@ use strict;
use warnings;
use Carp;
use File::Basename;
use File::Path;
use File::Path;
use List::Util qw(first);
use Class::Std::Storable;
use base qw(SOAP::WSDL::Base);
@@ -116,7 +116,17 @@ sub _create_interface {
#
my %operations = ();
for my $operation ( @{ $operation_ref } ) {
my $operation_name = $operation->get_name();
my $operation_name = $operation->get_name();
my $soap_operation = $operation->first_operation();
$operations{ $operation_name }->{ style } = $soap_operation
? $soap_operation->get_style()
: undef;
$operations{ $operation_name }->{ soap_action } = $soap_operation
? $soap_operation->get_soapAction()
: undef;
my $port_op = first { $_->get_name() eq $operation_name } @{ $port_operation_ref };
$operations{ $operation_name }->{ documentation } = $port_op->get_documentation();
@@ -151,9 +161,6 @@ sub _create_interface {
}
}
# use Data::Dumper;
# die Dumper \%operations;
my $template = <<'EOT';
package [% interface_prefix %][% service.get_name.replace('\.', '::') %];
@@ -174,9 +181,14 @@ sub new {
}
__PACKAGE__->__create_methods(
[% FOREACH name = operations.keys -%]
[% name %] => [ [% FOREACH class = operations.$name.input.class %]'[% class %]', [% END %]],
[% END %]
[% FOREACH name = operations.keys -%]
[% name %] => {
parts => [ [% FOREACH class = operations.$name.input.class %]'[% class %]', [% END %]],
soap_action => '[% operations.$name.soap_action %]',
style => '[% operations.$name.style %]',
# use => '', # use not implemented yet
},
[% END %]
);
1;
+13 -7
View File
@@ -28,8 +28,7 @@ sub _initialize {
my $current = undef;
my $ignore = [ 'Envelope', 'Body' ]; # top level elements to ignore
my $list = []; # node list
my $path = []; # current path (without
# number)
my $path = []; # current path
my $skip = 0; # skip elements
# use "globals" for speed
@@ -84,7 +83,7 @@ sub _initialize {
$current = $_class->new({ %_attrs }); # set new current object
# remember top level element
defined $self->{ data }
exists $self->{ data }
or ($self->{ data } = $current);
},
@@ -143,6 +142,13 @@ sub parsefile {
return $_[0]->{ data };
}
# SAX-like aliases
sub parse_string;
*parse_string = \&parse;
sub parse_file;
*parse_file = \&parsefile;
sub get_data {
return $_[0]->{ data };
}
@@ -202,9 +208,9 @@ This module may be used under the same terms as perl itself.
$ID: $
$LastChangedDate: $
$LastChangedRevision: $
$LastChangedBy: $
$LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $
$LastChangedRevision: 176 $
$LastChangedBy: kutterma $
$HeadURL: $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/MessageParser.pm $
+4 -4
View File
@@ -67,9 +67,9 @@ This module may be used under the same terms as perl itself.
$ID: $
$LastChangedDate: $
$LastChangedRevision: $
$LastChangedBy: $
$LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $
$LastChangedRevision: 176 $
$LastChangedBy: kutterma $
$HeadURL: $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/MessageStreamParser.pm $
+213
View File
@@ -0,0 +1,213 @@
#!/usr/bin/perl
package SOAP::WSDL::Expat::MessageSubParser;
use strict;
use warnings;
use SOAP::WSDL::XSD::Typelib::Builtin;
use XML::Parser::Expat;
sub new {
my ($class, $args) = @_;
my $self = {};
bless $self, $class;
return $self;
}
# create handlers via currying - XML::Compiled is a good teacher...
#
# A handler has to know
# - the order of it's child elements
# - the classes for these child elements
# - the handlers for these child elements (sub refs)
# order is checked if provided
sub start_tag {
my $self = shift;
my $arg_ref = shift;
my $CHILD_ORDER = $arg_ref->{ order } || [];
my $CHILD_CLASS = $arg_ref->{ class_of } || {};
my $CHILD_HANDLER = $arg_ref->{ handler_of };
my $CHILD_OCCURS = $arg_ref->{ occurs_of } || {};
my $CHILD_INDEX = 0;
return sub {
# parser, element, attrs
my ($prefix, $localname) = split m{:}xms , $_[1];
$localname ||= $_[1];
=pod
# # implement better checks...
# if (@{ $CHILD_ORDER }) {
# if ($CHILD_ORDER->[$CHILD_INDEX] ne $localname) {
# if (! $CHILD_ORDER->[++$CHILD_INDEX]
# || $CHILD_ORDER->[$CHILD_INDEX] ne $localname) {
# die "misplaced xml element " . $parser->recognized_string()
# . " at line "
# . $parser->current_line()
# . " column " . $parser->current_column() , "\n"
# , "Element order: " . join(',' , @{ $CHILD_ORDER }), "\n"
# }
# }
# }
#
# if (%{ $CHILD_OCCURS }) {
# die "too many occurances of $localname at line "
# . $parser->current_line()
# . " column " . $parser->current_column() , "\n"
# if (not --$CHILD_OCCURS->{ $localname }->{ max });
#
# # min must be checked in end_element !
# $CHILD_OCCURS->{ $localname }->{ min }--
# if ($CHILD_OCCURS->{ $localname }->{ min });
# }
=cut
# remove this some day
return if ($localname eq 'Envelope');
return if ($localname eq 'Body');
# step down in tree (remember current)
push @{ $self->{ list } }, $self->{ current };
$self->{ current } = $CHILD_CLASS->{ $localname }->new({ @_[2..$#_] });
# Set (and remember) next state
push @{ $self->{ handlers } }, $CHILD_HANDLER->{ $localname };
$_[0]->setHandlers( %{ $CHILD_HANDLER->{ $localname } } );
};
}
# characters is a good candidate for replacement when not needed -
# expat calls it for those whitespaces in non-mixed-content-elements, too
sub characters {
my $self = shift;
return sub { $self->{ characters } .= $_[1] };
}
# end_tag is a somewhat generic thingy - don't know whether we should
# curry it, and whether this will speed us up...
sub end_tag {
my $self = shift;
return sub {
# step down handler hierarchy
pop @{ $self->{ handlers } };
# restore state: set handler to last handler
$_[0]->setHandlers( %{ $self->{ handlers }->[ -1 ] } );
my ($prefix, $localname) = split m{:}xms , $_[1];
$localname ||= $_[1]; # for non-prefixed elements
# we only have characters if we need them - if not Char handler
# has to be set to undef
$self->{ current }->set_value( $self->{ characters } )
if ($self->{ characters });
# empty temp characters
undef $self->{ characters };
# return if we're top node
# This one easily handles ignores for us, too...
#
# Hmm... could be replaced by something else, maybe ???
# Maybe by defining an empty end_tag handler for the top node ?
# Can we do this ???
return if not defined $self->{ list }->[-1];
# set appropriate attribute in last element
# multiple values must be implemented in base class
my $method = "add_$localname";
$self->{ list }->[-1]->$method( $self->{ current } );
# step up in object hierarchy...
$self->{ current } = pop @{ $self->{ list } };
};
}
sub end_top_tag {
my $self = shift;
return sub {};
}
sub initialize {
my ($self, $handler_of_ref, $parser ) = @_;
$parser ||= XML::Parser::Expat->new();
$self->{ list } = undef;
$self->{ current } = undef;
$self->{ characters } = q{}; # empty characters
$self->{ handlers } = [ $handler_of_ref ];
$parser->setHandlers( %$handler_of_ref );
return $parser;
}
sub get_data {
return $_[0]->{ current };
}
1;
=pod
=head1 NAME
SOAP::WSDL::Expat::MessageParser - Convert SOAP messages to custom object trees
=head1 SYNOPSIS
my $parser = SOAP::WSDL::Expat::MessageParser->new({
class_resolver => 'My::Resolver'
});
$parser->parse( $xml );
my $obj = $parser->get_data();
=head1 DESCRIPTION
Real fast expat based SOAP message parser.
See L<SOAP::WSDL::Parser> for details.
=head2 Skipping unwanted items
Sometimes there's unneccessary information transported in SOAP messages.
To skip XML nodes (including all child nodes), just edit the type map for
the message and set the type map entry to '__SKIP__'.
=head1 Bugs and Limitations
=over
=item * Ignores all namespaces
=item * Does not handle mixed content
=item * The SOAP header is ignored
=back
=head1 AUTHOR
Replace the whitespace by @ for E-Mail Address.
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 COPYING
This module may be used under the same terms as perl itself.
=head1 Repository information
$ID: $
$LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $
$LastChangedRevision: 176 $
$LastChangedBy: kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/MessageSubParser.pm $
+219
View File
@@ -0,0 +1,219 @@
#!/usr/bin/perl
package SOAP::WSDL::Expat::MessageSubParser;
use strict;
use warnings;
use SOAP::WSDL::XSD::Typelib::Builtin;
use XML::Parser::Expat;
sub new {
my ($class, $args) = @_;
my $self = {
class_resolver => $args->{ class_resolver }
};
bless $self, $class;
return $self;
}
sub class_resolver {
my $self = shift;
$self->{ class_resolver } = shift;
}
sub _start;
sub _initialize {
my ($self, $parser) = @_;
delete $self->{ data };
my $characters;
my $current = undef;
my $ignore = [ 'Envelope', 'Body' ]; # top level elements to ignore
my $list = []; # node list
my $path = []; # current path (without
# number)
my $skip = 0; # skip elements
# use "globals" for speed
my ($_prefix, $_localname, $_element, $_method,
$_class, $_parser, %_attrs) = ();
no strict qw(refs);
my $start_sub = sub {
($_parser, $_element, %_attrs) = @_;
($_prefix, $_localname) = split m{:}xms , $_element;
# $parser->setHandlers( Start => \&_start );
$_localname ||= $_element; # for non-prefixed elements
# ignore top level elements
if (@{ $ignore } && $_localname eq $ignore->[0]) {
shift @{ $ignore };
return;
}
push @{ $path }, $_localname; # step down in path
return if $skip; # skip inside __SKIP__
# resolve class of this element
$_class = $self->{ class_resolver }->get_class( $path )
or die "Cannot resolve class for "
. join('/', @{ $path }) . " via $self->{ class_resolver }";
# maybe write as "return $skip = join ... if (...)" ?
# would save a BLOCK...
return $skip = join('/', @{ $path }) if ($_class eq '__SKIP__');
push @$list, $current; # step down in tree ()remember current)
$characters = q{}; # empty characters
# Check whether we have a primitive - we implement them as classes
# We could replace this with UNIVERSAL->isa() - but it's slow...
# match is a bit faster if the string does not match, but WAY slower
# if $class matches...
if (index $_class, 'SOAP::WSDL::XSD::Typelib::Builtin', 0 < 0) {
# check wheter there is a CODE reference for $class::new.
# If not, require it - all classes required here MUST
# define new()
# This is the same as $class->can('new'), but it's way faster
*{ "$_class\::new" }{ CODE }
or eval "require $_class" ## no critic qw(ProhibitStringyEval)
or die $@;
}
$current = $_class->new({ %_attrs }); # set new current object
# remember top level element
defined $self->{ data }
or ($self->{ data } = $current);
};
my $char_sub = sub {
return if $skip;
$characters .= $_[1];
};
my $end_sub = sub {
$_element = $_[1];
($_prefix, $_localname) = split m{:}xms , $_element;
$_localname ||= $_element; # for non-prefixed elements
pop @{ $path }; # step up in path
if ($skip) {
return if $skip ne join '/', @{ $path }, $_localname;
$skip = 0;
return;
}
# This one easily handles ignores for us, too...
return if not ref $$list[-1];
# set characters in current if we are a simple type
# we may have characters in complexTypes with simpleContent,
# too - maybe we should rely on the presence of characters ?
# may get a speedup by defining a ident method in anySimpleType
# and looking it up via exists &$class::ident;
if ( $current->isa('SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType') ) {
$current->set_value( $characters );
}
# set appropriate attribute in last element
# multiple values must be implemented in base class
$_method = "add_$_localname";
$$list[-1]->$_method( $current );
$current = pop @$list; # step up in object hierarchy...
};
$parser->setHandlers(
Start => sub {
$_[0]->setHandlers( Start => $start_sub );
$start_sub->(@_) },
Char => $char_sub,
End => $end_sub,
);
return $parser;
}
sub parse {
$_[0]->_initialize( XML::Parser::Expat->new() )->parse( $_[1] );
return $_[0]->{ data };
}
sub parsefile {
$_[0]->_initialize( XML::Parser::Expat->new() )->parsefile( $_[1] );
return $_[0]->{ data };
}
sub get_data {
return $_[0]->{ data };
}
1;
=pod
=head1 NAME
SOAP::WSDL::Expat::MessageParser - Convert SOAP messages to custom object trees
=head1 SYNOPSIS
my $parser = SOAP::WSDL::Expat::MessageParser->new({
class_resolver => 'My::Resolver'
});
$parser->parse( $xml );
my $obj = $parser->get_data();
=head1 DESCRIPTION
Real fast expat based SOAP message parser.
See L<SOAP::WSDL::Parser> for details.
=head2 Skipping unwanted items
Sometimes there's unneccessary information transported in SOAP messages.
To skip XML nodes (including all child nodes), just edit the type map for
the message and set the type map entry to '__SKIP__'.
=head1 Bugs and Limitations
=over
=item * Ignores all namespaces
=item * Does not handle mixed content
=item * The SOAP header is ignored
=back
=head1 AUTHOR
Replace the whitespace by @ for E-Mail Address.
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 COPYING
This module may be used under the same terms as perl itself.
=head1 Repository information
$ID: $
$LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $
$LastChangedRevision: 176 $
$LastChangedBy: kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/SubParser.pm $
+175
View File
@@ -0,0 +1,175 @@
package SOAP::WSDL::Expat::WSDLParser;
use strict;
use warnings;
use Carp;
use SOAP::WSDL::TypeLookup;
use XML::Parser::Expat;
sub new {
my ($class, $args) = @_;
my $self = {};
bless $self, $class;
return $self;
}
sub _initialize {
my ($self, $parser) = @_;
# init object data
$self->{ parser } = $parser;
delete $self->{ data };
# setup local variables for keeping temp data
my $characters = undef;
my $current = undef;
my $list = []; # node list
# TODO skip non-XML Schema namespace tags
$parser->setHandlers(
Start => sub {
my ($parser, $localname, %attrs) = @_;
$characters = q{};
my $action = SOAP::WSDL::TypeLookup->lookup(
$parser->namespace($localname),
$localname
);
return if not $action;
if ($action->{ type } eq 'CLASS') {
eval "require $action->{ class }";
croak $@ if ($@);
my $obj = $action->{ class }->new({ parent => $current })
->init( _fixup_attrs( $parser, %attrs ) );
if ($current) {
# inherit namespace, but don't override
$obj->set_targetNamespace( $current->get_targetNamespace() )
if not $obj->get_targetNamespace();
# push on parent's element/type list
my $method = "push_$localname";
no strict qw(refs);
$current->$method( $obj );
# remember element for stepping back
push @{ $list }, $current;
}
else {
$self->{ data } = $obj;
}
# set new element (step down)
$current = $obj;
}
elsif ($action->{ type } eq 'PARENT') {
$current->init( _fixup_attrs($parser, %attrs) );
}
elsif ($action->{ type } eq 'METHOD') {
my $method = $action->{ method } || $localname;
no strict qw(refs);
# call method with
# - default value ($action->{ value } if defined,
# dereferencing lists
# - the values of the elements Attributes hash
# TODO: add namespaces declared to attributes.
# Expat consumes them, so we have to re-add them here.
$current->$method( defined $action->{ value }
? ref $action->{ value }
? @{ $action->{ value } }
: ($action->{ value })
: _fixup_attrs($parser, %attrs)
);
}
},
Char => sub { $characters .= $_[1] },
End => sub {
my ($parser, $localname) = @_;
my $action = SOAP::WSDL::TypeLookup->lookup(
$parser->namespace( $localname ),
$localname
) || {};
return if not ($action->{ type });
if ( $action->{ type } eq 'CLASS' ) {
$current = pop @{ $list };
}
elsif ($action->{ type } eq 'CONTENT' ) {
my $method = $action->{ method };
# normalize whitespace
$characters =~s{ ^ \s+ (.+) \s+ $ }{$1}xms;
$characters =~s{ \s+ }{ }xmsg;
no strict qw(refs);
$current->$method( $characters );
}
}
);
return $parser;
}
# make attrs SAX style
sub _fixup_attrs {
my ($parser, %attrs_of) = @_;
my @attrs_from = map { $_ =
{
Name => $_,
Value => $attrs_of{ $_ },
LocalName => $_
}
} keys %attrs_of;
# add xmlns: attrs. expat eats them.
push @attrs_from, map {
# ignore xmlns=FOO namespaces - must be XML schema
# Other nodes should be ignored somewhere else
($_ eq '#default')
? ()
:
{
Name => "xmlns:$_",
Value => $parser->expand_ns_prefix( $_ ),
LocalName => $_
}
} $parser->new_ns_prefixes();
return @attrs_from;
}
sub parse {
$_[0]->_initialize( XML::Parser::Expat->new(
Namespaces => 1
) )->parse( $_[1] );
$_[0]->{ parser }->release();
return $_[0]->{ data };
}
sub parsefile {
$_[0]->_initialize( XML::Parser::Expat->new(
Namespaces => 1
) )->parsefile( $_[1] );
$_[0]->{ parser }->release();
return $_[0]->{ data };
}
# aliases to make it more SAX-like
sub parse_file;
*parse_file = \&parsefile;
sub parse_string;
*parse_string = \&parse;
sub get_data {
return $_[0]->{ data };
}
1;
+128
View File
@@ -0,0 +1,128 @@
package SOAP::WSDL::Factory::Serializer;
use strict;
use warnings;
my %SERIALIZER = (
'1.1' => 'SOAP::WSDL::Serializer::SOAP11',
);
# class method
sub register {
my ($class, $ref_type, $package) = @_;
$SERIALIZER{ $ref_type } = $package;
}
sub get_serializer {
my ($self, $args_of_ref) = @_;
eval "require $SERIALIZER{ $args_of_ref->{ soap_version } }" or die $@;
return $SERIALIZER{ $args_of_ref->{ soap_version } }->new();
}
1;
=pod
=head1 NAME
SOAP::WSDL::Factory::Serializer - factory for retrieving serializer objects
=head1 SYNOPSIS
# from SOAP::WSDL::Client:
$serializer = SOAP::WSDL::Factory::Serializer->get_serializer({
soap_version => $soap_version,
});
# in serializer class:
package MyWickedSerializer;
use SOAP::WSDL::Factory::Serializer;
# u don't know the SOAP 1.2 recommendation? poor boy...
SOAP::WSDL::Factory::Serializer->register( '1.2' , __PACKAGE__ );
=head1 DESCRIPTION
SOAP::WSDL::Factory::Serializer serves as factory for retrieving
serializer objects for SOAP::WSDL.
The actual work is done by specific serializer classes.
SOAP::WSDL::Serializer tries to load one of the following classes:
a) the class registered for the scheme via register()
=head1 METHODS
=head2 register
SOAP::WSDL::Serializer->register('1.1', 'MyWickedSerializer');
Globally registers a class for use as serializer class.
=head2 get_serializer
Returns an object of the serializer class for this endpoint.
=head1 WRITING YOUR OWN SERIALIZER CLASS
Serializer classes may register with SOAP::WSDL::Factory::Serializer.
Serializer objects may also be passed directly to SOAP::WSDL::Client
by using the set_serializer method. Note that serializers objects set
via SOAP::WSDL::Client's set_serializer method are discarded when the
SOAP version is changed via set_soap_version.
Registering a serializer class with SOAP::WSDL::Factory::Serializer
is done by executing the following code where $version is the
SOAP version the class should be used for, and $class is the class
name.
SOAP::WSDL::Factory::Serializer->register( $version, $class);
To auto-register your transport class on loading, execute register()
in your tranport class (see L<SYNOPSIS|SYNOPSIS> above).
Serializer modules must be named equal to the serializer
class they contain. There can only be one serializer class per
serializer module.
Serializer class must implement the following methods:
=over
=item * new
Constructor.
=item * serialize
Serializes data to XML. The following named parameters are passed to
the serialize method in a anonymous hash ref:
{
method => $operation_name,
header => $header_data,
body => $body_data,
}
=back
=head1 LICENSE
Copyright 2004-2007 Martin Kutter.
This file is part of SOAP-WSDL. You may distribute/modify it under
the same terms as perl itself
=head1 AUTHOR
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 176 $
$LastChangedBy: kutterma $
$Id: Serializer.pm 176 2007-08-31 15:28:29Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Factory/Serializer.pm $
=cut
+230
View File
@@ -0,0 +1,230 @@
package SOAP::WSDL::Factory::Transport;
use strict;
use warnings;
# class data
my %registered_transport_of = ();
# Local constants
# Could be made readonly, but that's just for the paranoid...
my %SOAP_LITE_TRANSPORT_OF = (
ftp => 'SOAP::Transport::FTP',
http => 'SOAP::Transport::HTTP',
https => 'SOAP::Transport::HTTPS',
mailto => 'SOAP::Transport::MAILTO',
'local' => 'SOAP::Transport::LOCAL',
jabber => 'SOAP::Transport::JABBER',
mq => 'SOAP::Transport::MQ',
);
my %SOAP_WSDL_TRANSPORT_OF = (
http => 'SOAP::WSDL::Transport::HTTP',
https => 'SOAP::WSDL::Transport::HTTP',
);
# class methods only
sub register {
my ($class, $scheme, $package) = @_;
$registered_transport_of{ $scheme } = $package;
}
sub get_transport {
my ($class, $scheme, %attrs) = @_;
$scheme =~s{ \A ([^\:]+) \: .+ }{$1}smx;
if (exists $registered_transport_of{ $scheme }) {
eval "require $registered_transport_of{ $scheme }" or die $@;
# try "foo::Client" class first - SOAP::Tranport always requires
# a package withoug the ::Client appended, and then
# instantiates a ::Client object...
# ... pretty weird ...
# ... must be from some time when the max number of files was a
# sparse resource ...
# ... but we've decided to mimic SOAP::Lite...
my $protocol_class = $SOAP_LITE_TRANSPORT_OF{ $scheme } . '::Client';
my $transport;
eval {
$transport = $protocol_class->new( %attrs );
};
return $transport if not $@;
return $registered_transport_of{ $scheme }->new( %attrs );
}
# try SOAP::Lite's Transport module - just skip if not require'able
SOAP_Lite: {
if (exists $SOAP_LITE_TRANSPORT_OF{ $scheme }) {
eval "require $SOAP_LITE_TRANSPORT_OF{ $scheme }"
or last SOAP_Lite;
my $protocol_class = $SOAP_LITE_TRANSPORT_OF{ $scheme } . '::Client';
return $protocol_class->new( %attrs );
}
}
if (exists $SOAP_WSDL_TRANSPORT_OF{ $scheme }) {
eval "require $SOAP_WSDL_TRANSPORT_OF{ $scheme }" or die $@;
return $SOAP_WSDL_TRANSPORT_OF{ $scheme }->new( %attrs );
}
die "no transport class found for scheme <$scheme>";
}
1;
=pod
=head1 NAME
SOAP::WSDL::Factory::Transport - factory for retrieving transport objects
=head1 SYNOPSIS
# from SOAP::WSDL::Client:
$transport = SOAP::WSDL::Factory::Transport->get_transport( $url, @opt );
# in transport class:
package MyWickedTransport;
use SOAP::WSDL::Factory::Transport;
# u don't know the httpr protocol? poor boy...
SOAP::WSDL::Factory::Transport->register( 'httpr' , __PACKAGE__ );
SOAP::WSDL::Factory::Transport->register( 'https' , __PACKAGE__ );
=head1 DESCRIPTION
SOAP::WSDL::Transport serves as factory for retrieving
transport objects for SOAP::WSDL.
The actual work is done by specific transport classes.
SOAP::WSDL::Transport tries to load one of the following classes:
a) the class registered for the scheme via register()
b) the SOAP::Lite class matching the scheme
c) the SOAP::WSDL class matching the scheme
=head1 METHODS
=head2 register
SOAP::WSDL::Transport->register('https', 'MyWickedTransport');
Globally registers a class for use as transport class.
=head2 proxy
$trans->proxy('http://soap-wsdl.sourceforge.net');
Sets the proxy (endpoint).
Returns the transport for this protocol.
=head2 set_transport
Sets the current transport object.
=head2 get_transport
Gets the current transport object.
=head1 WRITING YOUR OWN TRANSPORT CLASS
Transport classes must be registered with SOAP::WSDL::Factory::Transport.
This is done by executing the following code where $scheme is the
URL scheme the class should be used for, and $module is the class'
module name.
SOAP::WSDL::Factory::Transport->register( $scheme, $module);
To auto-register your transport class on loading, execute register()
in your tranport class (see L<SYNOPSIS|SYNOPSIS> above).
Multiple protocols ore multiple classes are registered by multiple calls to
register().
You may only use transport classes whose name is either
the module name or the module name with '::Client' appended.
Transport classes must implement the interface required for
SOAP::Lite transport classes.
See L<SOAP::Lite::Transport> for details,
L<SOAP::WSDL::Transport::HTTP|SOAP::WSDL::Transport::HTTP>
for an example.
Transport modules must implement the following methods:
=over
=item * new
=item * send_receive
Dispatches a request and returns the content of the response.
=item * code
Returns the status code of the last send_receive call (if any).
=item * message
Returns the status message of the last send_receive call (if any).
=item * status
Returns the status of the last send_receive call (if any).
=item * is_success
Returns true after a send_receive was successful, false if it was not.
=back
SOAP::Lite requires transport modules to pack client and server
classes in one file, and to follow this naming scheme:
Module name:
"SOAP::Transport::" . uc($scheme)
Client class (additional package in module):
"SOAP::Transport::" . uc($scheme) . "::Client"
Server class (additional package in module):
"SOAP::Transport::" . uc($scheme) . "::Client"
SOAP::WSDL does not require you to follow these restrictions.
There is only one restriction in SOAP::WSDL:
You may only use transport classes whose name is either
the module name or the module name with '::Client' appended.
SOAP::WSDL will try to instantiate an object of your
transport class with '::Client' appended to allow using transport
classes written for SOAP::Lite.
This may lead to errors when a different module with the name
of your transport module suffixed with ::Client is also loaded.
=head1 LICENSE
Copyright 2004-2007 Martin Kutter.
This file is part of SOAP-WSDL. You may distribute/modify it under
the same terms as perl itself
=head1 AUTHOR
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 176 $
$LastChangedBy: kutterma $
$Id: Transport.pm 176 2007-08-31 15:28:29Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Factory/Transport.pm $
=cut
+48 -8
View File
@@ -11,9 +11,12 @@ some internet protocol, typically via HTTP(S).
=head2 SOAP
SOAP (the Simple Object Access Protocol) is a specification for
defining RPC interfaces, including (but not neccessarily limited to)
web services.
SOAP is an acronym for Simple Object Access Protocol.
SOAP is a W3C recommendation. The latest version of the SOAP
specification may be found at L<http://www.w3.org/TR/soap/>.
SOAP defines a protocoll for message exchange between applications.
The most popular usage is to use SOAP for remote procedure calls (RPC).
While one of the constituting aspects of a web service is its
reachability via some internet protocol, you might as well define
@@ -26,15 +29,52 @@ carry your pet.
=head2 WSDL
WSDL (Web Service Definition Language) is a XML-based markup language
for defining web service interfaces.
WSDL is an acronym for Web Services Description Language.
WSDL is a W3C recommendation. The latest version of the WSDL specification
may be found at L<http://www.w3.org/TR/wsdl20/>.
WSDL defines a XML-based language for describing web service interfaces,
including SOAP interfaces.
=head2 WS-I
WS-I (Web Service Interoperability) is a industry consortium dedicated
to finding interoperability rules for web services.
WS-I (Web Services Interoperability Organization) is an open industry
organisation chartered to promote Web service interoperability across
platforms, operating systems, and programming languages.
SOAP::WSDL aims to be a WS-I compliant SOAP client.
WS-I publishes profiles, which provide implementation guidelines for
how related Web services specifications should be used together for
best interoperability. To date, WS-I has finalized the Basic Profile,
Attachments Profile and Simple SOAP Binding Profile.
SOAP::WSDL aims at complying to the Basic Profile (but does not
implement full support yet).
=head2 SOAP message styles
=head3 rpc
Meant for transporting a RPC message. All contents of the SOAP body are
put into a top-level node named equal to the SOAP operation.
WS-I Basic Profile allows the use of rpc message style.
SOAP::WSDL does not support rpc message style yet.
SOAP::Lite supports rpc message style only.
=head3 document
Meant for transporting arbitrary content. No additional nodes are inserted
between the SOAP body and the actual content.
WS-I Basic Profile allows the use of document message style.
=head2 SOAP encoding styles
=head3 encoded
=head3 literal
=head1 LICENSE
File diff suppressed because it is too large Load Diff
+59 -16
View File
@@ -6,8 +6,8 @@ SOAP::WSDL::Parser - How SOAP::WSDL parses XML messages
=head1 Which XML message does SOAP::WSDL parse ?
Naturally, there are two kinds of XMLdocuments (or messages) SOAP::WSDL
has to parse:
Naturally, there are two kinds of XML documents (or messages)
SOAP::WSDL has to parse:
=over
@@ -19,13 +19,55 @@ has to parse:
=head1 Parser implementations
There are different parser implementations available for SOAP messages -
currently there's only one for WSDL definitions.
There are different parser implementations available for SOAP messages
and WSDL definitions.
Historically, SOAP::WSDL used SAX for parsing XML. The SAX handlers
were implemented as L<XML::LibXML|XML::LibXML> handlers, which
also worked with L<XML::SAX::ParserFactory|XML::SAX::ParserFactory>.
The use of SAX and L<XML::LibXML|XML::LibXML> in SOAP::WSDL is
deprecated for the following reasons:
=over
=item * Speed
L<XML::Parser::Expat|XML::Parser::Expat> is faster than
L<XML::LibXML|XML::LibXML> - at least when optimized for speed.
=item * Availability
L<XML::Parser|XML::Parser> is more popular than
L<XML::LibXML|XML::LibXML>.
=item * Stability
XML::LibXML is based on the libxml2 library. Several versions of
libxml2 are known to have specific bugs. As a workaround, there are
often several versions of libxml2 installed on one system. This may
lead to problems on operating systems which cannot load more than
one version of a shared library simultaneously.
=item * SOAP::Lite uses XML::Parser
L<SOAP::Lite|SOAP::Lite> uses L<XML::Parser|XML::Parser> if available.
SOAP::WSDL should not require users to install both L<XML::Parser|XML::Parser>
and L<XML::LibXML|XML::LibXML>.
=back
=head2 WSDL definitions parser
=over
=item * SOAP::WSDL::Expat::WSDLParser
A parser for WSDL definitions based on L<XML::Parser::Expat|XML::Parser::Expat>.
my $parser = SOAP::WSDL::Expat::WSDLParser->new();
my $wsdl = $parser->parse_file( $filename );
=item * SOAP::WSDL::SAX::WSDLHandler
This is a SAX handler for parsing WSDL files into object trees SOAP::WSDL
@@ -132,6 +174,19 @@ L<SOAP::WSDL::XSD::Typelib::ComplexType> and L<SOAP::WSDL::XSD::Typelib::SimpleT
=over
=item * SOAP::WSDL::Expat::MessageParser
A L<XML::Parser::Expat|XML::Parser::Expat> based parser. This is the fastest
parser for most SOAP messages and the default for SOAP::WSDL::Client.
=item * SOAP::WSDL::Expat::MessageStreamParser
A XML::Parser::ExpatNB based parser. Useful for parsing huge HTTP responses,
as you don't need to keep everything in memory.
See L<SOAP::WSDL::Expat::MessageStreamParser|SOAP::WSDL::Expat::MessageStreamParser>
for details.
=item * SOAP::WSDL::SAX::MessageHandler
This is a SAX handler for parsing WSDL files into object trees SOAP::WSDL
@@ -144,18 +199,6 @@ Can be used for parsing both streams (chunks) and documents.
See L<SOAP::WSDL::SAX::MessageHandler> for details.
=item * SOAP::WSDL::Expat::MessageParser
A L<XML::Parser::Expat|XML::Parser::Expat> based parser. This is the fastest
parser for most SOAP messages and the default for SOAP::WSDL::Client.
=item * SOAP::WSDL::Expat::MessageStreamParser
A XML::Parser::ExpatNB based parser. Useful for parsing huge HTTP responses,
as you don't need to keep everything in memory.
See L<SOAP::WSDL::Expat::MessageStreamParser|SOAP::WSDL::Expat::MessageStreamParser> for details.
=back
=head3 Performance
+71
View File
@@ -0,0 +1,71 @@
Release notes for SOAP::WSDL 2.00_11
-------
I'm happy to present a new pre-release version of SOAP::WSDL.
The following features were added (the numbers in brackets are the tracker IDs
from https://sourceforge.net/tracker/?group_id=111978&atid=660924):
* [1767963] Transport plugins via SOAP::WSDL::Factory::Transport.
SOAP::WSDL uses SOAP::Lite's tranport modules as default, with a
lightweight HTTP(S) transport plugin as fallback.
Custom transport modules can be registered via
SOAP::WSDL::Factory::Transport.
* [ 1772730 ] Serializer plugins via SOAP::WSDL::Factory::Serializer
The default serializer for SOAP1.1 is SOAP::WSDL::Serializer::SOAP11.
Custom serializers classes can be registered via
SOAP::WSDL::Factory::Serializer or set via SOAP::Lite's set_serializer
method.
The following bugs have been fixed (the numbers in brackets are the tracker IDs
from https://sourceforge.net/tracker/?group_id=111978&atid=660921):
* [ 1764854 ] Port WSDL parser to expat and remove XML::LibXML dependency
SOAP::WSDL now requires only XML::Parser to be installed.
XML::LibXML is not required any more, though XML::LibXML based modules still
exist.
The following uncategorized improvements have been made
* The number of dependencies has been reduced. SOAP::WSDL no longer requires the
following modules to be installed:
- XML::SAX::Base
- XML::SAX::ParserFactory
- Pod::Simple::Text
* The missing prerequisite Template has been added.
* Documentation has been improved.
The following changes were made in former pre-relase versions:
2.00_10
----
* Changed Makefile.PL to use Module::Build (passthrough mode)
* fixed element ref="" handling
2.00_09
----
* SOAP::WSDL::XSD::Typelib::Builtin::boolean objects now return their numerical
value in bool context, not "true" or "false" (always true...)
* date/time test are now timezone-sensitive
* examples added
2.00_08
---
* SOAP message parser may skip unwanted parts of the message - see
SOAP::WSDL::Expat::MessageParser for details.
* HTTP Content-Type is configurable now
* SOAP::WSDL::XSD::Typelib::ComplexType based objects now accept a
list ref of hash refs as parameter to set_value.
* SOAP::WSDL::XSD::Typelib::Builtin::dateTime and ::date now converts date
strings into XML date strings
* SOAP::WSDL::Definitions::create now
- converts '.' in service names to '::' (.NET class separator to perl class
separator)
- outputs Typemaps and Interface classes in UTF8 to allow proper inclusion
of UTF8 documentation from WSDL
* WSDLHandler now handles <wsdl:documentation> tags
* SOAP::WSDL::Definitions now includes some usable doc in generated interface classes
* fixed explain in SimpleType, ComplexType and Element (someway)
+4 -4
View File
@@ -273,9 +273,9 @@ This module may be used under the same terms as perl itself.
$ID: $
$LastChangedDate: $
$LastChangedRevision: $
$LastChangedBy: $
$LastChangedDate: 2007-08-31 17:28:29 +0200 (Fr, 31 Aug 2007) $
$LastChangedRevision: 176 $
$LastChangedBy: kutterma $
$HeadURL: $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/SAX/MessageHandler.pm $
@@ -1,13 +1,17 @@
#!/usr/bin/perl -w
package SOAP::WSDL::Envelope;
use strict;
use base qw/SOAP::WSDL::Base/;
package SOAP::WSDL::Serializer::SOAP11;
use strict;
use warnings;
use Class::Std::Storable;
# use base qw/SOAP::WSDL::Base/;
my $SOAP_NS = 'http://schemas.xmlsoap.org/soap/envelope/';
my $XML_INSTANCE_NS = 'http://www.w3.org/2001/XMLSchema-instance';
sub serialize {
my ($self, $name, $data, $opt) = @_;
my ($self, $args_of_ref) = @_;
my $opt = $args_of_ref->{ options };
if (not $opt->{ namespace }->{ $SOAP_NS })
{
@@ -32,8 +36,9 @@ sub serialize {
# TODO insert encoding
$xml.='>';
$xml .= $self->serialize_header($name, $data, $opt);
$xml .= $self->serialize_body($name, $data, $opt);
$xml .= $self->serialize_header($args_of_ref->{ method }, $args_of_ref->{ header }, $opt);
$xml .= "\n" if ($opt->{ readable });
$xml .= $self->serialize_body($args_of_ref->{ method }, $args_of_ref->{ body }, $opt);
$xml .= "\n" if ($opt->{ readable });
$xml .= '</' . $soap_prefix .':Envelope>';
$xml .= "\n" if ($opt->{ readable });
+107
View File
@@ -0,0 +1,107 @@
package SOAP::WSDL::Transport::HTTP;
use strict;
use base qw(LWP::UserAgent);
# create methods normally inherited from SOAP::Client
SUBFACTORY: {
no strict qw(refs);
foreach my $method ( qw(code message status is_success) ) {
*{ $method } = sub {
my $self = shift;
return $self->{ $method } if not @_;
return $self->{ $method } = shift;
};
}
}
sub send_receive {
my ($self, %parameters) = @_;
my ($envelope, $soap_action, $endpoint, $encoding, $content_type) =
@parameters{qw(envelope action endpoint encoding content_type)};
$encoding = defined($encoding)
? 'utf8'
: lc($encoding);
# TODO check whether we need this with current LWP::UserAgent - we're
# not here to fix LWP::UserAgent bugs...
#
# what's this all about?
# unfortunately combination of LWP and Perl 5.6.1 and later has bug
# in sending multibyte characters. LWP uses length() to calculate
# content-length header and starting 5.6.1 length() calculates chars
# instead of bytes. 'use bytes' in THIS file doesn't work, because
# it's lexically scoped. Unfortunately, content-length we calculate
# here doesn't work either, because LWP overwrites it with
# content-length it calculates (which is wrong) AND uses length()
# during syswrite/sysread, so we are in a bad shape anyway.
#
# what to do? we calculate proper content-length (using
# bytelength() function from SOAP::Utils) and then drop utf8 mark
# from string (doing pack with 'C0A*' modifier) if length and
# bytelength are not the same
# use bytes is lexically scoped
my $bytelength = do { use bytes; length $envelope };
$envelope = pack('C0A*', $envelope)
if length($envelope) != $bytelength;
# END TODO
my $request = HTTP::Request->new( 'POST',
$endpoint,
[ 'Content-Type', "$content_type; charset=$encoding",
'Content-Length', $bytelength,
'SOAPAction', $soap_action,
],
$envelope );
use Data::Dumper;
warn Dumper $request;
my $response = $self->request( $request );
warn Dumper $response;
$self->code( $response->code);
$self->message( $response->message);
$self->is_success($response->is_success);
$self->status($response->status_line);
return $response->content();
}
1;
=pod
=head1 NAME
SOAP::WSDL::Transport::HTTP - Fallback http(s) transport class
=head1 DESCRIPTION
Provides a thin transport class used by SOAP::WSDL::Transport when
SOAP::Lite is not available.
=head1 LICENSE
Copyright 2004-2007 Martin Kutter.
This file is part of SOAP-WSDL. You may distribute/modify it under
the same terms as perl itself
=head1 AUTHOR
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 176 $
$LastChangedBy: kutterma $
$Id: HTTP.pm 176 2007-08-31 15:28:29Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Transport/HTTP.pm $
=cut
+1 -1
View File
@@ -269,7 +269,7 @@ methods:
[% element.get_name -%]
[% END %]
=head1 Object structure
[% head1 %] Object structure
[% FOREACH element=self.get_element;
IF (element.get_type);
+2 -1
View File
@@ -1,6 +1,7 @@
package SOAP::WSDL::XSD::Typelib::Builtin::boolean;
use strict;
use warnings;
use Class::Std::Storable;
my %pattern_of :ATTR(:name<pattern> :default<()>);
my %whiteSpace_of :ATTR(:name<whiteSpace> :default<()>);
@@ -9,7 +10,7 @@ my %value_of :ATTR(:get<value> :init_attr<value> :default<()>);
# Speed up. Class::Std::new is slow - and we don't need it's functionality...
BEGIN {
use Class::Std::Storable;
# use Class::Std::Storable;
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType);
no warnings qw(redefine);
+3 -1
View File
@@ -53,7 +53,9 @@ sub set_value {
# We leave out the optional nanoseconds part, as it would always be empty.
else {
# strptime sets empty values to undef - and strftime doesn't like that...
my @time_from = map { ! defined $_ ? 0 : $_ } strptime($_[1]);
my @time_from = map { ! defined $_ ? 0 : $_ } strptime($_[1]);
# use Data::Dumper;
# die Dumper \@time_from;
my $time_str = strftime( '%Y-%m-%d%z', @time_from );
substr $time_str, -2, 0, ':';
$_[0]->SUPER::set_value($time_str);
+26
View File
@@ -14,6 +14,32 @@ my %ELEMENTS_FROM;
my %ATTRIBUTES_OF;
my %CLASSES_OF;
# STORABLE_ methods for supporting Class::Std::Storable.
# We could also handle them via AUTOMETHOD,
# but AUTOMETHOD should always croak...
sub STORABLE_freeze_pre {
}
sub STORABLE_freeze_post {
}
sub STORABLE_thaw_pre {
}
sub STORABLE_thaw_post {
}
# for error reporting. Eases working with data objects...
sub AUTOMETHOD {
my ($self, $ident, @args_from) = @_;
my $class = ref $self || $self;
confess "Can't locate object method \"$_\" via package \"$class\". \n"
. "Valid methods are: "
. join(', ', map { ("get_$_" , "set_$_") } keys %{ $ATTRIBUTES_OF{ $class } })
. "\n"
}
# we store per-class elements.
# call as __PACKAGE__->_factory
sub _factory {