Compare commits

...

4 Commits

Author SHA1 Message Date
Martin Kutter
fd0854e34a import SOAP-WSDL 2.00_12 from CPAN
git-cpan-module:   SOAP-WSDL
git-cpan-version:  2.00_12
git-cpan-authorid: MKUTTER
git-cpan-file:     authors/id/M/MK/MKUTTER/SOAP-WSDL-2.00_12.tar.gz
2009-12-12 19:47:49 -08:00
Martin Kutter
c2da74b5ae 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
2009-12-12 19:47:49 -08:00
Martin Kutter
7ba1959888 import SOAP-WSDL 2.00_10 from CPAN
git-cpan-module:   SOAP-WSDL
git-cpan-version:  2.00_10
git-cpan-authorid: MKUTTER
git-cpan-file:     authors/id/M/MK/MKUTTER/SOAP-WSDL-2.00_10.tar.gz
2009-12-12 19:47:48 -08:00
Martin Kutter
a554e87f49 import SOAP-WSDL 2.00_09 from CPAN
git-cpan-module:   SOAP-WSDL
git-cpan-version:  2.00_09
git-cpan-authorid: MKUTTER
git-cpan-file:     authors/id/M/MK/MKUTTER/SOAP-WSDL-2.00_09.tar.gz
2009-12-12 19:47:47 -08:00
83 changed files with 6523 additions and 964 deletions

View File

@@ -1,42 +1,40 @@
use Module::Build;
Module::Build->new(
dist_abstract => 'SOAP with WSDL support',
dist_name => 'SOAP-WSDL',
dist_version => '2.00_08',
module_name => 'SOAP::WSDL',
license => 'artistic',
requires => {
'Class::Std' => q/v0.0.8/,
'Class::Std::Storable' => 0,
'Date::Parse' => 0,
'Date::Format' => 0,
'LWP::UserAgent' => 0,
'List::Util' => 0,
'File::Basename' => 0,
'File::Path' => 0,
'XML::LibXML' => 0,
'XML::SAX::Base' => 0,
'XML::SAX::ParserFactory' => 0,
'XML::Parser::Expat' => 0,
create_makefile_pl => 'passthrough',
dist_abstract => 'SOAP with WSDL support',
dist_name => 'SOAP-WSDL',
dist_version => '2.00_12',
module_name => 'SOAP::WSDL',
license => 'artistic',
requires => {
'Class::Std' => q/v0.0.8/,
'Class::Std::Storable' => 0,
'Date::Parse' => 0,
'Date::Format' => 0,
'LWP::UserAgent' => 0,
'List::Util' => 0,
'File::Basename' => 0,
'File::Path' => 0,
'XML::Parser::Expat' => 0,
'Template' => 0,
'Getopt::Long' => 0,
},
buildrequires => {
'Date::Parse' => 0,
'Date::Format' => 0,
'Benchmark' => 0,
'Cwd' => 0,
'Test::More' => 0,
'Class::Std' => 0.0.8,
'Class::Std::Storable' => 0,
'List::Util' => 0,
'LWP::UserAgent' => 0,
'File::Basename' => 0,
'File::Path' => 0,
'XML::Simple' => 0,
'XML::LibXML' => 0,
'XML::Parser::Expat' => 0,
'XML::SAX::Base' => 0,
'XML::SAX::ParserFactory' => 0,
'Pod::Simple::Text' => 0,
buildrequires => {
'Date::Parse' => 0,
'Date::Format' => 0,
'Test::More' => 0,
'Class::Std' => q/v0.0.8/,
'Class::Std::Storable' => 0,
'List::Util' => 0,
'LWP::UserAgent' => 0,
'File::Basename' => 0,
'File::Path' => 0,
'XML::Parser::Expat' => 0,
'Template' => 0,
'Getopt::Long' => 0,
'Cwd' => 0,
'File::Find' => 0,
},
recursive_test_files => 1,
)->create_build_script;

123
CHANGES
View File

@@ -1 +1,122 @@
See perldoc SOAP::WSDL
Release notes for SOAP::WSDL 2.00_12
-------
I'm very happy to present a new pre-release version of SOAP::WSDL.
SOAP::WSDL is a toolkit for creating SOAP interfaces in perl.
Features:
* WSDL based SOAP client
o SOAP1.1 support
o Supports document/literal message style/encoding
* Code generator for generating WSDL-based interface classes
o Generated code includes usage documentation for the web service interface
* Easy-to use API. SOAP::WSDL is much easier to use than SOAP::Lite.
o Automatically encodes perl data structures as message data
o Automatically sets HTTP headers right
* SOAP::Lite like look and feel.
o Where possible, SOAP::WSDL mimics SOAP::Lite's API to allow easy migrations
* XML schema based class library for creating data objects
* High-performance XML parser
* Plugin support. SOAP::WSDL can be extended through plugins in various aspects.
The following plugins are supported:
o Transport plugins via SOAP::WSDL::Factory::Transport
o Serializer plugins via SOAP::WSDL::Factory::Serializer
The following changes have been made:
2.00_12
----
The following bugs have been fixed (the numbers in square brackets are the
tracker IDs from https://sourceforge.net/tracker/?group_id=111978&atid=660921):
* [1787146] SOAP::WSDL still uses XML::LibXML
The superficious usage of XML::LibXML has been removed. XML::LibXML with
sax filter has been replaced by SOAP::WSDL::Expat::WSDLParser.
* [1787054] Test suite requires XML::LibXML in 2.00_11
The test suite no longer requires XML::LibXML to pass.
2.00_11
----
The following features were added (the numbers in square 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::WSDL's set_serializer
method.
The following bugs have been fixed (the numbers in square 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
- XML::LibXML
* The missing prerequisite Template has been added.
* Documentation has been improved.
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::WSDL::XSD::Typelib::ComplexType objects now check the class of their
child objects.
This provides early feedback to developers.
* SOAP message parser can skip unwanted parts of the message to improve parsing
speed - see SOAP::WSDL::Expat::MessageParser for details.
* HTTP Content-Type is configurable
* SOAP::WSDL::XSD::Typelib::ComplexType based objects accept any combination of
hash refs, list refs and objects as parameter to set_value() and new().
* SOAP::WSDL::XSD::Typelib::Builtin::dateTime and ::date convert 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
* SOAP::WSDL::Definitions::create() includes doc in generated interface classes
* WSDLHandler now handles <wsdl:documentation> tags
* fixed explain in SimpleType, ComplexType and Element
2.00_07 and below
---
* Implemented a Code generator for creating SOAP interfaces based on WSDL definitions
* Implemented a high-speed stream based SOAP message parser
SOAP message parser returns a objects based on XML schema based class library
* Implemented a XML schema based class library
* Implemented a stream based WSDL parser.
Parses WSDL into objects. Objects can serialize data, and explain how to use the
service(s) they make up (output documentation).

View File

@@ -1,3 +1,4 @@
benchmark/01_expat.t
bin/wsdl2perl.pl
Build.PL
CHANGES
@@ -32,11 +33,16 @@ lib/SOAP/WSDL/Binding.pm
lib/SOAP/WSDL/Client.pm
lib/SOAP/WSDL/Client/Base.pm
lib/SOAP/WSDL/Definitions.pm
lib/SOAP/WSDL/Envelope.pm
lib/SOAP/WSDL/Expat/MessageParser.pm
lib/SOAP/WSDL/Expat/MessageStreamParser.pm
lib/SOAP/WSDL/Expat/MessageSubParser.pm
lib/SOAP/WSDL/Expat/SubParser.pm
lib/SOAP/WSDL/Expat/WSDLParser.pm
lib/SOAP/WSDL/Factory/Serializer.pm
lib/SOAP/WSDL/Factory/Transport.pm
lib/SOAP/WSDL/Manual.pod
lib/SOAP/WSDL/Manual/Glossary.pod
lib/SOAP/WSDL/Manual/WS_I.pod
lib/SOAP/WSDL/Message.pm
lib/SOAP/WSDL/Operation.pm
lib/SOAP/WSDL/OpMessage.pm
@@ -46,9 +52,11 @@ lib/SOAP/WSDL/Port.pm
lib/SOAP/WSDL/PortType.pm
lib/SOAP/WSDL/SAX/MessageHandler.pm
lib/SOAP/WSDL/SAX/WSDLHandler.pm
lib/SOAP/WSDL/Serializer/SOAP11.pm
lib/SOAP/WSDL/Service.pm
lib/SOAP/WSDL/SOAP/Typelib/Fault11.pm
lib/SOAP/WSDL/SoapOperation.pm
lib/SOAP/WSDL/Transport/HTTP.pm
lib/SOAP/WSDL/TypeLookup.pm
lib/SOAP/WSDL/Types.pm
lib/SOAP/WSDL/XSD/Builtin.pm
@@ -108,13 +116,18 @@ lib/SOAP/WSDL/XSD/Typelib/ComplexType.pm
lib/SOAP/WSDL/XSD/Typelib/Element.pm
lib/SOAP/WSDL/XSD/Typelib/SimpleType.pm
LICENSE
Makefile.PL
MANIFEST This list of files
META.yml
README
t/001_use.t
t/002_parse_wsdl.t
t/002_sax.t
t/003_sax_serializer.t
t/003_wsdl_based_serializer.t
t/004_parse_wsdl.t
t/004_sax_wsdl.t
t/005_parse_contributed.t
t/005_sax_contributed_wsdl.t
t/006_client.t
t/007_envelope.t
@@ -126,9 +139,13 @@ t/013_complexType.t
t/014_sax_typelib.t
t/015_to_typemap.t
t/016_client_object.t
t/017_generator.t
t/018_generator.t
t/017_generator_expat.t
t/017_generator_libxml.t
t/018_generator_expat.t
t/018_generator_libxml.t
t/020_storable.t
t/021_generator_element_ref_expat.t
t/021_generator_element_ref_libxml.t
t/098_pod.t
t/acceptance/results/03_complexType-all.xml
t/acceptance/results/03_complexType-sequence.xml
@@ -142,6 +159,7 @@ t/acceptance/wsdl/006_sax_client.wsdl
t/acceptance/wsdl/008_complexType.wsdl
t/acceptance/wsdl/02_port.wsdl
t/acceptance/wsdl/03_complexType-all.wsdl
t/acceptance/wsdl/03_complexType-element-ref.wsdl
t/acceptance/wsdl/03_complexType-sequence.wsdl
t/acceptance/wsdl/04_element-simpleType.wsdl
t/acceptance/wsdl/04_element.wsdl
@@ -156,6 +174,8 @@ t/acceptance/wsdl/contributed/OITest.wsdl
t/acceptance/wsdl/contributed/tools.wsdl
t/acceptance/wsdl/email_account.wsdl
t/Expat/01_expat.t
t/Expat/02_sub_parser.t
t/Expat/03_wsdl.t
t/lib/MyComplexType.pm
t/lib/MyElement.pm
t/lib/MySimpleType.pm
@@ -168,6 +188,7 @@ t/SOAP/WSDL/02_port.t
t/SOAP/WSDL/03_complexType-all.t
t/SOAP/WSDL/03_complexType-choice.t
t/SOAP/WSDL/03_complexType-complexContent.t
t/SOAP/WSDL/03_complexType-element-ref.t
t/SOAP/WSDL/03_complexType-group.t
t/SOAP/WSDL/03_complexType-sequence.t
t/SOAP/WSDL/03_complexType-simpleContent.t
@@ -177,11 +198,9 @@ t/SOAP/WSDL/04_element.t
t/SOAP/WSDL/05_simpleType-list.t
t/SOAP/WSDL/05_simpleType-restriction.t
t/SOAP/WSDL/05_simpleType-union.t
t/SOAP/WSDL/10_performance.t
t/SOAP/WSDL/11_helloworld.NET.t
t/SOAP/WSDL/12_binding.pl
t/SOAP/WSDL/XSD/Typelib/Builtin/001_string.t
t/SOAP/WSDL/XSD/Typelib/Builtin/002_dateTime.t
t/SOAP/WSDL/XSD/Typelib/Builtin/002_time.t
t/SOAP/WSDL/XSD/Typelib/Builtin/003_date.t
TODO

View File

@@ -1,6 +1,6 @@
---
name: SOAP-WSDL
version: 2.00_08
version: 2.00_12
author:
abstract: SOAP with WSDL support
license: artistic
@@ -11,12 +11,11 @@ requires:
Date::Parse: 0
File::Basename: 0
File::Path: 0
Getopt::Long: 0
LWP::UserAgent: 0
List::Util: 0
XML::LibXML: 0
Template: 0
XML::Parser::Expat: 0
XML::SAX::Base: 0
XML::SAX::ParserFactory: 0
generated_by: Module::Build version 0.2808
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.2.html
@@ -24,23 +23,28 @@ meta-spec:
provides:
SOAP::WSDL:
file: lib/SOAP/WSDL.pm
version: 2.00_08
version: 2.00_12
SOAP::WSDL::Base:
file: lib/SOAP/WSDL/Base.pm
SOAP::WSDL::Binding:
file: lib/SOAP/WSDL/Binding.pm
SOAP::WSDL::Client:
file: lib/SOAP/WSDL/Client.pm
version: 2.00_12
SOAP::WSDL::Client::Base:
file: lib/SOAP/WSDL/Client/Base.pm
SOAP::WSDL::Definitions:
file: lib/SOAP/WSDL/Definitions.pm
SOAP::WSDL::Envelope:
file: lib/SOAP/WSDL/Envelope.pm
SOAP::WSDL::Expat::MessageParser:
file: lib/SOAP/WSDL/Expat/MessageParser.pm
SOAP::WSDL::Expat::MessageStreamParser:
file: lib/SOAP/WSDL/Expat/MessageStreamParser.pm
SOAP::WSDL::Expat::MessageSubParser:
file: lib/SOAP/WSDL/Expat/MessageSubParser.pm
SOAP::WSDL::Factory::Serializer:
file: lib/SOAP/WSDL/Factory/Serializer.pm
SOAP::WSDL::Factory::Transport:
file: lib/SOAP/WSDL/Factory/Transport.pm
SOAP::WSDL::Message:
file: lib/SOAP/WSDL/Message.pm
SOAP::WSDL::OpMessage:
@@ -57,10 +61,14 @@ provides:
file: lib/SOAP/WSDL/SAX/MessageHandler.pm
SOAP::WSDL::SOAP::Typelib::Fault11:
file: lib/SOAP/WSDL/SOAP/Typelib/Fault11.pm
SOAP::WSDL::Serializer::SOAP11:
file: lib/SOAP/WSDL/Serializer/SOAP11.pm
SOAP::WSDL::Service:
file: lib/SOAP/WSDL/Service.pm
SOAP::WSDL::SoapOperation:
file: lib/SOAP/WSDL/SoapOperation.pm
SOAP::WSDL::Transport::HTTP:
file: lib/SOAP/WSDL/Transport/HTTP.pm
SOAP::WSDL::TypeLookup:
file: lib/SOAP/WSDL/TypeLookup.pm
SOAP::WSDL::Types:

31
Makefile.PL Normal file
View File

@@ -0,0 +1,31 @@
# Note: this file was auto-generated by Module::Build::Compat version 0.03
unless (eval "use Module::Build::Compat 0.02; 1" ) {
print "This module requires Module::Build to install itself.\n";
require ExtUtils::MakeMaker;
my $yn = ExtUtils::MakeMaker::prompt
(' Install Module::Build now from CPAN?', 'y');
unless ($yn =~ /^y/i) {
die " *** Cannot install without Module::Build. Exiting ...\n";
}
require Cwd;
require File::Spec;
require CPAN;
# Save this 'cause CPAN will chdir all over the place.
my $cwd = Cwd::cwd();
CPAN::Shell->install('Module::Build::Compat');
CPAN::Shell->expand("Module", "Module::Build::Compat")->uptodate
or die "Couldn't install Module::Build, giving up.\n";
chdir $cwd or die "Cannot chdir() back to $cwd: $!";
}
eval "use Module::Build::Compat 0.02; 1" or die $@;
Module::Build::Compat->run_build_pl(args => \@ARGV);
require Module::Build;
Module::Build::Compat->write_makefile(build_class => 'Module::Build');

26
README
View File

@@ -1,2 +1,26 @@
INTRO
-----
SOAP-WSDL provides a SOAP client with WSDL support.
This is a developer release - everything may (and most things will) change.
INSTALLING
----------
Use the following mantra:
perl Build.PL
perl Build
perl Build test
perl Build install
If you don't have Module::Build installed, you may also use
perl Makefile.PL
make
make test
make install
Note that Module::Build is the recommended installer - make will not run
all tests provided with SOAP-WSDL.

67
TODO
View File

@@ -1,36 +1,35 @@
- support embedded atomic types by including a second (and third and fourth)
package type_prefix::complex_type::element_name element package.
Allow unlimited depth (though this is rather wicked).
- fixup generated pod so it looks nice in SOAP::WSDL::Definitions.
- remove benchmarks from tests. Create benchmark/ directory and store benchmarks in.
- add tests for SOAP::WSDL::Definitions::create
- test for correct creation
- test against web service (fullerdata.com?)
- Improve docs
- Partially DONE
- Remove SOAP::Lite dependency - for now, just support HTTP(s) via LWP::UserAgent.
- Partially DONE. SOAP::WSDL still uses SOAP::Schema
- write inheritance Test for all XSD::Typelib::Builtin::* classes
- Check & probably fix simpleType support.
The WS at http://www.webservicex.net/genericbarcode.asmx?wsdl should make up a good example for simpleType
definitions.
- add default Fault11 typemap to generated typemaps
- DONE
- SOAP::WSDL::Definitions::create creates bad interface docs. Fix it.
- DONE
- update all Builtin Types to new constructor BEGIN block (Class::Std unfortunately is way slow)
- DONE.
- Remove useless (but on CPAN annoying) doc from Builtin::* classes
- DONE
- add example WS scripts
- DONE.
- SOAP::WSDL::XSD::Typelib::Builtin::string does not unescape XML builtin entities on get_value()
- WONTFIX.
Entities are unescaped by XML parser.
If you want the plain value, you have to use get_value, as XML conversion is overloaded on stringification.
- Make callin WS easier: implent WS-I-based SOAP::WSDL::Client::WSI
- WONTFIX - SOAP::WSDL::Base should behave equal
- add capability to create request objects based on input part definitions to SOAP::WSDL::Client::Base
- DONE.
TODO list for SOAP::WSDL
2.00 Pre-releases
--------
* SOAP Header support (#1764845)
* Implement a interface similar to SOAP::Schema (#1783639)
* (#1785195) Support deserializer plugins
* Support XML::Compiled as one serializer/deserializer
* Check & probably fix simpleType support.
The WS at http://www.webservicex.net/genericbarcode.asmx?wsdl should
make up a good example for simpleType definitions.
* Remove benchmarks from test. Create benchmark/ directory to store benchmarks.
* write inheritance Test for all XSD::Typelib::Builtin::* classes
* support embedded atomic types (#1761532)
Implement by including a second (and third and fourth)
package type_prefix::complex_type::element_name;
element package.
Maybe even allow unlimited depth? What does the specs say?
2.1 release
--------
Past 2.1 release
--------
* XML schema support ("minimal conformant") (#1764845)
* Support SOAP attachments

68
benchmark/01_expat.t Normal file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use lib '../lib';
use lib 'lib';
use lib '../t/lib';
use SOAP::WSDL::SAX::MessageHandler;
use Benchmark;
use SOAP::WSDL::Expat::MessageParser;
use XML::Simple;
use XML::LibXML;
use MyComplexType;
use MyElement;
use MySimpleType;
my $xml = q{<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >
<SOAP-ENV:Body><MyAtomicComplexTypeElement xmlns="urn:Test" >
<test>Test</test>
<test2 >Test2</test2>
</MyAtomicComplexTypeElement></SOAP-ENV:Body></SOAP-ENV:Envelope>};
my $parser = SOAP::WSDL::Expat::MessageParser->new({
class_resolver => 'FakeResolver'
});
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
my $libxml = XML::LibXML->new();
timethese 1000,
{
'SOAP::WSDL' => sub { $parser->parse( $xml ) },
#'XML::Simple (Hash)' => sub { XMLin $xml },
'XML::LibXML (DOM)' => sub { my $dom = $libxml->parse_string( $xml ) },
};
use Test::More tests => 1;
is $parser->get_data(), q{<MyAtomicComplexTypeElement xmlns="urn:Test" >}
. q{<test >Test</test><test2 >Test2</test2></MyAtomicComplexTypeElement>}
, 'Content comparison';
$parser->class_resolver( 'FakeResolver2' );
# data classes reside in t/lib/Typelib/
BEGIN {
package FakeResolver;
{
my %class_list = (
'MyAtomicComplexTypeElement' => 'MyAtomicComplexTypeElement',
'MyAtomicComplexTypeElement/test' => 'MyTestElement',
'MyAtomicComplexTypeElement/test2' => 'MyTestElement2',
);
sub get_map { return \%class_list };
sub new { return bless {}, 'FakeResolver' };
sub get_class {
my $name = join('/', @{ $_[1] });
return ($class_list{ $name }) ? $class_list{ $name }
: warn "no class found for $name";
};
};
};

View File

@@ -1,13 +1,10 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Fcntl;
use IO::File;
use Pod::Usage;
use Getopt::Long;
use LWP::UserAgent;
use SOAP::WSDL::SAX::WSDLHandler;
use XML::LibXML;
use SOAP::WSDL::Expat::WSDLParser;
my %opt = (
url => '',
@@ -39,8 +36,7 @@ my $url = $ARGV[0];
pod2usage( -exit => 1 , verbose => 2 ) if ($opt{help});
pod2usage( -exit => 1 , verbose => 1 ) if not ($url);
my $handler = SOAP::WSDL::SAX::WSDLHandler->new();
my $parser = XML::LibXML->new();
my $parser = SOAP::WSDL::Expat::WSDLParser->new();
local $ENV{HTTP_PROXY} = $opt{proxy} if $opt{proxy};
my $lwp = LWP::UserAgent->new();
@@ -49,16 +45,13 @@ die $response->message(), "\n" if $response->code != 200;
my $xml = $response->content();
$parser->set_handler( $handler );
$parser->parse_string( $xml );
my $wsdl = $handler->get_data();
my $wsdl = $parser->parse_string( $xml );
if ($opt{typemap_include}) {
my $fh = IO::File->new($opt{typemap_include} , O_RDONLY)
open my $fh , $opt{typemap_include}
or die "cannot open typemap_include file $opt{typemap_include}\n";
$opt{custom_types} = join q{}, $fh->getlines();
$fh->close();
$opt{custom_types} .= join q{}, <$fh>;
close $fh;
delete $opt{typemap_include};
}

View File

@@ -11,23 +11,37 @@
use lib 'lib/';
use MyInterfaces::FullerData_x0020_Fortune_x0020_Cookie;
use MyElements::GetFortuneCookie;
my $cookieService = MyInterfaces::FullerData_x0020_Fortune_x0020_Cookie->new();
my $cookie = $cookieService->GetFortuneCookie();
my $cookie;
$cookie = $cookieService->GetFortuneCookie()
or die "$cookie";
if ($cookie) {
print $cookie->get_GetFortuneCookieResult()->get_value, "\n";
}
else {
print $cookie;
}
print $cookie; # ->get_GetFortuneCookieResult()->get_value, "\n";
$cookie = $cookieService->GetSpecificCookie({ index => 23 });
if ($cookie) {
print $cookie
->get_GetSpecificCookieResult(), "\n";
}
else {
print $cookie;
}
$cookie = $cookieService->GetSpecificCookie({ index => 23 })
or die "$cookie";
print $cookie->get_GetSpecificCookieResult(), "\n";
print $cookie;
=for demo:
# the same in SOAP lite (second call)
#
use SOAP::Lite;
my $lite = SOAP::Lite->new()->on_action(sub { join '/', @_ } )
->proxy('http://www.fullerdata.com/FortuneCookie/FortuneCookie.asmx');
$lite->call(
SOAP::Data->name('GetSpecificCookie')
->attr({ 'xmlns', 'http://www.fullerdata.com/FortuneCookie/FortuneCookie.asmx' }),
SOAP::Data->name('index')->value(23)
);
die $soap->message() if ($soap->fault());
print $soap->result();

View File

@@ -3,6 +3,7 @@ use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
# atomic complexType
# <element name="GetCitiesByCountry"><complexType> definition
use SOAP::WSDL::XSD::Typelib::ComplexType;
@@ -16,7 +17,7 @@ my %CountryName_of :ATTR(:get<CountryName>);
__PACKAGE__->_factory(
[ qw(
[ qw(
CountryName
) ],
{
@@ -25,8 +26,8 @@ __PACKAGE__->_factory(
},
{
CountryName => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
CountryName => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
}
);
@@ -46,9 +47,16 @@ __PACKAGE__->__set_ref('');
__END__
=pod
=head1 NAME MyElements::GetCitiesByCountry
=head1 NAME
MyElements::GetCitiesByCountry
=head1 SYNOPSIS

View File

@@ -3,6 +3,7 @@ use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
# atomic complexType
# <element name="GetCitiesByCountryResponse"><complexType> definition
use SOAP::WSDL::XSD::Typelib::ComplexType;
@@ -16,7 +17,7 @@ my %GetCitiesByCountryResult_of :ATTR(:get<GetCitiesByCountryResult>);
__PACKAGE__->_factory(
[ qw(
[ qw(
GetCitiesByCountryResult
) ],
{
@@ -25,8 +26,8 @@ __PACKAGE__->_factory(
},
{
GetCitiesByCountryResult => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
GetCitiesByCountryResult => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
}
);
@@ -46,9 +47,16 @@ __PACKAGE__->__set_ref('');
__END__
=pod
=head1 NAME MyElements::GetCitiesByCountryResponse
=head1 NAME
MyElements::GetCitiesByCountryResponse
=head1 SYNOPSIS

View File

@@ -3,6 +3,7 @@ use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
# atomic complexType
# <element name="GetWeather"><complexType> definition
use SOAP::WSDL::XSD::Typelib::ComplexType;
@@ -18,9 +19,9 @@ my %CountryName_of :ATTR(:get<CountryName>);
__PACKAGE__->_factory(
[ qw(
[ qw(
CityName
CountryName
) ],
{
@@ -30,11 +31,11 @@ __PACKAGE__->_factory(
},
{
CityName => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
CityName => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
CountryName => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
CountryName => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
}
);
@@ -54,9 +55,16 @@ __PACKAGE__->__set_ref('');
__END__
=pod
=head1 NAME MyElements::GetWeather
=head1 NAME
MyElements::GetWeather
=head1 SYNOPSIS

View File

@@ -3,6 +3,7 @@ use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
# atomic complexType
# <element name="GetWeatherResponse"><complexType> definition
use SOAP::WSDL::XSD::Typelib::ComplexType;
@@ -16,7 +17,7 @@ my %GetWeatherResult_of :ATTR(:get<GetWeatherResult>);
__PACKAGE__->_factory(
[ qw(
[ qw(
GetWeatherResult
) ],
{
@@ -25,8 +26,8 @@ __PACKAGE__->_factory(
},
{
GetWeatherResult => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
GetWeatherResult => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
}
);
@@ -46,9 +47,16 @@ __PACKAGE__->__set_ref('');
__END__
=pod
=head1 NAME MyElements::GetWeatherResponse
=head1 NAME
MyElements::GetWeatherResponse
=head1 SYNOPSIS

View File

@@ -3,6 +3,7 @@ use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
#
# <element name="string" type="s:string"/> definition
#
@@ -26,9 +27,16 @@ __PACKAGE__->__set_ref('');
__END__
=pod
=head1 NAME MyElements::string
=head1 NAME
MyElements::string
=head1 SYNOPSIS

View File

@@ -1,4 +1,5 @@
package MyInterfaces::GlobalWeather;
use strict;
use warnings;
use MyTypemaps::GlobalWeather;
@@ -16,15 +17,29 @@ sub new {
}
__PACKAGE__->__create_methods(
GetWeather => [ 'MyElements::GetWeather', ],
GetCitiesByCountry => [ 'MyElements::GetCitiesByCountry', ],
GetWeather => {
parts => [ 'MyElements::GetWeather', ],
soap_action => 'http://www.webserviceX.NET/GetWeather',
style => 'document',
# use => '', # use not implemented yet
},
GetCitiesByCountry => {
parts => [ 'MyElements::GetCitiesByCountry', ],
soap_action => 'http://www.webserviceX.NET/GetCitiesByCountry',
style => 'document',
# use => '', # use not implemented yet
},
);
1;
__END__
=pod
=head1 NAME
@@ -64,5 +79,5 @@ SYNOPSIS:
=cut
=pod

View File

@@ -14,6 +14,7 @@ use MyInterfaces::GlobalWeather;
my $weather = MyInterfaces::GlobalWeather->new();
my $result = $weather->GetWeather({ CountryName => 'Germany', CityName => 'Munich' });
die $result->get_faultstring()->get_value() if not ($result); # boolean comparison overloaded
# boolean comparison overloaded
die $result->get_faultstring()->get_value() if not ($result);
print $result->get_GetWeatherResult()->get_value() "\n";
print $result->get_GetWeatherResult()->get_value() , "\n";

View File

@@ -23,3 +23,17 @@ my $som = $soap->wsdl("file:///$path/wsdl/globalweather.xml")
die $som->message() if $som->fault();
print $som->result();
# SOAP::Lite variant:
use SOAP::Lite;
my $soap = SOAP::Lite->new()->on_action( sub { join'/', @_ } )
->proxy("http://www.webservicex.net/globalweather.asmx");
my $som = $soap->call(
SOAP::Data->name('GetWeather')->attr({ xmlns => 'http://www.webserviceX.NET' }),
SOAP::Data->name('CountryName')->value('Germany'),
SOAP::Data->name('CityName')->value('Munich')
);
print $som->result();

View File

@@ -5,14 +5,11 @@ use vars qw($AUTOLOAD);
use Carp;
use Scalar::Util qw(blessed);
use SOAP::WSDL::Client;
use SOAP::WSDL::Envelope;
use SOAP::WSDL::SAX::WSDLHandler;
use SOAP::WSDL::Expat::WSDLParser;
use Class::Std;
use XML::LibXML;
use Data::Dumper;
use LWP::UserAgent;
our $VERSION='2.00_08';
our $VERSION='2.00_12';
my %no_dispatch_of :ATTR(:name<no_dispatch>);
my %wsdl_of :ATTR(:name<wsdl>);
@@ -64,8 +61,10 @@ for my $method (keys %LOOKUP ) {
};
}
{
# we need to roll our own for supporting
# SOAP::WSDL->new( key => value ) syntax,
# like SOAP::Lite does
no warnings qw(redefine);
sub new {
my $class = shift;
@@ -85,7 +84,6 @@ for my $method (keys %LOOKUP ) {
return $self;
}
}
sub wsdlinit {
@@ -98,13 +96,11 @@ sub wsdlinit {
croak $response->message() if ($response->code != 200);
# TODO: Port parser to expat and remove XML::LibXML dependency
my $parser = XML::LibXML->new();
my $filter = SOAP::WSDL::SAX::WSDLHandler->new();
$parser->set_handler( $filter );
my $parser = SOAP::WSDL::Expat::WSDLParser->new();
$parser->parse_string( $response->content() );
# sanity checks
my $wsdl_definitions = $filter->get_data() or die "unable to parse WSDL";
my $wsdl_definitions = $parser->get_data() or die "unable to parse WSDL";
my $types = $wsdl_definitions->first_types()
or die "unable to extract schema from WSDL";
my $ns = $wsdl_definitions->get_xmlns()
@@ -145,7 +141,7 @@ sub _wsdl_get_port :PRIVATE {
return $port_of{ $ident } = $portname_of{ $ident }
? $service_of{ $ident }->get_port( $ns, $portname_of{ $ident } )
: $port_of{ $ident } = $service_of{ $ident }->get_port()->[ 0 ];
} ## end sub _wsdl_get_port
}
sub _wsdl_get_binding :PRIVATE {
my $self = shift;
@@ -155,7 +151,7 @@ sub _wsdl_get_binding :PRIVATE {
$binding_of{ $ident } = $wsdl->find_binding( $wsdl->_expand( $port->get_binding() ) )
or die "no binding found for ", $port->get_binding();
return $binding_of{ $ident };
} ## end sub _wsdl_get_binding
}
sub _wsdl_get_portType :PRIVATE {
my $self = shift;
@@ -165,8 +161,7 @@ sub _wsdl_get_portType :PRIVATE {
$porttype_of{ $ident } = $wsdl->find_portType( $wsdl->_expand( $binding->get_type() ) )
or die "cannot find portType for " . $binding->get_type();
return $porttype_of{ $ident };
} ## end sub _wsdl_get_portType
}
sub _wsdl_init_methods :PRIVATE {
my $self = shift;
@@ -174,9 +169,7 @@ sub _wsdl_init_methods :PRIVATE {
my $wsdl = $definitions_of{ $ident };
my $ns = $wsdl->get_targetNamespace();
# get bindings, portType, message, part(s)
# - use cached values where possible for speed,
# private methods if not for clear separation...
# get bindings, portType, message, part(s) - use private methods for clear separation...
$self->_wsdl_get_service if not ($service_of{ $ident });
my $binding = $binding_of{ $ident } || $self->_wsdl_get_binding()
|| die "Can't find binding";
@@ -241,7 +234,6 @@ sub call {
my $response = (blessed $data)
? $client->call( $method, $data )
: do {
my $content = '';
# TODO support RPC-encoding: Top-Level element + namespace...
foreach my $part ( @{ $method_info_of{ $ident }->{ $method }->{ parts } } ) {
@@ -471,7 +463,19 @@ You may pass the servicename and portname as attributes to wsdlinit, though.
=head1 Differences to SOAP::Lite
=head3 Output formats
=head2 Message style/encoding
While SOAP::Lite supports rpc/encoded style/encoding only, SOAP::WSDL currently
supports document/literal style/encoding.
=head2 autotype / type information
SOAP::Lite defaults to transmitting XML type information by default, where
SOAP::WSDL defaults to leaving it out.
autotype(1) might even be broken in SOAP::WSDL - it's not well-tested, yet.
=head2 Output formats
In contrast to SOAP::Lite, SOAP::WSDL supports the following output formats:
@@ -498,7 +502,7 @@ See below.
=back
=head3 outputxml
=head2 outputxml
SOAP::Lite returns only the content of the SOAP body when outputxml is set
to true. SOAP::WSDL returns the complete XML response.
@@ -565,7 +569,7 @@ Passing in item => [1,2,3] could serialize to
<item>1 2</item><item>3</item>
<item>1</item><item>2 3</item>
Ambiguos data can be avoided by passing an objects as data.
Ambiguos data can be avoided by providing data as objects.
=item * XML Schema facets
@@ -588,6 +592,41 @@ The following facets have no influence yet:
=back
=head1 SEE ALSO
=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 * <XML::Compile::WSDL|XML::Compile::WSDL>
A promising-looking approach derived from a cool functional DOM-based XML schema parser.
Will support encoding/decoding of SOAP messages based on WSDL definitions.
Not yet finished at the time of writing - but you may wish to give it a try, especially
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
There are many people out there who fostered SOAP::WSDL's developement.
@@ -595,7 +634,7 @@ I would like to thank them all (and apologize to all those I have forgotten).
Giovanni S. Fois wrote a improved version of SOAP::WSDL (which eventually became v1.23)
Damian A. Martinez Gelabert, Dennis S. Hennen, Dan Horne, Peter Orvos, Marc Overmeer,
Damian A. Martinez Gelabert, Dennis S. Hennen, Dan Horne, Peter Orvos, Mark Overmeer,
Jon Robens, Isidro Vila Verde and Glenn Wood spotted bugs and/or
suggested improvements in the 1.2x releases.
@@ -615,7 +654,14 @@ the same terms as perl itself
=head1 AUTHOR
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 188 $
$LastChangedBy: kutterma $
$Id: WSDL.pm 188 2007-09-03 15:15:19Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL.pm $
=cut

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) {

View File

@@ -8,28 +8,44 @@ 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...
our $VERSION='2.00_12';
# 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 +55,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 +123,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 +204,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 +233,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
@@ -284,7 +381,12 @@ the same terms as perl itself
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 188 $
$LastChangedBy: kutterma $
$Id: Client.pm 188 2007-09-03 15:15:19Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Client.pm $
=cut

View File

@@ -21,23 +21,37 @@ 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;
$self->call( $method, @param );
return $self->SUPER::call( {
operation => $method,
soap_action => $soap_action,
}, @param );
}
}
}
1;
@@ -48,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

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,33 +181,42 @@ 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;
__END__
=pod
[% MACRO pod BLOCK %]=pod[% END %]
[% MACRO cut BLOCK %]=pod[% END %]
[% MACRO head1 BLOCK %]=head1[% END %]
[% MACRO head2 BLOCK %]=head2[% END %]
[% pod %]
=head1 NAME
[% head1 %] NAME
[% interface_prefix %][% service.get_name %] - SOAP interface to [% service.get_name %] at
[% service.first_port.get_location %]
=head1 SYNOPSIS
[% head1 %] SYNOPSIS
my $interface = [% interface_prefix %][% service.get_name %]->new();
my $[% operations.keys.1 %] = $interface->[% operations.keys.1 %]();
=head1 METHODS
[% head1 %] METHODS
[% FOREACH name=operations.keys;
operation=operations.$name;
%]
=head2 [% name %]
[% head2 %] [% name %]
[% operation.documentation %]
@@ -211,7 +227,7 @@ SYNOPSIS:
[% END %]
=cut
[% cut %]
EOT

View File

@@ -5,29 +5,10 @@ use warnings;
use SOAP::WSDL::XSD::Typelib::Builtin;
use XML::Parser::Expat;
=pod
=head2 new
=over
=item SYNOPSIS
my $obj = ->new();
=item DESCRIPTION
Constructor.
=back
=cut
sub new {
my $class = shift;
my $args = shift;
my ($class, $args) = @_;
my $self = {
class_resolver => $args->{ class_resolver }
class_resolver => $args->{ class_resolver },
};
bless $self, $class;
return $self;
@@ -39,33 +20,39 @@ sub class_resolver {
}
sub _initialize {
my $self = shift;
my ($self, $parser) = @_;
$self->{ data } = undef;
delete $self->{ data }; # remove potential old results
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 $path = []; # current path
my $skip = 0; # skip elements
my $parser = XML::Parser::Expat->new();
# use "globals" for speed
my ($_prefix, $_localname, $_element, $_method,
$_class, $_parser, %_attrs) = ();
no strict qw(refs);
$parser->setHandlers(
Start => sub {
($_parser, $_element, %_attrs) = @_;
($_prefix, $_localname) = split m{:}xms , $_element;
$_localname ||= $_element; # for non-prefixed elements
$_localname ||= $_element; # for non-prefixed elements
# ignore top level elements
if (@{ $ignore } && $_localname eq $ignore->[0]) {
if (@{ $ignore } && $_localname eq $ignore->[0]) {
CHECK_ENVELOPE: {
last CHECK_ENVELOPE if $_localname ne 'Envelope';
last CHECK_ENVELOPE if exists $_attrs{ 'xmlns' }
&& $_attrs{ 'xmlns' } eq 'http://schemas.xmlsoap.org/soap/envelope/';
last CHECK_ENVELOPE if $_attrs{ "xmlns:$_prefix"}
eq 'http://schemas.xmlsoap.org/soap/envelope/';
die "Bad namespace for SOAP envelope: " . $parser->recognized_string();
}
shift @{ $ignore };
return;
}
@@ -73,39 +60,40 @@ sub _initialize {
push @{ $path }, $_localname; # step down in path
return if $skip; # skip inside __SKIP__
# resolve class of this element
# resolve class of this element
$_class = $self->{ class_resolver }->get_class( $path )
or die "Cannot resolve class for "
. join('/', @{ $path }) . " via $self->{ class_resolver }";
. join('/', @{ $path }) . " via " . $self->{ class_resolver };
if ($_class eq '__SKIP__') {
$skip = join '/', @{ $path };
return;
}
# 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
# TODO replace with UNIVERSAL->isa()
# 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.
# check wheter there is a non-empty ARRAY reference for $_class::ISA
# or a "new" method
# 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 }
# This is not exactly the same as $class->can('new'), but it's way faster
defined *{ "$_class\::new" }{ CODE }
or scalar @{ *{ "$_class\::ISA" }{ ARRAY } }
or eval "require $_class" ## no critic qw(ProhibitStringyEval)
or die $@;
or die $@;
}
$current = $_class->new({ %_attrs }); # set new current object
# remember top level element
defined $self->{ data }
exists $self->{ data }
or ($self->{ data } = $current);
},
@@ -146,8 +134,8 @@ sub _initialize {
# set appropriate attribute in last element
# multiple values must be implemented in base class
$_method = "add_$_localname";
$$list[-1]->$_method( $current );
$$list[-1]->$_method( $current );
$current = pop @$list; # step up in object hierarchy...
}
);
@@ -155,18 +143,24 @@ sub _initialize {
}
sub parse {
$_[0]->_initialize->parse( $_[1] );
$_[0]->_initialize( XML::Parser::Expat->new() )->parse( $_[1] );
return $_[0]->{ data };
}
sub parsefile {
$_[0]->_initialize->parsefile( $_[1] );
$_[0]->_initialize( XML::Parser::Expat->new() )->parsefile( $_[1] );
return $_[0]->{ data };
}
# SAX-like aliases
sub parse_string;
*parse_string = \&parse;
sub parse_file;
*parse_file = \&parsefile;
sub get_data {
my $self = shift;
return $self->{ data };
return $_[0]->{ data };
}
1;
@@ -224,9 +218,9 @@ This module may be used under the same terms as perl itself.
$ID: $
$LastChangedDate: $
$LastChangedRevision: $
$LastChangedBy: $
$LastChangedDate: 2007-09-02 21:05:18 +0200 (So, 02 Sep 2007) $
$LastChangedRevision: 184 $
$LastChangedBy: kutterma $
$HeadURL: $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Expat/MessageParser.pm $

View File

@@ -2,148 +2,25 @@
package SOAP::WSDL::Expat::MessageStreamParser;
use strict;
use warnings;
use SOAP::WSDL::XSD::Typelib::Builtin;
use XML::Parser::Expat;
use SOAP::WSDL::Expat::MessageParser;
use base qw(SOAP::WSDL::Expat::MessageParser);
=pod
=head2 new
=over
=item SYNOPSIS
my $obj = ->new();
=item DESCRIPTION
Constructor.
=back
=cut
sub new {
my $class = shift;
my $self = {
class_resolver => shift->{ class_resolver }
};
bless $self, $class;
return $self;
}
sub class_resolver {
sub parse_start {
my $self = shift;
$self->{ class_resolver } = shift;
$self->{ parser } = $_[0]->_initialize( XML::Parser::ExpatNB->new() );
}
sub init {
my $self = shift;
my $xml = shift;
$self->{ data } = undef;
my $characters;
my $current = '__STOP__';
my $ignore = [ 'Envelope', 'Body' ];
my $list = [];
my $namespace = {};
my $path = [];
my $parser = XML::Parser::ExpatNB->new();
sub init;
*init = \&parse_start;
no strict qw(refs);
$parser->setHandlers(
Start => sub {
my ($parser, $element, %attrs) = @_;
my ($prefix, $localname) = split m{:}xms , $element;
# for non-prefixed elements
if (not $localname) {
$localname = $element;
$prefix = q{};
}
# ignore top level elements
if (@{ $ignore } && $localname eq $ignore->[0]) {
shift @{ $ignore };
return;
}
# empty characters
$characters = q{};
push @{ $path }, $localname; # step down...
push @{ $list }, $current; # remember current
# resolve class of this element
my $class = $self->{ class_resolver }->get_class( $path )
or die "Cannot resolve class for "
. join('/', @{ $path }) . " via $self->{ class_resolver }";
# Check whether we have a primitive - we implement them as classes
# TODO replace with UNIVERSAL->isa()
# match is a bit faster if the string does not match, but WAY slower
# if $class matches...
# if (not $class=~m{^SOAP::WSDL::XSD::Typelib::Builtin}xms) {
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 $@;
}
# create object
# set current object
$current = $class->new({ %attrs });
# remember top level element
defined $self->{ data }
or ($self->{ data } = $current);
},
Char => sub {
$characters .= $_[1];
},
End => sub {
my $element = $_[1];
my ($prefix, $localname) = split m{:}xms , $element;
# for non-prefixed elements
if (not $localname) {
$localname = $element;
$prefix = q{};
}
# This one easily handles ignores for us, too...
return if not ref $list->[-1];
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
my $method = "add_$localname";
$list->[-1]->$method( $current );
# step up in path
pop @{ $path };
# step up in object hierarchy...
$current = pop @{ $list };
}
);
return $parser;
sub parse_more {
$_[0]->{ parser }->parse_more( $_[1] );
}
sub get_data {
my $self = shift;
return $self->{ data };
sub parse_done {
$_[0]->{ parser }->parse_done();
}
1;
=pod
@@ -174,15 +51,7 @@ See L<SOAP::WSDL::Parser> for details.
=head1 Bugs and Limitations
=over
=item * Ignores all namespaces
=item * Does not handle mixed content
=item * The SOAP header is ignored
=back
See SOAP::WSDL::Expat::MessageParser
=head1 AUTHOR
@@ -198,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 $

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 $

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 $

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;

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

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

View File

@@ -35,9 +35,6 @@ the service's interface structure.
The results of all calls to your service object's methods (except new)
are objects based on SOAP::WSDL's XML schema implementation.
These objects are false in boolean context, and serialize to XML when
printed.
To access the object's properties use get_NAME / set_NAME getter/setter
methods whith NAME corresponding to the XML tag name.

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

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

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 $

View File

@@ -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 });

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

View File

@@ -181,7 +181,7 @@ sub to_class {
my $template = <<'EOT';
package [% type_prefix %][% self.get_name %];
use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::ComplexType;
use base qw(
SOAP::WSDL::XSD::Typelib::ComplexType
@@ -192,17 +192,17 @@ my %[% element.get_name %]_of :ATTR(:get<[% element.get_name %]>);
[% END %]
__PACKAGE__->_factory(
[ qw([% FOREACH element=self.get_element -%]
[% element.get_name %]
[ qw([% FOREACH element=self.get_element -%]
[% element.get_name %]
[% END %]) ],
{
[% FOREACH element=self.get_element %][% element.get_name %] => \%[% element.get_name %]_of,
[% END %]
{
[% FOREACH element=self.get_element %][% element.get_name %] => \%[% element.get_name %]_of,
[% END %]
},
{
[%-
[%-
FOREACH element=self.get_element;
IF (element.get_type);
IF (element.get_type); # element type="..."
split_name = element.get_type.split(':');
prefix = split_name.0;
localname = split_name.1;
@@ -210,8 +210,13 @@ __PACKAGE__->_factory(
[% element.get_name %] => 'SOAP::WSDL::XSD::Typelib::Builtin::[% localname %]',
[% ELSE -%]
[% element.get_name %] => '[% type_prefix %][% localname %]',
[%- END;
ELSIF (simpleType = element.first_simpleType);
[%- END;
ELSIF (element.get_ref); # element ref="..."
split_name = element.get_ref.split(':');
prefix = split_name.0;
localname = split_name.1; %]
[% element.get_name %] => '[% type_prefix %][% localname %]',
[% ELSIF (simpleType = element.first_simpleType);
base = simpleType.get_base();
%]
# basic simple type handling: we treat atomic simple types
@@ -237,18 +242,25 @@ sub get_xmlns { '[% self.get_targetNamespace %]' }
1;
__END__
[% MACRO pod BLOCK %]=pod[% END %]
[% MACRO cut BLOCK %]=cut[% END %]
[% MACRO head1 BLOCK %]=head1[% END %]
[% MACRO head2 BLOCK %]=head2[% END %]
[% pod %]
[% head1 %] NAME
[% type_prefix %][% self.get_name %]
=pod
[% head1 %] SYNOPSIS
=head1 NAME [% type_prefix %][% self.get_name %]
=head1 SYNOPSIS
=head1 DESCRIPTION
[% head1 %] DESCRIPTION
Type class for the XML type [% self.get_name %].
=head1 PROPERTIES
[% head1 %] PROPERTIES
The following properties may be accessed using get_PROPERTY / set_PROPERTY
methods:
@@ -257,7 +269,7 @@ methods:
[% element.get_name -%]
[% END %]
=head1 Object structure
[% head1 %] Object structure
[% FOREACH element=self.get_element;
IF (element.get_type);
@@ -269,7 +281,12 @@ methods:
[% ELSE -%]
[% element.get_name %] => '[% type_prefix %][% localname %]',
[%- END;
ELSIF (simpleType = element.first_simpleType);
ELSIF (element.get_ref); # element ref="..."
split_name = element.get_ref.split(':');
prefix = split_name.0;
localname = split_name.1; %]
[% element.get_name %] => '[% type_prefix %][% localname %]',
[% ELSIF (simpleType = element.first_simpleType);
base = simpleType.get_base();
split_name = base.split(':');
prefix = split_name.0;
@@ -292,7 +309,7 @@ Structure as perl hash:
[% structure %]
=cut
[% cut %]
EOT

View File

@@ -90,8 +90,8 @@ sub serialize {
elsif (my $ref_name = $ref_of{ $ident }) { # ref
my ($prefix, $localname) = split /:/ , $ref_name;
my $ns = $ns_map{ $prefix };
$type = $typelib->find_type( $ns, $localname );
die "no type for $prefix:$localname" if (not $type);
$type = $typelib->find_element( $ns, $localname );
die "no element for ref $prefix:$localname" if (not $type);
return $type->serialize( $name, $value, $opt );
}
@@ -130,6 +130,12 @@ sub explain {
}
return $type->explain( $opt, $self->get_name() );
}
elsif (my $element_name = $self->get_ref() ) {
my $element = $opt->{ wsdl }->first_types()->find_element(
$opt->{ wsdl }->_expand( $element_name )
);
return $element->explain( $opt, $self->get_name() );
}
# return if it's not a derived type - we don't handle
# other stuff yet.
@@ -152,7 +158,7 @@ sub explain {
delete $opt->{ anonymous };
return $text .= $type->explain( $opt, undef );
}
return $text .= $type->explain( $opt, $self->get_name() );
return $text .= $type->explain( $opt, $name || $self->get_name() );
return 'ERROR: '. $@;
}
@@ -238,8 +244,9 @@ sub to_class {
my $template = <<'EOT';
package [% element_prefix %][% self.get_name %];
use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
[% IF (type = self.first_simpleType) %]
# <element name="[% self.get_name %]"><simpleType> definition
use SOAP::WSDL::XSD::Typelib::SimpleType;
@@ -249,6 +256,17 @@ use base qw(
[% type.flavor_class %]
[% type.base_class($type_prefix) %]
);
[% ELSIF (ref_name = self.get_ref);
split_name = ref_name.split(':');
prefix = split_name.0;
localname = split_name.1;
ref_class = element_prefix _ localname;
%]
# <element name="[% self.get_name %]" ref="[% ref_name %]"> definition
# use [% ref_class %];
use base qw(
[% ref_class %]
);
[% ELSIF (type = self.first_complexType) %]
# atomic complexType
# <element name="[% self.get_name %]"><complexType> definition
@@ -263,7 +281,7 @@ my %[% element.get_name %]_of :ATTR(:get<[% element.get_name %]>);
[% END %]
__PACKAGE__->_factory(
[ qw([% FOREACH element = type.get_element %]
[ qw([% FOREACH element = type.get_element %]
[% element.get_name %]
[% END %]) ],
{
@@ -276,10 +294,10 @@ __PACKAGE__->_factory(
prefix = split_name.0;
localname = split_name.1;
IF nsmap.$prefix == 'http://www.w3.org/2001/XMLSchema' %]
[% element.get_name %] => 'SOAP::WSDL::XSD::Typelib::Builtin::[% localname %]',
[% element.get_name %] => 'SOAP::WSDL::XSD::Typelib::Builtin::[% localname %]',
[% ELSE %]
[% element.get_name %] => '[% type_prefix %][% localname %]',
[% END %]
[% END %]
[% END %]
}
);
@@ -304,10 +322,6 @@ use base qw(
SOAP::WSDL::XSD::Typelib::Element
[% base_class %]
);
[% ELSIF (element = self.get_ref)
%]
# element ref"element" definition
# Sorry, we don't handle this yet...
[% END %]
sub get_xmlns { '[% self.get_targetNamespace %]' }
@@ -322,18 +336,25 @@ __PACKAGE__->__set_ref('[% self.get_ref %]');
__END__
[% MACRO pod BLOCK %]=pod[% END %]
[% MACRO cut BLOCK %]=cut[% END %]
[% MACRO head1 BLOCK %]=head1[% END %]
[% MACRO head2 BLOCK %]=head2[% END %]
[% pod %]
[% head1 %] NAME
=pod
[% element_prefix %][% self.get_name %]
=head1 NAME [% element_prefix %][% self.get_name %]
[% head1 %] SYNOPSIS
=head1 SYNOPSIS
=head1 DESCRIPTION
[% head1 %] DESCRIPTION
Type class for the XML element [% self.get_name %].
=head1 PROPERTIES
[% head1 %] PROPERTIES
The following properties may be accessed using get_PROPERTY / set_PROPERTY
methods:
@@ -344,7 +365,7 @@ methods:
[% END;
END %]
=head1 Object structure
[% head1 %] Object structure
[%- IF (type = self.first_complexType);
FOREACH element = type.get_element;
@@ -368,8 +389,8 @@ Structure as perl hash:
tree.
[% structure %]
=cut
[% cut %]
EOT

View File

@@ -7,6 +7,7 @@ use base qw(SOAP::WSDL::Base);
# child elements
my %type_of :ATTR(:name<type> :default<[]>);
my %element_of :ATTR(:name<element> :default<[]>);
my %group_of :ATTR(:name<group> :default<[]>);
# attributes
my %attributeFormDefault_of :ATTR(:name<attributeFormDefault> :default<()>);

View File

@@ -29,6 +29,13 @@ sub as_bool :BOOLIFY {
return $value_of { ident $_[0] };
}
sub _get_handlers {
my $parser = $_[1];
return {
Char => $parser->characters(),
}
}
Class::Std::initialize(); # make :BOOLIFY overloading serializable

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);
@@ -40,7 +41,7 @@ sub serialize {
, $self->end_tag($opt);
}
sub as_num :NUMERIFY {
sub as_num :NUMERIFY :BOOLIFY {
return $_[0]->get_value();
}

View File

@@ -36,10 +36,10 @@ BEGIN {
sub set_value {
# use set_value from base class if we have a XML-DateTime format
#2037-12-31T00:00:00.0000000+01:00
#2037-12-31+01:00
if (
$_[1] =~ m{ ^\d{4} \- \d{2} \- \d{2}
(:? [\+\-] \d{2} \: \d{2} )?
(:? [\+\-] \d{2} \: \d{2} )?$
}xms
) {
$_[0]->SUPER::set_value($_[1])
@@ -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);

View File

@@ -37,26 +37,20 @@ BEGIN {
sub set_value {
# use set_value from base class if we have a XML-DateTime format
#2037-12-31T00:00:00.0000000+01:00
if (
return $_[0]->SUPER::set_value($_[1]) if (
$_[1] =~ m{ ^\d{4} \- \d{2} \- \d{2}
T \d{2} \: \d{2} \: \d{2} (:? \. \d{1,7} )?
[\+\-] \d{2} \: \d{2} $
}xms
) {
$_[0]->SUPER::set_value($_[1])
}
# use a combination of strptime and strftime for converting the date
# Unfortunately, strftime outputs the time zone as [+-]0000, whereas XML
# whants it as [+-]00:00
# 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_str = strftime( '%Y-%m-%dT%H:%M:%S%z', @time_from );
substr $time_str, -2, 0, ':';
$_[0]->SUPER::set_value($time_str);
}
);
# strptime sets empty values to undef - and strftime doesn't like that...
my @time_from = map { ! defined $_ ? 0 : $_ } strptime($_[1]);
undef $time_from[-1];
my $time_str = strftime( '%Y-%m-%dT%H:%M:%S%z', @time_from );
substr $time_str, -2, 0, ':';
$_[0]->SUPER::set_value($time_str);
}
1;

View File

@@ -22,26 +22,3 @@ BEGIN {
};
}
1;
__END__
=pod
=head1 NAME
SOAP::WSDL::XSD::Typelib::Builtin::unsignedLong - unsigned long integer objects
=head1 DESCRIPTION
Subclass of nonNegativeInteger.
=head1 LICENSE
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>
=cut

View File

@@ -1,12 +1,12 @@
#!/usr/bin/perl
package SOAP::WSDL::XSD::Typelib::ComplexType;
use strict;
use warnings;
use Carp;
use SOAP::WSDL::XSD::Typelib::Builtin;
use Scalar::Util qw(blessed);
use Class::Std::Storable;
use Scalar::Util qw(blessed refaddr);
use Data::Dumper;
use Class::Std::Storable;
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anyType);
@@ -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 {
@@ -29,56 +55,50 @@ sub _factory {
my $type = $CLASSES_OF{ $class }->{ $name }
or die "No class given for $name";
# require all types here - this is a slow check -
# TODO speedup
# require all types here
$type->isa('UNIVERSAL')
or eval "require $type"
or croak $@;
# check now, so we don't need to do it later...
my $is_list = $type->isa('SOAP::WSDL::XSD::Typelib::Builtin::list');
*{ "$class\::set_$name" } = sub {
my ($self, $value) = @_;
# my ($self, $value) = @_;
=pod
# The structure below looks rather weird, but is optimized for performance.
#
# We could use sub calls for sure, but these are much slower. And the logic
# is not that easy:
#
# we accept:
# a) objects
# b) scalars
# c) list refs
# d) hash refs
# e) mixed stuff of all of the above, so we have to set our element to
# a) value if it's an object
# b) New object of expected class with value for simple values
# c 1) New object with value for list values and list type
# c 2) List ref of new objects with value for list values and non-list type
# c + e 1) List ref of objects for list values (list of objects) and non-list type
# c + e 2) List ref of new objects for list values (list of hashes) and non-list type
# where the hash ref is passed to new as argument
# d) New object with values passed to new for HASH references
#
# We throw an error on
# a) list refs of list refs - don't know what to do with this (maybe use for lists of list types ?)
# b) wrong object types
# c) non-blessed non-ARRAY/HASH references - if you can define semantics
# for GLOB references, feel free to add them.
# d) we should also die for non-blessed non-ARRAY/HASH references in lists but don't do yet - oh my !
=for developers
The structure below looks rather weird, but is optimized for performance.
We could use sub calls for sure, but these are much slower. And the logic
is not that easy:
we accept:
a) objects
b) scalars
c) list refs
d) hash refs
e) mixed stuff of all of the above, so we have to set our element to
a) value if it's an object
b) New object of expected class with value for simple values
c 1) New object with value for list values and list type
c 2) List ref of new objects with value for list values and non-list type
c + e 1) List ref of objects for list values (list of objects) and non-list type
c + e 2) List ref of new objects for list values (list of hashes) and non-list type
where the hash ref is passed to new as argument
d) New object with values passed to new for HASH references
We throw an error on
a) list refs of list refs - don't know what to do with this (maybe use for lists of list types ?)
b) wrong object types
c) non-blessed non-ARRAY/HASH references - if you can define semantics
for GLOB references, feel free to add them.
d) we should also die for non-blessed non-ARRAY/HASH references in lists but don't do yet - oh my !
=cut
my $is_ref = ref $value;
$attribute_ref->{ ident $self } = ($is_ref)
my $is_ref = ref $_[1];
$attribute_ref->{ ident $_[0] } = ($is_ref)
? $is_ref eq 'ARRAY'
? $is_list
? $type->new({ value => $value })
: [ map {
? $is_list # remembered from outside closure
? $type->new({ value => $_[1] }) # list element - can take list ref as value
: [ map {
ref $_
? ref $_ eq 'HASH'
? $type->new($_)
@@ -86,98 +106,110 @@ is not that easy:
? $_
: croak "cannot use " . ref($_) . " reference as value for $name - $type required"
: $type->new({ value => $_ })
} @{ $value }
} @{ $_[1] }
]
: $is_ref eq 'HASH'
? $type->new( $value )
? $type->new( $_[1] )
: $is_ref eq $type
? $value
: die 'Cannot use non-ARRAY/HASH as data'
: $type->new({ value => $value });
? $_[1]
: die croak "cannot use $is_ref reference as value for $name - $type required"
: $type->new({ value => $_[1] });
};
*{ "$class\::add_$name" } = sub {
my ($self, $value) = @_;
my $ident = ident $self;
if (not defined $value) {
warn "attempting to add empty value to " . ref $self;
}
return $attribute_ref->{ $ident } = $value
my $ident = ident $_[0];
warn "attempting to add empty value to " . ref $_[0]
if not defined $_[1];
# first call
return $attribute_ref->{ $ident } = $_[1]
if not defined $attribute_ref->{ $ident };
# listify previous value if it's no list
# second call: listify previous value if it's no list
$attribute_ref->{ $ident } = [ $attribute_ref->{ $ident } ]
if not ref $attribute_ref->{ $ident } eq 'ARRAY';
# add to list
return push @{ $attribute_ref->{ $ident } }, $value;
# second and following: add to list
return push @{ $attribute_ref->{ $ident } }, $_[1];
};
*{ "$class\::START" } = sub {
my ($self, $ident, $args_of) = @_;
# iterate over keys of arguments
# and call set appropriate field in clase
map { ($ATTRIBUTES_OF{ $class }->{ $_ })
? do {
my $method = "set_$_";
$self->$method( $args_of->{ $_ } );
}
: $_ =~ m{ \A # beginning of string
xmlns # xmlns
}xms
? do {}
: do { use Data::Dumper;
croak "unknown field $_ in $class. Valid fields are "
. join(', ', @{ $ELEMENTS_FROM{ $class } }) . "\n"
. Dumper @_ };
# TODO maybe only warn for unknown fields ?
} keys %$args_of;
};
# this serialize method works fine for <all> and <sequence>
# complextypes, as well as for <restriction><all> or
# <restriction><sequence>.
# But what about choice, group, extension ?
#
*{ "$class\::$name" } = *{ "$class\::add_$name" };
}
*{ "$class\::_serialize" } = sub {
my $ident = ident $_[0];
# my $class = ref $_[0];
# return concatenated return value of serialize call of all
# elements retrieved from get_elements expanding list refs.
# get_elements is inlined for performance.
return join q{} , map {
my $element = $ATTRIBUTES_OF{ $class }->{ $_ }->{ $ident };
if (defined $element) {
$element = [ $element ]
if not ref $element eq 'ARRAY';
my $name = $_;
*{ "$class\::new" } = sub {
my $self = bless \my ($o), $_[0];
$self->BUILD( ident $self, $_[1] ) if exists &BUILD;
$self->_init( ident $self, $_[1] );
$self->START( ident $self, $_[1] ) if exists &START;
return $self;
};
*{ "$class\::_init" } = sub {
# We're working on @_ for speed.
# Normally, the first line would look like this:
# my ($self, $ident, $args_of) = @_;
#
# The hanging side comment show you what would be there, then.
# iterate over keys of arguments
# and call set appropriate field in clase
map { ($ATTRIBUTES_OF{ $class }->{ $_ })
? do {
my $method = "set_$_";
$_[0]->$method( $_[2]->{ $_ } ); # ( $args_of->{ $_ } );
}
: $_ =~ m{ \A # beginning of string
xmlns # xmlns
}xms
? do {}
: do { use Data::Dumper;
croak "unknown field $_ in $class. Valid fields are:\n"
. join(', ', @{ $ELEMENTS_FROM{ $class } }) . "\n"
. "Structure given:\n" . Dumper @_ };
} keys %{ $_[2] }; # %$args_of;
return $_[0]; # $self;
};
# this serialize method works fine for <all> and <sequence>
# complextypes, as well as for <restriction><all> or
# <restriction><sequence>.
# But what about choice, extension ?
*{ "$class\::_serialize" } = sub {
my $ident = ident $_[0];
# my $class = ref $_[0];
# return concatenated return value of serialize call of all
# elements retrieved from get_elements expanding list refs.
# get_elements is inlined for performance.
return join q{} , map {
my $element = $ATTRIBUTES_OF{ $class }->{ $_ }->{ $ident };
# do we have some content
if (defined $element) {
$element = [ $element ]
if not ref $element eq 'ARRAY';
my $name = $_;
map {
# serialize element elements with their own serializer
# but name them like they're named here.
if ( $_->isa( 'SOAP::WSDL::XSD::Typelib::Element' ) ) {
$_->serialize( { name => $name } );
}
# serialize complextype elments (of other types) with their
# serializer, but add element tags around.
else {
join q{}, $_->start_tag({ name => $name })
, $_->serialize()
, $_->end_tag({ name => $name });
}
} @{ $element }
}
else {
q{};
}
} (@{ $ELEMENTS_FROM{ $class } });
};
map {
# serialize element elements with their own serializer
# but name them like they're named here.
if ( $_->isa( 'SOAP::WSDL::XSD::Typelib::Element' ) ) {
$_->serialize( { name => $name } );
}
# serialize complextype elments (of other types) with their
# serializer, but add element tags around.
else {
join q{}, $_->start_tag({ name => $name })
, $_->serialize()
, $_->end_tag({ name => $name });
}
} @{ $element }
}
else {
q{};
}
} (@{ $ELEMENTS_FROM{ $class } });
};
*{ "$class\::serialize" } = sub {
my ($self, $opt) = @_;
@@ -191,7 +223,7 @@ is not that easy:
}
}
1;
__END__
@@ -202,6 +234,81 @@ __END__
SOAP::WSDL::XSD::Typelib::ComplexType - complexType base class
=head1 Subclassing
package MyComplexType;
use Class::Std::Storable
use base qw(SOAP::WSDL::XSD::Typelib::ComplexType);
__PACKAGE__->_factory(
\@elements_from,
\%attributes_of,
\%classes_of
);
When subclassing, the following methods are created in the subclass:
=head2 new
Constructor. For your convenience, new will accept data for the object's
properties in the following forms:
hash refs
1) of scalars
2) of list refs
3) of hash refs
4) of objects
5) mixed stuff of all of the above
new() will set the data via the set_FOO methods to the object's element
properties.
Data passed to new must comply to the object's structure or new() will
complain. Objects passed must be of the expected type, or new() will
complain, too.
Examples:
my $obj = MyClass->new({ MyName => $value });
my $obj = MyClass->new({
MyName => {
DeepName => $value
},
MySecondName => $value,
});
my $obj = MyClass->new({
MyName => [
{ DeepName => $value },
{ DeepName => $other_value },
],
MySecondName => $object,
MyThirdName => [ $object1, $object2 ],
});
To be correct, SOAP::WSDL::XSD::Typelib::ComplexType will create a START
method, not new() - but new() will be created from Class::Std::Storable and
behave like stated above.
=head2 set_FOO
A mutator method for every element property.
For your convenience, the set_FOO methods will accept all kind of data you
can think of (and all combinations of them) as input - with the exception
of GLOBS and filehandles.
This means you may set element properties by passing
a) objects
b) scalars
c) list refs
d) hash refs
e) mixed stuff of all of the above
Examples are similar to the examples provided for new() above.
=head1 Bugs and limitations
=over

View File

@@ -1,8 +1,6 @@
#!/usr/bin/perl
package SOAP::WSDL::XSD::Typelib::Element;
use strict;
use Class::Std::Storable;
use Data::Dumper;
my %NAME;
my %NILLABLE;

View File

@@ -15,7 +15,6 @@ my @modules = qw(
SOAP::WSDL::Port
SOAP::WSDL::PortType
SOAP::WSDL::Types
SOAP::WSDL::SAX::WSDLHandler
SOAP::WSDL::XSD::Builtin
SOAP::WSDL::XSD::ComplexType
SOAP::WSDL::XSD::SimpleType

327
t/002_parse_wsdl.t Normal file
View File

@@ -0,0 +1,327 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 17;
use lib '../lib';
eval {
require Test::XML;
import Test::XML;
};
use_ok(qw/SOAP::WSDL::Expat::WSDLParser/);
my $filter;
my $parser = SOAP::WSDL::Expat::WSDLParser->new();
$parser->parse_string( xml() );
my $wsdl;
ok( $wsdl = $parser->get_data() , "get object tree");
my $types = $wsdl->first_types();
is $types->get_parent(), $wsdl , 'types parent';
my $serializer_options = {
readable => 1,
autotype => 1,
namespace => { 'urn:myNamespace' => 'tns',
"http://www.w3.org/2001/XMLSchema" => 'xsd' },
typelib => $wsdl->first_types(),
indent => "\t",
};
my $xml;
my $type = $types->find_type( 'urn:myNamespace', 'testSimpleType1' );
ok($xml = $type->serialize( 'test', 1 , $serializer_options ),
"serialize simple Type"
);
# print $xml;
SKIP: {
skip_without_test_xml();
is_xml( $xml, '<test type="tns:testSimpleType1">1</test>',
"content compare" );
};
$type = $types->find_type( 'urn:myNamespace', 'testSimpleList' );
ok($xml = $type->serialize( 'testList', [ 1, 2, 3 ] , $serializer_options ),
"serialize simple list type"
);
SKIP: {
skip_without_test_xml();
is_xml( $xml, '<testList type="tns:testSimpleList">1 2 3</testList>',
"content compare" );
};
$type = $types->find_element( 'urn:myNamespace', 'TestElement' );
ok($xml = $type->serialize( undef, 1 , $serializer_options ),
"serialize simple element");
SKIP: {
skip_without_test_xml();
is_xml( $xml, '<TestElement type="xsd:int">1</TestElement>',
"content compare" );
};
ok( $xml = $types->find_type( 'urn:myNamespace', 'length3')->serialize(
'TestComplex', { size => -13, unit => 'BLA' } ,
$serializer_options
),
"serialize complex type");
SKIP: {
skip_without_test_xml();
is_xml( $xml, q{
<TestComplex type="tns:length3">
<size type="xsd:non-positive-integer">-13</size>
<unit type="xsd:NMTOKEN">BLA</unit>
</TestComplex>},
"content compare" );
};
ok($xml = $types->find_element( 'urn:myNamespace', 'TestElementComplexType')
->serialize(
undef, { size => -13, unit => 'BLA' } , $serializer_options ),
"serialize element with complex type"
);
SKIP: {
skip_without_test_xml();
is_xml( $xml, q{
<TestElementComplexType type="tns:length3">
<size type="xsd:non-positive-integer">-13</size>
<unit type="xsd:NMTOKEN">BLA</unit>
</TestElementComplexType>
},
"content compare" );
};
ok($xml = $types->find_type( 'urn:myNamespace', 'complex')->serialize(
'complexComplex',
{ 'length' => { size => -13, unit => 'BLA' }, 'int' => 1 },
$serializer_options ),
"serialize complex type with complex content"
);
SKIP: {
skip_without_test_xml();
is_xml( $xml, q{
<complexComplex type="tns:complex">
<length type="tns:length3">
<size type="xsd:non-positive-integer">-13</size>
<unit type="xsd:NMTOKEN">BLA</unit>
</length>
<int type="xsd:int">1</int>
</complexComplex>
},
"content compare" );
}
ok($xml = $wsdl->find_message('urn:myNamespace', 'testRequest')
->get_part()->[0]->serialize(
undef,
{ test => { length => { size => -13, unit => 'BLA' } , int => 3 } },
$serializer_options ),
"serialize part"
);
SKIP: {
skip_without_test_xml();
is_xml( $xml, q{
<test type="tns:complex">
<length type="tns:length3">
<size type="xsd:non-positive-integer">-13</size>
<unit type="xsd:NMTOKEN">BLA</unit>
</length>
<int type="xsd:int">3</int>
</test>
},
"content compare")
};
my $opt = {
typelib => $types,
readable => 1,
autotype => 0,
namespace => { 'urn:myNamespace' => 'tns',
'http://www.w3.org/2001/XMLSchema' => 'xsd',
'http://schemas.xmlsoap.org/wsdl/' => 'wsdl',
},
indent => "",
wsdl => $wsdl,
};
# ok $wsdl->explain($opt) =~ m/#optional/m;
sub skip_without_test_xml {
skip("Test::XML not available", 1) if (not $Test::XML::VERSION);
}
sub xml
{
return q{<?xml version="1.0"?>
<definitions name="simpleType"
targetNamespace="urn:myNamespace"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="urn:myNamespace"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
>
<types>
<xsd:schema targetNamespace="urn:myNamespace">
<xsd:complexType name="length3">
<xsd:all>
<xsd:element name="size" type="xsd:non-positive-integer"/>
<xsd:element name="unit" type="xsd:NMTOKEN"/>
</xsd:all>
</xsd:complexType>
<xsd:complexType name="complex">
<xsd:sequence>
<xsd:element name="length" type="tns:length3"/>
<xsd:element name="int" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="TestElement" type="xsd:int"/>
<xsd:element name="TestElementComplexType" type="tns:length3"/>
<xsd:simpleType name="testSimpleType1">
<xsd:restriction base="int">
<xsd:enumeration value="1"/>
<xsd:enumeration value="2"/>
<xsd:enumeration value="3"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="testSimpleList">
<xsd:annotation>
<xsd:documentation>
SimpleType Test
</xsd:documentation>
</xsd:annotation>
<xsd:list itemType="int">
</xsd:list>
</xsd:simpleType>
<xsd:simpleType name="testSimpleUnion">
<xsd:annotation>
<xsd:documentation>
SimpleType Union test
</xsd:documentation>
</xsd:annotation>
<xsd:union memberTypes="int float">
</xsd:union>
</xsd:simpleType>
</xsd:schema>
</types>
<message name="testRequest">
<part name="test" type="tns:complex"/>
</message>
<message name="testResponse">
<part name="test" type="tns:testSimpleType1"/>
</message>
<message name="testRequest2">
<part name="test" type="tns:testSimpleType1"/>
</message>
<message name="testResponse2">
<part name="test" type="tns:testSimpleType1"/>
</message>
<portType name="testPort">
<operation name="test">
<documentation>
Test-Methode
</documentation>
<input message="tns:testRequest"/>
<output message="tns:testResponse"/>
</operation>
<operation name="test2">
<documentation>
Test-Methode
</documentation>
<input message="tns:testRequest2"/>
<output message="tns:testResponse2"/>
</operation>
</portType>
<portType name="testPort2">
<operation name="test">
<documentation>
Test-Methode
</documentation>
<input message="tns:testRequest"/>
<output message="tns:testResponse"/>
</operation>
</portType>
<portType name="testPort3">
<operation name="test">
<documentation>
Test-Methode
</documentation>
<input message="tns:testRequest"/>
<output message="tns:testResponse"/>
</operation>
</portType>
<binding type="tns:testPort" name="testBinding">
<operation name="test">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<soap:operation soapAction="test">
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</soap:operation>
</operation>
</binding>
<binding type="tns:testPort2" name="testBinding2">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="test">
<soap:operation soapAction="test">
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</soap:operation>
</operation>
</binding>
<binding type="tns:testPort3" name="testBinding3">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="test">
<soap:operation soapAction="test">
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</soap:operation>
</operation>
</binding>
<service name="testService">
<port name="testPort" binding="tns:testBinding">
<soap:address location="http://127.0.0.1/testPort" />
</port>
<port name="testPort2" binding="tns:testBinding2">
<soap:address location="http://127.0.0.1/testPort2" />
</port>
</service>
<service name="testService2">
<port name="testPort3" binding="tns:testBinding3">
<soap:address location="http://127.0.0.1/testPort3" />
</port>
</service>
</definitions>
};
}

View File

@@ -1,9 +1,15 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 18; # qw/no_plan/; # TODO: change to tests => N;
use Test::More;
use lib '../lib';
use XML::SAX::ParserFactory;
if (eval "require XML::LibXML") {
plan tests => 18;
}
else {
plan skip_all => "Cannot test without XML::LibXML";
}
eval {
require Test::XML;
@@ -15,12 +21,10 @@ use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/);
my $filter;
ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(
{ base => 'XML::SAX::Base' }
), "Object creation");
my $parser = XML::SAX::ParserFactory->parser(
Handler => $filter
);
my $parser = XML::LibXML->new();
$parser->set_handler( $filter );
$parser->parse_string( xml() );

View File

@@ -1,7 +1,13 @@
use Test::More tests => 11;
use Data::Dumper;
use Test::More;
use lib '../lib';
use XML::LibXML;
if (eval "require XML::LibXML") {
plan tests => 11;
}
else {
plan skip_all => "Cannot test without XML::LibXML";
}
use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/);

View File

@@ -0,0 +1,253 @@
use Test::More tests => 11;
use Data::Dumper;
use lib '../lib';
use_ok(qw/SOAP::WSDL::Expat::WSDLParser/);
my $filter;
my $parser;
ok($parser = SOAP::WSDL::Expat::WSDLParser->new() );
eval { $parser->parse_string( xml() ) };
if ($@)
{
fail("parsing WSDL");
die "Can't test without parsed WSDL";
}
else
{
pass("parsing XML");
}
my $wsdl;
ok( $wsdl = $parser->get_data() , "get object tree");
my $schema = $wsdl->first_types();
my $opt = {
readable => 0,
autotype => 1,
namespace => $wsdl->get_xmlns(),
indent => "\t",
typelib => $schema,
};
is( $schema->find_type( 'myNamespace', 'testSimpleType1' )->serialize(
'test', 1 , $opt ),
q{<test type="tns:testSimpleType1">1</test>} , "serialize simple type");
is( $schema->find_type( 'myNamespace', 'testSimpleList' )->serialize(
'testList', [ 1, 2, 3 ] , $opt),
q{<testList type="tns:testSimpleList">1 2 3</testList>},
"serialize simple list type"
);
is( $schema->find_element( 'myNamespace', 'TestElement' )->serialize(
undef, 1 , $opt),
q{<TestElement type="xsd:int">1</TestElement>}, "Serialize element"
);
$opt->{ readable } = 0;
is( $schema->find_type( 'myNamespace', 'length3')->serialize(
'TestComplex', { size => -13, unit => 'BLA' } ,
$opt ),
q{<TestComplex type="tns:length3" >}
. q{<size type="xsd:non-positive-integer">-13</size>}
. q{<unit type="xsd:NMTOKEN">BLA</unit></TestComplex>}
, "serialize complex type" );
is( $schema->find_element( 'myNamespace', 'TestElementComplexType')->serialize(
undef, { size => -13, unit => 'BLA' } ,
$opt ),
q{<TestElementComplexType type="tns:length3" >}
. q{<size type="xsd:non-positive-integer">-13</size>}
. q{<unit type="xsd:NMTOKEN">BLA</unit></TestElementComplexType>},
"element with complex type"
);
is( $schema->find_type( 'myNamespace', 'complex')->serialize(
'complexComplex',
{ 'length' => { size => -13, unit => 'BLA' }, 'int' => 1 },
$opt ),
q{<complexComplex type="tns:complex" >}
. q{<length type="tns:length3" >}
. q{<size type="xsd:non-positive-integer">-13</size>}
. q{<unit type="xsd:NMTOKEN">BLA</unit></length>}
. q{<int type="xsd:int">1</int></complexComplex>},
"nested complex type"
);
is( $wsdl->find_message('myNamespace', 'testRequest')->first_part()->serialize(
undef, { test => { length => { size => -13, unit => 'BLA' } , int => 3 } },
$opt ),
q{<test type="tns:complex" >}
. q{<length type="tns:length3" >}
. q{<size type="xsd:non-positive-integer">-13</size>}
. q{<unit type="xsd:NMTOKEN">BLA</unit>}
. q{</length><int type="xsd:int">3</int></test>}
, "Message part"
);
exit;
sub xml
{
return q{<?xml version="1.0"?>
<definitions name="simpleType"
targetNamespace="myNamespace"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="myNamespace"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
>
<types>
<xsd:schema targetNamespace="myNamespace">
<xsd:complexType name="length3">
<xsd:sequence>
<xsd:element name="size" type="xsd:non-positive-integer"/>
<xsd:element name="unit" type="xsd:NMTOKEN"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="complex">
<xsd:sequence>
<xsd:element name="length" type="tns:length3"/>
<xsd:element name="int" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="TestElement" type="xsd:int"/>
<xsd:element name="TestElementComplexType" type="tns:length3"/>
<xsd:simpleType name="testSimpleType1">
<xsd:restriction base="int">
<xsd:enumeration value="1"/>
<xsd:enumeration value="2"/>
<xsd:enumeration value="3"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="testSimpleList">
<xsd:annotation>
<xsd:documentation>
SimpleType Test
</xsd:documentation>
</xsd:annotation>
<xsd:list itemType="int">
</xsd:list>
</xsd:simpleType>
<xsd:simpleType name="testSimpleUnion">
<xsd:annotation>
<xsd:documentation>
SimpleType Union test
</xsd:documentation>
</xsd:annotation>
<xsd:union memberTypes="int float">
</xsd:union>
</xsd:simpleType>
</xsd:schema>
</types>
<message name="testRequest">
<part name="test" type="tns:complex"/>
</message>
<message name="testResponse">
<part name="test" type="tns:testSimpleType1"/>
</message>
<message name="testRequest2">
<part name="test" type="tns:testSimpleType1"/>
</message>
<message name="testResponse2">
<part name="test" type="tns:testSimpleType1"/>
</message>
<portType name="testPort">
<operation name="test">
<documentation>
Test-Methode
</documentation>
<input message="testRequest"/>
<output message="testResponse"/>
</operation>
<operation name="test2">
<documentation>
Test-Methode
</documentation>
<input message="testRequest2"/>
<output message="testResponse2"/>
</operation>
</portType>
<portType name="testPort2">
<operation name="test">
<documentation>
Test-Methode
</documentation>
<input message="testRequest"/>
<output message="testResponse"/>
</operation>
</portType>
<portType name="testPort3">
<operation name="test">
<documentation>
Test-Methode
</documentation>
<input message="testRequest"/>
<output message="testResponse"/>
</operation>
</portType>
<binding type="testPort" name="testBinding">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<soap:operation soapAction="test">
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</soap:operation>
</binding>
<binding type="testPort2" name="testBinding2">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<soap:operation soapAction="test">
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</soap:operation>
</binding>
<binding type="testPort3" name="testBinding3">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<soap:operation soapAction="test">
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</soap:operation>
</binding>
<service name="testService">
<port name="testPort" binding="testBinding">
<soap:address location="http://127.0.0.1/testPort" />
</port>
<port name="testPort2" binding="testBinding2">
<soap:address location="http://127.0.0.1/testPort2" />
</port>
<port name="testPort3" binding="testBinding3">
<soap:address location="http://127.0.0.1/testPort3" />
</port>
</service>
</definitions>
};
}

398
t/004_parse_wsdl.t Normal file
View File

@@ -0,0 +1,398 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 5;
use lib '../lib';
eval {
require Test::XML;
import Test::XML;
};
use_ok(qw/SOAP::WSDL::Expat::WSDLParser/);
my $parser;
ok($parser = SOAP::WSDL::Expat::WSDLParser->new(), "Object creation");
eval { $parser->parse_string( xml() ) };
if ($@)
{
fail("parsing WSDL");
die "Can't test without parsed WSDL: $@";
}
else
{
pass("parsing XML");
}
my $wsdl;
ok( $wsdl = $parser->get_data() , "get object tree");
my $schema = $wsdl->get_types()->[0]->get_schema()->[0] || die "No schema !";
my $opt = {
typelib => $wsdl->first_types,
readable => 1,
autotype => 0,
namespace => { 'http://www.example.org/MessageGateway2/' => 'tns',
'http://www.w3.org/2001/XMLSchema' => 'xsd',
'http://schemas.xmlsoap.org/wsdl/' => 'wsdl',
},
indent => "",
};
my $data = { EnqueueMessage => {
MMessage => {
MRecipientURI => 'anyURI',
MSenderAddress => 'a string',
MMessageContent => 'a string',
MSubject => 'a string',
MDeliveryReportRecipientURI => 'anyURI',
MKeepalive => {
MKeepaliveTimeout => 1234567,
MKeepaliveErrorPolicy => ' ( suppress | report ) ',
}
}
}
};
SKIP: { skip_without_test_xml();
is_xml( $wsdl->find_message(
"http://www.example.org/MessageGateway2/" ,'EnqueueMessageRequest'
)->first_part()->serialize( 'test', $data, $opt ),
xml_message()
, "Serialized message part"
);
}
sub skip_without_test_xml {
skip("Test::XML not available", 1) if (not $Test::XML::VERSION);
}
sub xml_message {
return
q{<EnqueueMessage xmlns="http://www.example.org/MessageGateway2/">
<MMessage>
<MRecipientURI>anyURI</MRecipientURI>
<MSenderAddress>a string</MSenderAddress>
<MMessageContent>a string</MMessageContent>
<MSubject>a string</MSubject>
<MDeliveryReportRecipientURI>anyURI</MDeliveryReportRecipientURI>
<MKeepalive>
<MKeepaliveTimeout>1234567</MKeepaliveTimeout>
<MKeepaliveErrorPolicy> ( suppress | report ) </MKeepaliveErrorPolicy>
</MKeepalive>
</MMessage>
</EnqueueMessage>
};
}
sub xml {
return q{<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="MessageGateway"
targetNamespace="http://www.example.org/MessageGateway2/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://www.example.org/MessageGateway2/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/MessageGateway2/">
<xsd:element name="EnqueueMessage" type="tns:TEnqueueMessage"
xmlns:tns="http://www.example.org/MessageGateway2/">
<xsd:annotation>
<xsd:documentation>Enqueue message request element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="TMessage">
<xsd:annotation>
<xsd:documentation>
A type containing all elements of a message to enqueue.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MRecipientURI" type="xsd:anyURI" minOccurs="1"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The recipient in URI notaitions. Valid URI schemas are: mailto:, sms:,
phone:. Not all URI schemas need to be implemented at the current
implementation stage.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MSenderAddress" type="xsd:string" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
E-Mail sender address. Ignored for all but mailto: recipient URIs.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MMessageContent" type="xsd:string" minOccurs="1"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>Message Content.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MSubject" type="xsd:string" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Message Subject. Ignored for all but mailto: URIs
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MDeliveryReportRecipientURI" type="xsd:anyURI" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
URI to send a delivery report to. May be of one of the following schemes:
mailto:, http:, https:. Reports to mailto: URIs are sent as plaintext,
reports to http(s) URIs are sent as SOAP requests following the
MessageGatewayClient service definition.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MKeepalive" type="tns:TKeepalive" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Container for keepalive information. May be missing.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepalive">
<xsd:annotation>
<xsd:documentation>Type containing keeplive information.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MKeepaliveTimeout" type="xsd:double">
<xsd:annotation>
<xsd:documentation>
Keepalive timeout. The keepalive timeout spezifies how long the sending of
a message will be delayed waiting for keepalive updates. If a keepalive
update is received during this period, the timeout will be reset. If not,
the message will be sent after the timeout has expired.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MKeepaliveErrorPolicy" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Policy to comply to in case of system errors. Valid values are "suppress"
and "report". If the policy is set to "suppress", keepalive messages will
not be sent to their recipients in case of partial system failure, even if
the keepalive has expired. This may result in "false negatives", i.e.
messages may not be sent, even though their keepalive has expired. If the
value is "report", keepalive messages will be sent from any cluster node.
This may result in "false positive" alerts.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="suppress"></xsd:enumeration>
<xsd:enumeration value="report"></xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TMessageID">
<xsd:annotation>
<xsd:documentation>Type containing a message ID.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessageID" type="xsd:string" minOccurs="1" maxOccurs="1"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepliveMessage">
<xsd:annotation>
<xsd:documentation>
Type containing all elements of a keppalive update / remove request.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessageID" type="xsd:string" minOccurs="1" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The ID for the message to update / remove
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MAction" minOccurs="1" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The action to perform. Valid values are: "remove", "update". On "remove",
the message with the ID specified will be removed from the queue, thus it
will never be sent, even if it's timeout expires. On "update" the
keepalive timeout of the corresponding message will be reset.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="remove"></xsd:enumeration>
<xsd:enumeration value="update"></xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="KeepaliveMessage" type="tns:TKeepaliveMessageRequest">
<xsd:annotation>
<xsd:documentation>Keepalive message request element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="KeepaliveMessageResponse" type="tns:TMessageID">
<xsd:annotation>
<xsd:documentation>Response element for a keepalive request</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="EnqueueMessageResponse" type="tns:TMessageID">
<xsd:annotation>
<xsd:documentation>Enqueue message response element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="TEnqueueMessage">
<xsd:annotation>
<xsd:documentation>
A complex type containing one element: The message to enqueue.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessage" type="tns:TMessage">
<xsd:annotation>
<xsd:documentation>
Element containing a message to enqueue.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepaliveMessageRequest">
<xsd:annotation>
<xsd:documentation>
A complex type containing one element: The keepalive message to process.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MKeepaliveMessage" type="tns:TKeepliveMessage">
<xsd:annotation>
<xsd:documentation>
Element containing a keepalive message to process.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="EnqueueMessageRequest">
<wsdl:part name="parameters" element="tns:EnqueueMessage">
<wsdl:documentation>inputparameters for EnqueueMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="EnqueueMessageResponse">
<wsdl:part name="parameters" element="tns:EnqueueMessageResponse">
<wsdl:documentation>outputparameters for EnqueueMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="KeepaliveMessageRequest">
<wsdl:part name="parameters" element="tns:KeepaliveMessage">
<wsdl:documentation>input parameters for KeepaliveMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="KeepaliveMessageResponse">
<wsdl:part name="parameters" element="tns:KeepaliveMessageResponse">
<wsdl:documentation>output parameters for KeepaliveMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:portType name="MGWPortType">
<wsdl:documentation>
generic port type for all methods required for sending messages over the mosaic
message gatewa
</wsdl:documentation>
<wsdl:operation name="EnqueueMessage">
<wsdl:documentation>
This method is used to enqueue a normal (immediate send) or a delayed message with
keepalive functionality.
</wsdl:documentation>
<wsdl:input message="tns:EnqueueMessageRequest"></wsdl:input>
<wsdl:output message="tns:EnqueueMessageResponse"></wsdl:output>
</wsdl:operation>
<wsdl:operation name="KeepaliveMessage">
<wsdl:documentation>
This method is used to update or remove a
keepalive message.
</wsdl:documentation>
<wsdl:input message="tns:KeepaliveMessageRequest"></wsdl:input>
<wsdl:output message="tns:KeepaliveMessageResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MGWBinding" type="tns:MGWPortType">
<wsdl:documentation>Generic binding for all (SOAP) port</wsdl:documentation>
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="EnqueueMessage">
<soap:operation soapAction="http://www.example.org/MessageGateway2/EnqueueMessage" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="KeepaliveMessage">
<soap:operation
soapAction="http://www.example.org/MessageGateway2/KeepaliveMessage" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MessageGateway">
<wsdl:documentation>
Web Service for sending messages over the mosaic message gatewa
</wsdl:documentation>
<wsdl:port name="HTTPPort" binding="tns:MGWBinding">
<wsdl:documentation>HTTP(S) port for the mosaic message gatewa</wsdl:documentation>
<soap:address location="https://www.example.org/MessageGateway/" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>};
}

View File

@@ -1,11 +1,15 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 5;
use Test::More;
use lib '../lib';
use XML::SAX::ParserFactory;
use diagnostics;
if (eval "require XML::LibXML") {
plan tests => 5;
}
else {
plan skip_all => "Cannot test without XML::LibXML";
}
eval {
require Test::XML;
@@ -18,7 +22,6 @@ my $filter;
ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation");
use XML::LibXML;
my $parser = XML::LibXML->new();
$parser->set_handler( $filter );

249
t/005_parse_contributed.t Normal file
View File

@@ -0,0 +1,249 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More qw/no_plan/; # TODO: change to tests => N;
use Data::Dumper;
use lib '../lib';
use diagnostics;
use_ok(qw/SOAP::WSDL::Expat::WSDLParser/);
my $parser;
ok($parser = SOAP::WSDL::Expat::WSDLParser->new(), "Object creation");
eval { $parser->parse_string( xml() ) };
if ($@)
{
fail("parsing WSDL");
die "Can't test without parsed WSDL: $@";
}
else
{
pass("parsing XML");
}
my $wsdl;
ok( $wsdl = $parser->get_data() , "get object tree");
my $opt = {
namespace => $wsdl->get_xmlns(),
style => 'perl',
wsdl => $wsdl,
readable => 1,
};
my $txt;
ok( $txt = $wsdl->explain( $opt ) , "explain WSDL" );
# print $txt;
sub xml {
return q{<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://example.com/soap/services/ETest/impl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="http://example.com/soap/services/ETest/impl"
xmlns:intf="http://example.com/soap/services/ETest"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tns1="urn:ETest"
xmlns:tns2="urn:acquisition"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<schema targetNamespace="urn:ETest" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
<complexType name="CreationBaseData">
<sequence>
<element name="createdBy" nillable="true" type="xsd:long" />
<element name="creationDate" nillable="true" type="xsd:dateTime" />
<element name="updateDateCenter" nillable="true" type="xsd:dateTime" />
<element name="updateDateLocal" nillable="true" type="xsd:dateTime" />
<element name="updatedBy" nillable="true" type="xsd:long" />
</sequence>
</complexType>
<complexType name="CreationData">
<complexContent>
<extension base="tns1:CreationBaseData">
<sequence>
<element name="creatorFullName" nillable="true" type="xsd:string" />
<element name="modifierFullName" nillable="true" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType abstract="true" name="EProductData">
<sequence>
<element name="EStatus" nillable="true" type="xsd:string" />
<element name="EStatusUpdatedate" nillable="true" type="xsd:dateTime" />
<element name="SFXID" nillable="true" type="xsd:string" />
<element name="activationFromDate" nillable="true" type="xsd:dateTime" />
<element name="activationToDate" nillable="true" type="xsd:dateTime" />
<element name="activityStatusDateFrom" nillable="true" type="xsd:dateTime" />
<element name="activityStatusDateTo" nillable="true" type="xsd:dateTime" />
<element name="canEditSFXID" type="xsd:boolean" />
<element name="concurrentNumberOfUsers" nillable="true" type="xsd:int" />
<element name="creationData" nillable="true" type="tns1:CreationData" />
<element name="deleteable" type="xsd:boolean" />
<element name="ETestCode" nillable="true" type="xsd:string" />
<element name="id" nillable="true" type="xsd:long" />
<element name="instanceCode" nillable="true" type="xsd:string" />
<element name="mainContact" nillable="true" type="xsd:string" />
<element name="metaLibID" nillable="true" type="xsd:string" />
<element name="otherID" nillable="true" type="xsd:string" />
<element name="otherSource" nillable="true" type="xsd:string" />
<element name="privateNote" nillable="true" type="xsd:string" />
<element name="procurementStatus" nillable="true" type="xsd:string" />
<element name="procurementStatusUpdateDate" nillable="true" type="xsd:dateTime" />
<element name="procurementStatusUpdatedate" nillable="true" type="xsd:dateTime" />
<element name="sourceInstanceCode" nillable="true" type="xsd:string" />
<element name="sponseringLibraryCode" nillable="true" type="xsd:string" />
<element name="sponseringLibraryName" nillable="true" type="xsd:string" />
<element name="updateTarget" nillable="true" type="xsd:string" />
<element name="workExpressionCode" nillable="true" type="xsd:string" />
</sequence>
</complexType>
<complexType name="EProductInformation">
<sequence>
<element name="acquisitions" nillable="true"
type="impl:ArrayOf_tns2_AcquisitionData" />
<element name="data" nillable="true" type="tns1:EProductData" />
</sequence>
</complexType>
</schema>
<schema targetNamespace="urn:acquisition" xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
<complexType name="AcquisitionCommonData">
<sequence>
<element name="budgets" nillable="true" type="xsd:string" />
<element name="campusCode" nillable="true" type="xsd:string" />
<element name="concurrentUsersNote" nillable="true" type="xsd:string" />
<element name="creationData" nillable="true" type="tns1:CreationData" />
<element name="id" nillable="true" type="xsd:long" />
<element name="instituteCode" nillable="true" type="xsd:string" />
</sequence>
</complexType>
<complexType name="AcquisitionData">
<sequence>
<element name="ILSSubscriptionNo" nillable="true" type="xsd:string" />
<element name="acquisitionCode" nillable="true" type="xsd:string" />
<element name="acquisitionCommonData" nillable="true"
type="tns2:AcquisitionCommonData" />
<element name="acquisitionMethod" nillable="true" type="xsd:string" />
<element name="acquisitionNumber" nillable="true" type="xsd:string" />
<element name="acquisitionStatus" nillable="true" type="xsd:string" />
<element name="acquisitionStatusDate" nillable="true" type="xsd:dateTime" />
<element name="advanceNoticeDate" nillable="true" type="xsd:dateTime" />
<element name="autoRenewal" nillable="true" type="xsd:boolean" />
<element name="consortialAgreement" type="xsd:boolean" />
<element name="discountOnPrice" nillable="true" type="xsd:int" />
<element name="id" nillable="true" type="xsd:long" />
<element name="instanceCode" nillable="true" type="xsd:string" />
<element name="materialType" nillable="true" type="xsd:string" />
<element name="noteForILS" nillable="true" type="xsd:string" />
<element name="noteForVendor" nillable="true" type="xsd:string" />
<element name="noticePeriodCode" nillable="true" type="xsd:string" />
<element name="numberOfCopies" nillable="true" type="xsd:int" />
<element name="orderDate" nillable="true" type="xsd:dateTime" />
<element name="orderForm" nillable="true" type="xsd:string" />
<element name="orderSendMethod" nillable="true" type="xsd:string" />
<element name="pooledConcurrentUsers" nillable="true" type="xsd:int" />
<element name="price" nillable="true" type="xsd:double" />
<element name="pricingCap" nillable="true" type="xsd:int" />
<element name="pricingCapFrom" nillable="true" type="xsd:dateTime" />
<element name="pricingCapTo" nillable="true" type="xsd:dateTime" />
<element name="pricingModel" nillable="true" type="xsd:string" />
<element name="printCancellationNote" nillable="true" type="xsd:string" />
<element name="printCancellationRestriction" type="xsd:boolean" />
<element name="printPurchaseOrderNo" nillable="true" type="xsd:string" />
<element name="purchaseOrderNo" nillable="true" type="xsd:string" />
<element name="renewallOrCancellationDate" nillable="true" type="xsd:dateTime" />
<element name="renewallOrCancellationDescisionNote" nillable="true"
type="xsd:string" />
<element name="renewallOrCancellationNoteForILS" nillable="true"
type="xsd:string" />
<element name="renewallOrCancellationNoteForVendor" nillable="true"
type="xsd:string" />
<element name="subscriptionNotification" nillable="true" type="xsd:int" />
<element name="subscriptionPeriodCode" nillable="true" type="xsd:string" />
<element name="subscriptionType" nillable="true" type="xsd:string" />
<element name="subscriptionTypeNote" nillable="true" type="xsd:string" />
<element name="vendorAdvancedNotice" nillable="true" type="xsd:int" />
<element name="vendorAdvancedNoticeVal" nillable="true" type="xsd:string" />
<element name="vendorCode" nillable="true" type="xsd:string" />
<element name="vendorName" nillable="true" type="xsd:string" />
<element name="vendorSubscriptionCode" nillable="true" type="xsd:string" />
</sequence>
</complexType>
</schema>
<schema targetNamespace="http://example.com/soap/services/ETest/impl"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
<complexType name="ArrayOf_tns2_AcquisitionData">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType" wsdl:arrayType="tns2:AcquisitionData[]" />
</restriction>
</complexContent>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="getETestResponse">
<wsdl:part name="getETestReturn" type="tns1:EProductInformation" />
</wsdl:message>
<wsdl:message name="getFixedETestResponse">
<wsdl:part name="getFixedETestReturn" type="tns1:EProductInformation" />
</wsdl:message>
<wsdl:message name="getFixedETestRequest"></wsdl:message>
<wsdl:message name="getETestRequest">
<wsdl:part name="indexName" type="xsd:string" />
<wsdl:part name="indexValue" type="xsd:string" />
<wsdl:part name="withStatus" type="xsd:string" />
</wsdl:message>
<wsdl:portType name="ETestWeb">
<wsdl:operation name="getETest" parameterOrder="indexName indexValue withStatus">
<wsdl:input message="impl:getETestRequest" name="getETestRequest" />
<wsdl:output message="impl:getETestResponse" name="getETestResponse" />
</wsdl:operation>
<wsdl:operation name="getFixedETest">
<wsdl:input message="impl:getFixedETestRequest" name="getFixedETestRequest" />
<wsdl:output message="impl:getFixedETestResponse"
name="getFixedETestResponse" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ETestSoapBinding" type="impl:ETestWeb">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="getETest">
<wsdlsoap:operation soapAction="" />
<wsdl:input name="getETestRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://example.com/soap/services/ETest" use="encoded" />
</wsdl:input>
<wsdl:output name="getETestResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://example.com/soap/services/ETest" use="encoded" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getFixedETest">
<wsdlsoap:operation soapAction="" />
<wsdl:input name="getFixedETestRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://example.com/soap/services/ETest" use="encoded" />
</wsdl:input>
<wsdl:output name="getFixedETestResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://example.com/soap/services/ETest" use="encoded" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ETestWebService">
<wsdl:port binding="impl:ETestSoapBinding" name="ETest">
<wsdlsoap:address location="http://example.com/soap/services/ETest" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
};
}

View File

@@ -1,10 +1,15 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More qw/no_plan/; # TODO: change to tests => N;
use Data::Dumper;
use Test::More; # TODO: change to tests => N;
use lib '../lib';
use XML::LibXML;
if (eval "require XML::LibXML") {
plan tests => 5;
}
else {
plan skip_all => "Cannot test without XML::LibXML";
}
use diagnostics;

View File

@@ -1,10 +1,8 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Pod::Simple::Text;
use Test::More qw/no_plan/; # TODO: change to tests => N;
use lib '../lib';
use XML::SAX::ParserFactory;
eval {
require Test::XML;
@@ -31,11 +29,17 @@ ok( $soap->no_dispatch( 1 ) , "Set no_dispatch" );
ok( $soap->explain() );
my $pod = Pod::Simple::Text->new();
my $output;
$pod->output_string( \$output );
$pod->parse_string_document( $soap->explain() );
SKIP: {
if (not eval "require Pod::Simple::Text") {
skip "cannot test parsing pod without Pod::Test::Simple", 1;
};
my $pod = Pod::Simple::Text->new();
my $output;
$pod->output_string( \$output );
ok $pod->parse_string_document( $soap->explain() ), 'parse explain pod';
}
# print $output;
SKIP: {
@@ -60,6 +64,3 @@ sub skip_without_test_xml {
my $number = shift || 1;
skip("Test::XML not available", $number) if (not $Test::XML::VERSION);
}
__END__

View File

@@ -10,7 +10,7 @@ eval {
import Test::XML;
};
use_ok qw/SOAP::WSDL::Envelope/;
use_ok qw/SOAP::WSDL::Serializer::SOAP11/;
my $opt = {
readable => 1,
@@ -18,7 +18,7 @@ my $opt = {
},
};
my $xml;
ok( $xml = SOAP::WSDL::Envelope->serialize(
ok( $xml = SOAP::WSDL::Serializer::SOAP11->serialize(
undef, undef, $opt
),
"serialize empty envelope"

View File

@@ -1,13 +1,14 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 5;
use lib 't/lib';
use lib '../lib';
use lib 'lib';
use XML::Simple;
use SOAP::WSDL::SAX::WSDLHandler;
use Cwd;
use XML::LibXML::SAX;
use_ok(qw/SOAP::WSDL::SAX::MessageHandler/);
use SOAP::WSDL;
@@ -15,22 +16,18 @@ use SOAP::WSDL::XSD::Typelib::Builtin;
my $path = cwd;
$path =~s|\/t\/?$||; # allow running from t/ and above (Build test)
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
my $filter;
ok($filter = SOAP::WSDL::SAX::MessageHandler->new( {
my $parser;
ok $parser = SOAP::WSDL::Expat::MessageParser->new({
class_resolver => FakeResolver->new(),
} ), "Object creation");
}), "Object creation";
my $parser = XML::LibXML->new();
$parser->set_handler( $filter );
# TODO factor out into bool test
$parser->parse_string( xml() );
$parser->parse( xml() );
# print $filter->get_data();
# print $filter->get_data()->get_MMessage()->_DUMP();
if($filter->get_data()->get_MMessage()->get_MDeliveryReportRecipientURI()) {
if($parser->get_data()->get_MMessage()->get_MDeliveryReportRecipientURI()) {
pass "bool context overloading";
}
else
@@ -38,6 +35,8 @@ else
fail "bool context overloading"
}
# TODO factor out into different test
my $soap = SOAP::WSDL->new(
readable => 1,
wsdl => 'file:///' . $path .'/t/acceptance/wsdl/006_sax_client.wsdl',
@@ -86,6 +85,4 @@ BEGIN {
: warn "no class found for $name";
};
};
};

View File

@@ -1,11 +1,15 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 16;
use Test::More;
use lib '../lib';
use XML::SAX::ParserFactory;
use diagnostics;
if (eval "require XML::LibXML") {
plan tests => 16;
}
else {
plan skip_all => "Cannot test without XML::LibXML";
}
eval {
require Test::XML;
@@ -18,7 +22,6 @@ my $filter;
ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation");
use XML::LibXML;
my $parser = XML::LibXML->new();
$parser->set_handler( $filter );
@@ -56,7 +59,8 @@ for my $element (@{ $wsdl->first_types()->get_schema()->[1]->get_type() } ) {
next;
}
my $name = 'MessageGateway::' . $element->get_name();
ok eval $output, $name;
ok eval $output, $name
or die $@, $output;
ok $name->can('serialize'), "$name\->can('serialize')";
}

View File

@@ -3,25 +3,16 @@ use strict;
use warnings;
use Test::More tests => 5;
use lib '../lib';
use XML::SAX::ParserFactory;
use diagnostics;
eval {
require Test::XML;
import Test::XML;
};
use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/);
use_ok(qw/SOAP::WSDL::Expat::WSDLParser/);
my $filter;
ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation");
use XML::LibXML;
my $parser = XML::LibXML->new();
$parser->set_handler( $filter );
my $parser;
ok($parser = SOAP::WSDL::Expat::WSDLParser->new(), "Object creation");
eval { $parser->parse_string( xml() ) };
if ($@)
{
@@ -34,7 +25,7 @@ else
}
my $wsdl;
ok( $wsdl = $filter->get_data() , "get object tree");
ok( $wsdl = $parser->get_data() , "get object tree");
ok $wsdl->to_typemap( { prefix => 'CP::EAI::Typelib::' } ), 'typemap';
exit;

412
t/017_generator_expat.t Normal file
View File

@@ -0,0 +1,412 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 19;
use lib '../lib';
use SOAP::WSDL::Expat::WSDLParser;
use SOAP::WSDL::Expat::MessageParser;
use File::Path;
use File::Basename;
my $path = dirname __FILE__;
my $wsdl;
ok( $wsdl = SOAP::WSDL::Expat::WSDLParser->new()
->parse_string( xml() ) , "get object tree");
$wsdl->create({
base_path => "$path/testlib",
typemap_prefix => "Test::Typemap::",
type_prefix => "Test::Type::",
element_prefix => "Test::Element::",
interface_prefix => "Test::Interface::",
});
eval "use lib '$path/testlib'";
use_ok qw(Test::Element::EnqueueMessage);
use_ok qw(Test::Type::TMessage);
use_ok qw(Test::Typemap::MessageGateway);
my $data = {
MMessage => {
MRecipientURI => 'anyURI',
MSenderAddress => 'a string',
MMessageContent => 'a string',
MSubject => 'a string',
MDeliveryReportRecipientURI => 'anyURI',
MKeepalive => {
MKeepaliveTimeout => 1234567,
MKeepaliveErrorPolicy => ' ( suppress | report ) ',
}
}
};
ok Test::Element::EnqueueMessage->new( $data ) , '(generated) object constructor';
my $message_parser = SOAP::WSDL::Expat::MessageParser->new({
class_resolver => 'Test::Typemap::MessageGateway'
});
eval { $message_parser->parse_string( xml_message2() ) };
ok ( !$@, 'parse XML message');
TODO: {
local $TODO = 'support embedded atomic simpleType/complexType definitions';
eval { $message_parser->parse_string( xml_message() ) };
ok ( !$@, 'parse XML message using atomic type definitions');
};
SKIP: {
eval "require Test::Pod";
skip 'Cannot test generated POD without Test::POD' , 6 if $@;
foreach my $module (Test::Pod::all_pod_files( "$path/testlib")) {
Test::Pod::pod_file_ok( $module )
}
}
# cleanup
rmtree "$path/testlib";
# print $wsdl->explain();
sub xml_message {
return
q{<EnqueueMessage xmlns="http://www.example.org/MessageGateway2/">
<MMessage>
<MRecipientURI>anyURI</MRecipientURI>
<MSenderAddress>a string</MSenderAddress>
<MMessageContent>a string</MMessageContent>
<MSubject>a string</MSubject>
<MDeliveryReportRecipientURI>anyURI</MDeliveryReportRecipientURI>
<MKeepalive>
<MKeepaliveTimeout>1234567</MKeepaliveTimeout>
<MKeepaliveErrorPolicy> ( suppress | report ) </MKeepaliveErrorPolicy>
</MKeepalive>
</MMessage>
</EnqueueMessage>
};
}
sub xml_message2 {
return
q{<EnqueueMessage xmlns="http://www.example.org/MessageGateway2/">
<MMessage>
<MRecipientURI>anyURI</MRecipientURI>
<MSenderAddress>a string</MSenderAddress>
<MMessageContent>a string</MMessageContent>
<MSubject>a string</MSubject>
<MDeliveryReportRecipientURI>anyURI</MDeliveryReportRecipientURI>
</MMessage>
</EnqueueMessage>
};
}
sub xml {
return q{<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="MessageGateway"
targetNamespace="http://www.example.org/MessageGateway2/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://www.example.org/MessageGateway2/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/MessageGateway2/">
<xsd:element name="EnqueueMessage" type="tns:TEnqueueMessage"
xmlns:tns="http://www.example.org/MessageGateway2/">
<xsd:annotation>
<xsd:documentation>Enqueue message request element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="TMessage">
<xsd:annotation>
<xsd:documentation>
A type containing all elements of a message to enqueue.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MRecipientURI" type="xsd:anyURI" minOccurs="1"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The recipient in URI notaitions. Valid URI schemas are: mailto:, sms:,
phone:. Not all URI schemas need to be implemented at the current
implementation stage.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MSenderAddress" type="xsd:string" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
E-Mail sender address. Ignored for all but mailto: recipient URIs.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MMessageContent" type="xsd:string" minOccurs="1"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>Message Content.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MSubject" type="xsd:string" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Message Subject. Ignored for all but mailto: URIs
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MDeliveryReportRecipientURI" type="xsd:anyURI" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
URI to send a delivery report to. May be of one of the following schemes:
mailto:, http:, https:. Reports to mailto: URIs are sent as plaintext,
reports to http(s) URIs are sent as SOAP requests following the
MessageGatewayClient service definition.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MKeepalive" type="tns:TKeepalive" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Container for keepalive information. May be missing.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepalive">
<xsd:annotation>
<xsd:documentation>Type containing keeplive information.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MKeepaliveTimeout" type="xsd:double">
<xsd:annotation>
<xsd:documentation>
Keepalive timeout. The keepalive timeout spezifies how long the sending of
a message will be delayed waiting for keepalive updates. If a keepalive
update is received during this period, the timeout will be reset. If not,
the message will be sent after the timeout has expired.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MKeepaliveErrorPolicy" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Policy to comply to in case of system errors. Valid values are "suppress"
and "report". If the policy is set to "suppress", keepalive messages will
not be sent to their recipients in case of partial system failure, even if
the keepalive has expired. This may result in "false negatives", i.e.
messages may not be sent, even though their keepalive has expired. If the
value is "report", keepalive messages will be sent from any cluster node.
This may result in "false positive" alerts.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="suppress"></xsd:enumeration>
<xsd:enumeration value="report"></xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TMessageID">
<xsd:annotation>
<xsd:documentation>Type containing a message ID.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessageID" type="xsd:string" minOccurs="1" maxOccurs="1"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepliveMessage">
<xsd:annotation>
<xsd:documentation>
Type containing all elements of a keppalive update / remove request.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessageID" type="xsd:string" minOccurs="1" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The ID for the message to update / remove
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MAction" minOccurs="1" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The action to perform. Valid values are: "remove", "update". On "remove",
the message with the ID specified will be removed from the queue, thus it
will never be sent, even if it's timeout expires. On "update" the
keepalive timeout of the corresponding message will be reset.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="remove"></xsd:enumeration>
<xsd:enumeration value="update"></xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="KeepaliveMessage" type="tns:TKeepaliveMessageRequest">
<xsd:annotation>
<xsd:documentation>Keepalive message request element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="KeepaliveMessageResponse" type="tns:TMessageID">
<xsd:annotation>
<xsd:documentation>Response element for a keepalive request</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="EnqueueMessageResponse" type="tns:TMessageID">
<xsd:annotation>
<xsd:documentation>Enqueue message response element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="TEnqueueMessage">
<xsd:annotation>
<xsd:documentation>
A complex type containing one element: The message to enqueue.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessage" type="tns:TMessage">
<xsd:annotation>
<xsd:documentation>
Element containing a message to enqueue.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepaliveMessageRequest">
<xsd:annotation>
<xsd:documentation>
A complex type containing one element: The keepalive message to process.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MKeepaliveMessage" type="tns:TKeepliveMessage">
<xsd:annotation>
<xsd:documentation>
Element containing a keepalive message to process.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="EnqueueMessageRequest">
<wsdl:part name="parameters" element="tns:EnqueueMessage">
<wsdl:documentation>inputparameters for EnqueueMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="EnqueueMessageResponse">
<wsdl:part name="parameters" element="tns:EnqueueMessageResponse">
<wsdl:documentation>outputparameters for EnqueueMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="KeepaliveMessageRequest">
<wsdl:part name="parameters" element="tns:KeepaliveMessage">
<wsdl:documentation>input parameters for KeepaliveMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="KeepaliveMessageResponse">
<wsdl:part name="parameters" element="tns:KeepaliveMessageResponse">
<wsdl:documentation>output parameters for KeepaliveMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:portType name="MGWPortType">
<wsdl:documentation>
generic port type for all methods required for sending messages over the mosaic
message gatewa
</wsdl:documentation>
<wsdl:operation name="EnqueueMessage">
<wsdl:documentation>
This method is used to enqueue a normal (immediate send) or a delayed message with
keepalive functionality.
</wsdl:documentation>
<wsdl:input message="tns:EnqueueMessageRequest"></wsdl:input>
<wsdl:output message="tns:EnqueueMessageResponse"></wsdl:output>
</wsdl:operation>
<wsdl:operation name="KeepaliveMessage">
<wsdl:documentation>
This method is used to update or remove a
keepalive message.
</wsdl:documentation>
<wsdl:input message="tns:KeepaliveMessageRequest"></wsdl:input>
<wsdl:output message="tns:KeepaliveMessageResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MGWBinding" type="tns:MGWPortType">
<wsdl:documentation>Generic binding for all (SOAP) port</wsdl:documentation>
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="EnqueueMessage">
<soap:operation soapAction="http://www.example.org/MessageGateway2/EnqueueMessage" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="KeepaliveMessage">
<soap:operation
soapAction="http://www.example.org/MessageGateway2/KeepaliveMessage" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MessageGateway">
<wsdl:documentation>
Web Service for sending messages over the message gatewa
</wsdl:documentation>
<wsdl:port name="HTTPPort" binding="tns:MGWBinding">
<wsdl:documentation>HTTP(S) port for the message gateway</wsdl:documentation>
<soap:address location="https://www.example.org/MessageGateway/" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>};
}

View File

@@ -1,13 +1,19 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 18;
use Test::More;
use lib '../lib';
use XML::LibXML;
use SOAP::WSDL::SAX::WSDLHandler;
use SOAP::WSDL::SAX::MessageHandler;
use File::Path;
use File::Basename;
if (eval "require XML::LibXML") {
plan tests => 18;
}
else {
plan skip_all => "Cannot test without XML::LibXML";
}
my $path = dirname __FILE__;

49
t/018_generator_expat.t Normal file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 12;
use lib '../lib';
use SOAP::WSDL::Expat::WSDLParser;
use File::Find;
use File::Basename;
my $path = dirname __FILE__;
my $wsdl;
my $parser = SOAP::WSDL::Expat::WSDLParser->new();
ok( $wsdl = $parser->parse_file( "$path/../example/wsdl/globalweather.xml" ) );
$wsdl->create({
base_path => "$path/testlib",
typemap_prefix => "Test::Typemap::",
type_prefix => "Test::Type::",
element_prefix => "Test::Element::",
interface_prefix => "Test::Interface::",
});
# Check for created files (and dirs) - value is the number of entries
# with this (local) name
my %expected = (
'GetCitiesByCountry.pm' => 1,
'GetCitiesByCountryResponse.pm' => 1,
'GetWeather.pm' => 1,
'GetWeatherResponse.pm' => 1,
'string.pm' => 1,
'Element' => 1,
'Interface' => 1,
'GlobalWeather.pm' => 2,
'Typemap' => 1,
'Test' => 1,
);
File::Find::finddepth(
sub {
return if $_ eq '.';
ok $expected{ $_ }--, $_;
unlink $_ if -f $_;
rmdir $_ if -d $_;
},
"$path/testlib",
);
rmdir "$path/testlib";

View File

@@ -1,13 +1,19 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 1;
use Test::More;
use lib '../lib';
use XML::LibXML;
use SOAP::WSDL::SAX::WSDLHandler;
use SOAP::WSDL::SAX::MessageHandler;
use File::Path;
use File::Basename;
if (eval "require XML::LibXML") {
plan tests => 1;
}
else {
plan skip_all => "Cannot test without XML::LibXML";
}
my $path = dirname __FILE__;

View File

@@ -0,0 +1,58 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More tests => 10;
use File::Path;
use File::Basename;
use lib '../lib';
use_ok(qw/SOAP::WSDL::Expat::WSDLParser/);
my $path = dirname __FILE__;
my $parser = SOAP::WSDL::Expat::WSDLParser->new();
eval { $parser->parsefile( "$path/acceptance/wsdl/03_complexType-element-ref.wsdl" ) };
if ($@)
{
fail("parsing WSDL");
die "Can't test without parsed WSDL: $@";
}
else
{
pass("parsing XML");
}
my $definitions = $parser->get_data();
my $type = $definitions->first_types()->find_type('urn:Test', 'testComplexTypeRef');
my $element = $definitions->first_types()->find_element('urn:Test', 'TestElement');
my $output = '';
ok $element->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output })
, 'generate element code';
ok eval $output, 'eval generated code';
$output = '';
ok $type->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output })
, 'generate complexType code with element ref=""';
ok eval $output, 'eval generated code';
my $obj = Test::testComplexTypeRef->new({
TestRef => 'test_ref',
Test2 => 'test2',
});
is $obj, '<TestRef >test_ref</TestRef><Test2 >test2</Test2 >', 'serialization';
$element = $definitions->first_types()->find_element('urn:Test', 'TestRef');
$output = '';
ok $element->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output })
, 'generate top level element ref code';
ok eval $output, 'eval generated code' . $@;
$obj = Test::TestRef->new({ value => 'test_ref' });
is $obj, '<TestRef xmlns="urn:Test" >test_ref</TestRef>', 'serialization';

View File

@@ -0,0 +1,76 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use Test::More;
use File::Path;
use File::Basename;
use lib '../lib';
if (eval "require XML::LibXML") {
plan tests => 11;
}
else {
plan skip_all => "Cannot test without XML::LibXML";
}
my $path = dirname __FILE__;
use_ok(qw/SOAP::WSDL::SAX::WSDLHandler/);
my $filter;
my $parser = XML::LibXML->new();
ok($filter = SOAP::WSDL::SAX::WSDLHandler->new(), "Object creation");
$parser->set_handler( $filter );
eval { $parser->parse_file( "$path/acceptance/wsdl/03_complexType-element-ref.wsdl" ) };
if ($@)
{
fail("parsing WSDL");
die "Can't test without parsed WSDL: $@";
}
else
{
pass("parsing XML");
}
my $definitions = $filter->get_data();
my $type = $definitions->first_types()->find_type('urn:Test', 'testComplexTypeRef');
my $element = $definitions->first_types()->find_element('urn:Test', 'TestElement');
my $output;
ok $element->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output })
, 'generate element code';
ok eval $output, 'eval generated code';
$output = '';
ok $type->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output })
, 'generate complexType code with element ref=""';
ok eval $output, 'eval generated code';
my $obj = Test::testComplexTypeRef->new({
TestRef => 'test_ref',
Test2 => 'test2',
});
is $obj, '<TestRef >test_ref</TestRef><Test2 >test2</Test2 >', 'serialization';
$element = $definitions->first_types()->find_element('urn:Test', 'TestRef');
$output = '';
ok $element->to_class({ wsdl => $definitions, prefix => 'Test::', output => \$output })
, 'generate top level element ref code';
ok eval $output, 'eval generated code' . $@;
# print $output;
$obj = Test::TestRef->new({ value => 'test_ref' });
is $obj, '<TestRef xmlns="urn:Test" >test_ref</TestRef>', 'serialization';

View File

@@ -5,7 +5,6 @@ use Test::More tests => 2;
use lib '../lib';
use lib 'lib';
use lib 't/lib';
use XML::LibXML;
use SOAP::WSDL::SAX::MessageHandler;
use_ok(qw/SOAP::WSDL::Expat::MessageParser/);
@@ -13,7 +12,6 @@ use_ok(qw/SOAP::WSDL::Expat::MessageParser/);
use MyComplexType;
use MyElement;
use MySimpleType;
use Benchmark;
my $xml = q{<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >
@@ -26,13 +24,6 @@ my $parser = SOAP::WSDL::Expat::MessageParser->new({
class_resolver => 'FakeResolver'
});
my $libxml = XML::LibXML->new();
my $handler = SOAP::WSDL::SAX::MessageHandler->new({
class_resolver => 'FakeResolver',
});
$libxml->set_handler( $handler );
$parser->parse( $xml );
is $parser->get_data(), q{<MyAtomicComplexTypeElement xmlns="urn:Test" >}

335
t/Expat/02_sub_parser.t Normal file
View File

@@ -0,0 +1,335 @@
package TopElement;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
use SOAP::WSDL::XSD::Typelib::ComplexType;
use Memoize;
memoize('_get_handlers');
use base qw(SOAP::WSDL::XSD::Typelib::Element
SOAP::WSDL::XSD::Typelib::ComplexType
);
{
my %TestElement_of :ATTR();
my $CLASS_OF_REF = { TestElement => 'TestElement' };
__PACKAGE__->_factory( [ 'TestElement' ],
{ 'TestElement' => \%TestElement_of, },
{ TestElement => 'TestElement' },
);
sub get_xmlns { 'urn:Test' };
__PACKAGE__->__set_name('TopElement');
__PACKAGE__->__set_nillable(1);
sub _get_handlers {
my $self = shift;
my $parser = shift;
return {
Start => $parser->start_tag({
class_of => $CLASS_OF_REF,
handler_of => {
TestElement => TestElement->_get_handlers( $parser ),
}
}),
End => $parser->end_top_tag( ),
Char => undef,
};
}
}
1;
package TestElement;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
use SOAP::WSDL::XSD::Typelib::ComplexType;
use Memoize;
memoize('_get_handlers');
use base qw(
SOAP::WSDL::XSD::Typelib::Element
SOAP::WSDL::XSD::Typelib::ComplexType
);
{
my %test_of :ATTR();
my %test2_of :ATTR();
my $CLASS_OF_REF = {
test => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
test2 => 'SOAP::WSDL::XSD::Typelib::Builtin::string'
};
__PACKAGE__->_factory( [ 'test', 'test2' ],
{ test => \%test_of, test2 => \%test2_of, },
$CLASS_OF_REF,
);
sub get_xmlns { 'urn:Test' };
__PACKAGE__->__set_name('TestElement');
__PACKAGE__->__set_nillable(1);
sub _get_handlers {
my $self = shift;
my $parser = shift;
return {
Start => $parser->start_tag({
class_of => $CLASS_OF_REF,
handler_of =>
{
map { ( $_ => $CLASS_OF_REF->{$_}->_get_handlers( $parser ) )}
keys %{ $CLASS_OF_REF }
},
}),
End => $parser->end_tag(),
Char => undef,
};
}
}
1;
package TestResolver;
sub get_class {
my $path = join('/', @{ $_[1] });
my $class = {
'TestElement' => 'TestElement',
'TestElement/test' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
'TestElement/test2' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
'TopElement' => 'TopElement',
'TopElement/TestElement' => 'TestElement',
'TopElement/TestElement/test' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
'TopElement/TestElement/test2' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
};
return $class->{ $path };
}
1;
package main;
use Test::More qw/no_plan/; # TODO: change to tests => N;
use strict;
use warnings;
use lib '../../lib';
use_ok('SOAP::WSDL::Expat::MessageParser');
use_ok('SOAP::WSDL::Expat::MessageSubParser');
my $obj;
ok($obj = SOAP::WSDL::Expat::MessageSubParser->new(), "Object creation");
#my $test = $obj->start_tag({
# order => [],
# class_of => {
# test => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
# test2 => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
# },
# handler_of => {
# test => {
# Char => $obj->characters(),
# },
# test2 => {
# Char => $obj->characters(),
# },
# }
#});
#
#my $handlers = {
# Start => $test,
# End => $obj->end_tag(),
#};
#
#my $parser = $obj->initialize( $handlers );
#
#$parser->parsestring('<test>Test</test>');
#is $obj->get_data(), 'Test', 'Parse simple XML';
#
#my $element = $obj->start_tag({
# order => [],
# class_of => {
# TestElement => 'TestElement',
# },
# handler_of => {
# TestElement => {
# Start => $obj->start_tag({
# order => [],
# class_of => {
# test => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
# test2 => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
# },
# handler_of => {
# test => {
# Char => $obj->characters(),
# },
# test2 => {
# Char => $obj->characters(),
# },
# }
# }),
# End => $obj->end_tag(),
# Char => undef,
# }
# }
#});
#
#
#$handlers = {
# Start => $element,
# End => $obj->end_tag(),
# Char => undef,
#};
#
#$parser = $obj->initialize( TestElement->_get_parser( $obj ) );
#
#my $xml = '<TestElement xmlns="urn:Test">
# <test>Test</test>
# <test2>Test2</test2>
#</TestElement>';
#
#$parser->parsestring($xml);
#
#is $obj->get_data()
# , '<TestElement xmlns="urn:Test" ><test >Test</test ><test2 >Test2</test2 ></TestElement>'
# , 'Parse && serialize ComplexType Element';
#
#my $mp = SOAP::WSDL::Expat::MessageParser->new({
# class_resolver => 'TestResolver',
#});
#
#$mp->parse( $xml );
#use Benchmark;
#
#timethese 1000 , {
# mp => sub { $mp->parse($xml) },
# 'sub_p' => sub { $obj->initialize( $handlers )->parse( $xml ) },
#
#};
#my $top = $obj->start_tag({
# order => [],
# class_of => {
# TopElement => 'TopElement',
# },
# handler_of => {
# TopElement => {
# Start => $obj->start_tag({
# order => [ 'TestElement', ],
# class_of => {
# TestElement => 'TestElement',
# },
# handler_of => {
# TestElement => {
# Start => $obj->start_tag({
# order => ['test', 'test2'],
# class_of => {
# test => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
# test2 => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
# },
# handler_of => {
# test => {
# Char => $obj->characters(),
# },
# test2 => {
# Char => $obj->characters(),
# },
# },
# occurs_of => {
# test => { max => 1 },
# }
# }),
# End => $obj->end_tag(),
# Char => undef,
# }
# }
# })
# }
# }
#});
my $top = $obj->start_tag({
class_of => {
TopElement => 'TopElement',
},
handler_of => {
TopElement => TopElement->_get_handlers( $obj ),
}
});
my $parser = $obj->initialize( { Start => $top , End => $obj->end_tag() , Char => undef } );
my $xml = '
<TopElement xmlns="urn:Test">
<TestElement>
<test>Test</test>
<test2>Test2</test2>
</TestElement>
<TestElement>
<test>Test</test>
<test2>Test2</test2>
</TestElement>
<TestElement>
<test>Test</test>
<test2>Test2</test2>
</TestElement>
<TestElement>
<test>Test</test>
<test2>Test2</test2>
</TestElement>
<TestElement>
<test>Test</test>
<test2>Test2</test2>
</TestElement>
<TestElement>
<test>Test</test>
<test2>Test2</test2>
</TestElement>
</TopElement>';
$parser->parsestring($xml);
# print $obj->get_data();
__END__
# TODO factor out into benchmark suite
use XML::Simple;
use Benchmark;
my $mp = SOAP::WSDL::Expat::MessageParser->new({
class_resolver => 'TestResolver',
});
$mp->parse( $xml );
$top = $obj->start_tag({
class_of => {
TopElement => 'TopElement',
},
handler_of => {
TopElement => TopElement->_get_handlers( $obj ),
}
});
my $top_end = $obj->end_top_tag();
$parser = $obj->initialize( { Start => $top , End => $top_end, , Char => undef } );
$parser->parse( $xml ),
print "DATA:" . $obj->get_data(), "\n";
# $XML::Simple::PREFERRED_PARSER = 'XML::SAX::Expat';
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';
timethese 500 , {
'typemap' => sub { $mp->parse($xml) },
'sub_tree' => sub {
my $parser = $obj->initialize( { Start => $top , End => $top_end, , Char => undef } );
$parser->parse( $xml ),
},
'XML::Simple' => sub { XMLin( $xml ); }
};

411
t/Expat/03_wsdl.t Normal file
View File

@@ -0,0 +1,411 @@
#!/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;
use Test::More tests => 7;
use Data::Dumper;
use lib '../lib';
eval {
require Test::XML;
import Test::XML;
};
use_ok(qw/SOAP::WSDL::Expat::WSDLParser/);
my $parser;
ok $parser = SOAP::WSDL::Expat::WSDLParser->new(), "Object creation";
$parser->parse( xml() );
eval { $parser->parse( xml() ) };
if ($@)
{
fail("parsing WSDL");
die "Can't test without parsed WSDL: " , Dumper $@;
}
else
{
pass("parsing XML");
}
my $wsdl;
ok $wsdl = $parser->get_data() , "get object tree";
my $schema = $wsdl->first_types()->get_schema()->[1] || die "No schema !";
my $element = $schema->find_element(
'http://www.example.org/MessageGateway2/'
, 'EnqueueMessage'
);
ok $element, 'find element';
is $element->get_xmlns()->{ 'http://www.example.org/MessageGateway2/' }, 'tns', 'Namespace definition';
my $opt = {
typelib => $wsdl->first_types,
readable => 1,
autotype => 0,
namespace => { 'http://www.example.org/MessageGateway2/' => 'tns',
'http://www.w3.org/2001/XMLSchema' => 'xsd',
'http://schemas.xmlsoap.org/wsdl/' => 'wsdl',
},
indent => "",
};
my $data = { EnqueueMessage => {
MMessage => {
MRecipientURI => 'anyURI',
MSenderAddress => 'a string',
MMessageContent => 'a string',
MSubject => 'a string',
MDeliveryReportRecipientURI => 'anyURI',
MKeepalive => {
MKeepaliveTimeout => 1234567,
MKeepaliveErrorPolicy => ' ( suppress | report ) ',
}
}
}
};
SKIP: { skip_without_test_xml();
is_xml( $wsdl->find_message(
"http://www.example.org/MessageGateway2/" ,'EnqueueMessageRequest'
)->first_part()->serialize( 'test', $data, $opt ),
xml_message()
, "Serialized message part"
);
}
sub skip_without_test_xml {
skip("Test::XML not available", 1) if (not $Test::XML::VERSION);
}
sub xml_message {
return
q{<EnqueueMessage xmlns="http://www.example.org/MessageGateway2/">
<MMessage>
<MRecipientURI>anyURI</MRecipientURI>
<MSenderAddress>a string</MSenderAddress>
<MMessageContent>a string</MMessageContent>
<MSubject>a string</MSubject>
<MDeliveryReportRecipientURI>anyURI</MDeliveryReportRecipientURI>
<MKeepalive>
<MKeepaliveTimeout>1234567</MKeepaliveTimeout>
<MKeepaliveErrorPolicy> ( suppress | report ) </MKeepaliveErrorPolicy>
</MKeepalive>
</MMessage>
</EnqueueMessage>
};
}
sub xml {
return q{<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="MessageGateway"
targetNamespace="http://www.example.org/MessageGateway2/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://www.example.org/MessageGateway2/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org/MessageGateway2/">
<xsd:element name="EnqueueMessage" type="tns:TEnqueueMessage"
xmlns:tns="http://www.example.org/MessageGateway2/"
>
<xsd:annotation>
<xsd:documentation>Enqueue message request element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="TMessage">
<xsd:annotation>
<xsd:documentation>
A type containing all elements of a message to enqueue.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MRecipientURI" type="xsd:anyURI" minOccurs="1"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The recipient in URI notaitions. Valid URI schemas are: mailto:, sms:,
phone:. Not all URI schemas need to be implemented at the current
implementation stage.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MSenderAddress" type="xsd:string" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
E-Mail sender address. Ignored for all but mailto: recipient URIs.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MMessageContent" type="xsd:string" minOccurs="1"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>Message Content.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MSubject" type="xsd:string" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Message Subject. Ignored for all but mailto: URIs
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MDeliveryReportRecipientURI" type="xsd:anyURI" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
URI to send a delivery report to. May be of one of the following schemes:
mailto:, http:, https:. Reports to mailto: URIs are sent as plaintext,
reports to http(s) URIs are sent as SOAP requests following the
MessageGatewayClient service definition.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MKeepalive" type="tns:TKeepalive" minOccurs="0"
maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Container for keepalive information. May be missing.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepalive">
<xsd:annotation>
<xsd:documentation>Type containing keeplive information.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MKeepaliveTimeout" type="xsd:double">
<xsd:annotation>
<xsd:documentation>
Keepalive timeout. The keepalive timeout spezifies how long the sending of
a message will be delayed waiting for keepalive updates. If a keepalive
update is received during this period, the timeout will be reset. If not,
the message will be sent after the timeout has expired.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MKeepaliveErrorPolicy" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
Policy to comply to in case of system errors. Valid values are "suppress"
and "report". If the policy is set to "suppress", keepalive messages will
not be sent to their recipients in case of partial system failure, even if
the keepalive has expired. This may result in "false negatives", i.e.
messages may not be sent, even though their keepalive has expired. If the
value is "report", keepalive messages will be sent from any cluster node.
This may result in "false positive" alerts.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="suppress"></xsd:enumeration>
<xsd:enumeration value="report"></xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TMessageID">
<xsd:annotation>
<xsd:documentation>Type containing a message ID.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessageID" type="xsd:string" minOccurs="1" maxOccurs="1"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepliveMessage">
<xsd:annotation>
<xsd:documentation>
Type containing all elements of a keppalive update / remove request.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessageID" type="xsd:string" minOccurs="1" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The ID for the message to update / remove
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MAction" minOccurs="1" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
The action to perform. Valid values are: "remove", "update". On "remove",
the message with the ID specified will be removed from the queue, thus it
will never be sent, even if it's timeout expires. On "update" the
keepalive timeout of the corresponding message will be reset.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="remove"></xsd:enumeration>
<xsd:enumeration value="update"></xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="KeepaliveMessage" type="tns:TKeepaliveMessageRequest">
<xsd:annotation>
<xsd:documentation>Keepalive message request element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="KeepaliveMessageResponse" type="tns:TMessageID">
<xsd:annotation>
<xsd:documentation>Response element for a keepalive request</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="EnqueueMessageResponse" type="tns:TMessageID">
<xsd:annotation>
<xsd:documentation>Enqueue message response element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="TEnqueueMessage">
<xsd:annotation>
<xsd:documentation>
A complex type containing one element: The message to enqueue.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MMessage" type="tns:TMessage">
<xsd:annotation>
<xsd:documentation>
Element containing a message to enqueue.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TKeepaliveMessageRequest">
<xsd:annotation>
<xsd:documentation>
A complex type containing one element: The keepalive message to process.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MKeepaliveMessage" type="tns:TKeepliveMessage">
<xsd:annotation>
<xsd:documentation>
Element containing a keepalive message to process.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="EnqueueMessageRequest">
<wsdl:part name="parameters" element="tns:EnqueueMessage">
<wsdl:documentation>inputparameters for EnqueueMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="EnqueueMessageResponse">
<wsdl:part name="parameters" element="tns:EnqueueMessageResponse">
<wsdl:documentation>outputparameters for EnqueueMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="KeepaliveMessageRequest">
<wsdl:part name="parameters" element="tns:KeepaliveMessage">
<wsdl:documentation>input parameters for KeepaliveMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:message name="KeepaliveMessageResponse">
<wsdl:part name="parameters" element="tns:KeepaliveMessageResponse">
<wsdl:documentation>output parameters for KeepaliveMessag</wsdl:documentation>
</wsdl:part>
</wsdl:message>
<wsdl:portType name="MGWPortType">
<wsdl:documentation>
generic port type for all methods required for sending messages over the mosaic
message gatewa
</wsdl:documentation>
<wsdl:operation name="EnqueueMessage">
<wsdl:documentation>
This method is used to enqueue a normal (immediate send) or a delayed message with
keepalive functionality.
</wsdl:documentation>
<wsdl:input message="tns:EnqueueMessageRequest"></wsdl:input>
<wsdl:output message="tns:EnqueueMessageResponse"></wsdl:output>
</wsdl:operation>
<wsdl:operation name="KeepaliveMessage">
<wsdl:documentation>
This method is used to update or remove a
keepalive message.
</wsdl:documentation>
<wsdl:input message="tns:KeepaliveMessageRequest"></wsdl:input>
<wsdl:output message="tns:KeepaliveMessageResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="MGWBinding" type="tns:MGWPortType">
<wsdl:documentation>Generic binding for all (SOAP) port</wsdl:documentation>
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="EnqueueMessage">
<soap:operation soapAction="http://www.example.org/MessageGateway2/EnqueueMessage" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="KeepaliveMessage">
<soap:operation
soapAction="http://www.example.org/MessageGateway2/KeepaliveMessage" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="MessageGateway">
<wsdl:documentation>
Web Service for sending messages over the mosaic message gatewa
</wsdl:documentation>
<wsdl:port name="HTTPPort" binding="tns:MGWBinding">
<wsdl:documentation>HTTP(S) port for the mosaic message gatewa</wsdl:documentation>
<soap:address location="https://www.example.org/MessageGateway/" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>};
}

View File

@@ -0,0 +1,43 @@
use Test::More tests => 4;
use strict;
use warnings;
use lib '../lib';
use lib 't/lib';
use lib 'lib';
use Cwd;
use File::Basename;
my $path = cwd();
my $name = basename $0;
$name =~s/\.t$//;
$name =~s/^t\///;
$path =~s{(/t)?/SOAP/WSDL}{}xms;
use_ok(qw/SOAP::WSDL/);
print "# SOAP::WSDL Version: $SOAP::WSDL::VERSION\n";
my $xml;
my $soap;
#2
ok( $soap = SOAP::WSDL->new(
wsdl => 'file://' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl',
readable => 1,
no_dispatch => 1,
), 'Instantiated object' );
ok ($xml = $soap->call('test',
testAll => {
Test2 => 'Test2',
TestRef => 'TestRef'
}
), 'Serialized complexType' );
is $xml, q{<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ><SOAP-ENV:Body><testAll>
<TestRef>TestRef</TestRef>
<Test2>Test2</Test2>
</testAll>
</SOAP-ENV:Body></SOAP-ENV:Envelope>}
, 'element ref="" serialization';

View File

@@ -1,4 +1,4 @@
use Test::More tests => 6;
use Test::More tests => 8;
use strict;
use warnings;
use lib '../lib';
@@ -39,6 +39,16 @@ ok ($xml = $soap->call('test',
testElement1 => 'Test'
), 'Serialized (simple) element' );
ok ($xml = $soap->call('testRef',
testElementRef => 'Test'
), 'Serialized (simple) element' );
is $xml
, q{<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ><SOAP-ENV:Body><testElementRef xmlns="urn:Test">Test</testElementRef>
</SOAP-ENV:Body></SOAP-ENV:Envelope>}
, 'element ref serialization result'
;
TODO: {
local $TODO="implement min/maxOccurs checks";

View File

@@ -1,83 +0,0 @@
#!/usr/bin/perl -w
use strict;
use Test::More tests=> 5;
use Time::HiRes qw( gettimeofday tv_interval );
use lib '../..';
use Data::Dumper;
use Cwd;
use File::Basename;
use_ok qw/ SOAP::WSDL /;
use Benchmark;
print "# Testing SOAP::WSDL ". $SOAP::WSDL::VERSION."\n";
print "# Performance test with simple WSDL file\n";
my $soap;
my $data = {
sayHello => {
name => 'Mein Name',
givenName => 'Vorname',
}
};
my $name = basename( $0 );
$name =~s/\.(t|pl)$//;
my $path = cwd;
$path=~s{(/t)?/SOAP/WSDL}{}xms;
my $cacheDir;
if ($^O =~ m/Win/)
{
$cacheDir = 'C:/Temp/WSDL';
}
else
{
$cacheDir = '/tmp/';
}
my $t0 = [gettimeofday];
ok(
$soap=SOAP::WSDL->new(
wsdl => "file://$path/t/acceptance/wsdl/10_helloworld.asmx.xml",
no_dispatch => 1
),
"Create SOAP::WSDL object (".tv_interval ( $t0, [gettimeofday]) ."ms)" );
$soap->proxy('http://helloworld/helloworld.asmx');
$t0 = [gettimeofday];
eval{
$soap->wsdlinit(
caching => 1,
cache_directory => $cacheDir,
servicename => 'Service1' ) };
unless ($@) {
pass("wsdl file init (".tv_interval ( $t0, [gettimeofday]) ."s)");
} else {
fail( $@ );
}
$soap->readable(1);
$t0 = [gettimeofday];
ok( $soap->call("sayHello" , %{ $data }),
"1 x call pre-work (".tv_interval ( $t0, [gettimeofday]) ."s)") ;
$t0 = [gettimeofday];
ok($soap->call(sayHello => %{ $data }),
"1 x call pre-work (".tv_interval ( $t0, [gettimeofday]) ."s)" );
timethis 1000, sub { $soap->call(sayHello => %{ $data }) };
__END__
$t0 = [gettimeofday];
for (my $i=1; $i<100; $i++)
{
$soap->call(sayHello => %{ $data });
}
ok(1, "100 x call pre-work (".tv_interval ( $t0, [gettimeofday]) ."s)");
chdir $cwd;

View File

@@ -1,25 +1,32 @@
use Test::More tests => 2;
use Test::More tests => 4;
use strict;
use warnings;
use lib '../lib';
use Date::Parse;
use Date::Format;
sub timezone {
my @time = strptime shift;
my $tz = strftime('%z', @time);
substr $tz, -2, 0, ':';
return $tz;
}
use_ok('SOAP::WSDL::XSD::Typelib::Builtin::dateTime');
print "# timezone is " . timezone( scalar localtime(time) ) . "\n";
my $obj;
my %dates = (
'2007-12-31 12:32' => '2007-12-31T12:32:00',
'2007-08-31 00:32' => '2007-08-31T00:32:00',
'30 Aug 2007' => '2007-08-30T00:00:00',
);
$obj = SOAP::WSDL::XSD::Typelib::Builtin::dateTime->new();
while (my ($date, $converted) = each %dates ) {
$obj->set_value( '2037-12-31' );
is $obj->get_value() , '2037-12-31T00:00:00+01:00', 'conversion';
$obj->set_value('2037-12-31T00:00:00.0000000+01:00');
# exit;
#~ use Benchmark;
#~ timethese 10000, {
#~ xml => sub { $obj->set_value('2037-12-31T00:00:00.0000000+01:00') },
#~ string => sub { $obj->set_value('2037-12-31') },
#~ }
$obj = SOAP::WSDL::XSD::Typelib::Builtin::dateTime->new();
$obj->set_value( $date );
is $obj->get_value() , $converted . timezone($date), 'conversion with timezone';
}
$obj->set_value('2007-12-31T00:00:00.0000000+01:00');

View File

@@ -1,25 +0,0 @@
use Test::More tests => 3;
use strict;
use warnings;
use lib '../lib';
use_ok('SOAP::WSDL::XSD::Typelib::Builtin::time');
my $obj;
$obj = SOAP::WSDL::XSD::Typelib::Builtin::time->new();
$obj->set_value( '12:23:03' );
is $obj->get_value() , '12:23:03+01:00', 'conversion';
$obj->set_value( '12:23:03.12345+01:00' ), ;
is $obj->get_value() , '12:23:03.12345+01:00', 'no conversion';
# exit;
#~ use Benchmark;
#~ timethese 10000, {
#~ xml => sub { $obj->set_value('2037-12-31T00:00:00.0000000+01:00') },
#~ string => sub { $obj->set_value('2037-12-31') },
#~ }

View File

@@ -1,17 +1,35 @@
use Test::More tests => 3;
use Test::More tests => 6;
use strict;
use warnings;
use lib '../lib';
use Date::Format;
use Date::Parse;
use_ok('SOAP::WSDL::XSD::Typelib::Builtin::date');
my $obj;
$obj = SOAP::WSDL::XSD::Typelib::Builtin::date->new();
sub timezone {
my @time = strptime shift;
my $tz = strftime('%z', @time);
substr $tz, -2, 0, ':';
return $tz;
}
$obj->set_value( '2037/12/31' );
is $obj->get_value() , '2037-12-31+01:00', 'conversion';
my %dates = (
'2007/12/31' => '2007-12-31',
'2007:08:31' => '2007-08-31',
'30 Aug 2007' => '2007-08-30',
);
while (my ($date, $converted) = each %dates ) {
$obj = SOAP::WSDL::XSD::Typelib::Builtin::date->new();
$obj->set_value( $date );
is $obj->get_value() , $converted . timezone($date), 'conversion';
}
$obj->set_value('2007-12-31T00:00:00.0000000+01:00');
is $obj->get_value() , '2007-12-31+01:00', 'conversion from XML dateTime';
$obj->set_value( '2037-12-31' );
is $obj->get_value() , '2037-12-31', 'no conversion on match';

View File

@@ -1,72 +1,63 @@
<?xml version="1.0"?>
<definitions name="urn:Test"
targetNamespace="urn:Test"
xmlns:tns="urn:Test"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
>
<definitions name="urn:Test" targetNamespace="urn:Test" xmlns:tns="urn:Test"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema targetNamespace="urn:Test">
<xsd:complexType name="testComplexTypeAll">
<xsd:annotation>
<xsd:documentation>
ComplexType Test
</xsd:documentation>
</xsd:annotation>
<xsd:annotation>
<xsd:documentation>ComplexType Test</xsd:documentation>
</xsd:annotation>
<xsd:all>
<xsd:element name="Test1" type="xsd:string"/>
<xsd:element name="Test2" type="xsd:string" minOccurs="1"/>
</xsd:all>
<xsd:element name="Test1" type="xsd:string" />
<xsd:element name="Test2" type="xsd:string" minOccurs="1" />
</xsd:all>
</xsd:complexType>
<xsd:complexType name="testComplexTypeSequence">
<xsd:annotation>
<xsd:documentation>
ComplexType Test
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="Test1" type="xsd:string" minOccurs="1"/>
<xsd:element name="Test2" type="xsd:string" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="testComplexTypeSequence">
<xsd:annotation>
<xsd:documentation>ComplexType Test</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="Test1" type="xsd:string" minOccurs="1" />
<xsd:element name="Test2" type="xsd:string" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</types>
<message name="testRequest">
<part name="testAll" type="tns:testComplexTypeAll"/>
</message>
<message name="testResponse">
<part name="testAll" type="tns:testComplexTypeAll"/>
</message>
<portType name="testPort">
<operation name="test">
<documentation>
Test-Methode
</documentation>
</types>
<message name="testRequest">
<part name="testAll" type="tns:testComplexTypeAll" />
</message>
<message name="testResponse">
<part name="testAll" type="tns:testComplexTypeAll" />
</message>
<portType name="testPort">
<operation name="test">
<documentation>Test-Methode</documentation>
<input message="tns:testRequest"/>
<output message="tns:testResponse"/>
</operation>
</portType>
<input message="tns:testRequest" />
<output message="tns:testResponse" />
</operation>
</portType>
<binding type="tns:testPort" name="testBinding">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="test">
<soap:operation soapAction="test">
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</soap:operation>
</operation>
</binding>
<service name="testService">
<port name="testPort" binding="tns:testBinding">
<soap:address location="http://127.0.0.1/testPort" />
</port>
</service>
</definitions>
<binding type="tns:testPort" name="testBinding">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="test">
<soap:operation soapAction="test">
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</soap:operation>
</operation>
</binding>
<service name="testService">
<port name="testPort" binding="tns:testBinding">
<soap:address location="http://127.0.0.1/testPort" />
</port>
</service>
</definitions>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0"?>
<definitions name="urn:Test" targetNamespace="urn:Test" xmlns:tns="urn:Test"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<types>
<xsd:schema targetNamespace="urn:Test">
<xsd:element name="TestElement" type="xsd:string" />
<xsd:element name="TestRef" ref="tns:TestElement" />
<xsd:complexType name="testComplexTypeRef">
<xsd:annotation>
<xsd:documentation>ComplexType Test</xsd:documentation>
</xsd:annotation>
<xsd:all>
<xsd:element name="TestRef" ref="tns:TestElement" />
<xsd:element name="Test2" type="xsd:string" minOccurs="1" />
</xsd:all>
</xsd:complexType>
</xsd:schema>
</types>
<message name="testRequest">
<part name="testAll" type="tns:testComplexTypeRef" />
</message>
<message name="testResponse">
<part name="testAll" type="tns:testComplexTypeRef" />
</message>
<portType name="testPort">
<operation name="test">
<documentation>Test-Methode</documentation>
<input message="tns:testRequest" />
<output message="tns:testResponse" />
</operation>
</portType>
<binding type="tns:testPort" name="testBinding">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="test">
<soap:operation soapAction="test">
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</soap:operation>
</operation>
</binding>
<service name="testService">
<port name="testPort" binding="tns:testBinding">
<soap:address location="http://127.0.0.1/testPort" />
</port>
</service>
</definitions>

View File

@@ -9,12 +9,17 @@
<types>
<xsd:schema targetNamespace="urn:Test">
<xsd:element name="testElement1" type="xsd:string" />
<xsd:element name="testElement2" type="xsd:int" />
<xsd:element name="testElement2" type="xsd:int" />
<xsd:element name="testElementRef" ref="tns:testElement1" />
</xsd:schema>
</types>
<message name="testRequest">
<part name="testAll" element="tns:testElement1"/>
</message>
<message name="testRefRequest">
<part name="testAll" element="tns:testElementRef"/>
</message>
<message name="testResponse">
<part name="testAll" type="tns:testElement1"/>
</message>
@@ -27,10 +32,18 @@
<input message="tns:testRequest"/>
<output message="tns:testResponse"/>
</operation>
<operation name="testRef">
<documentation>
Test-Methode
</documentation>
<input message="tns:testRefRequest"/>
<output message="tns:testResponse"/>
</operation>
</portType>
<binding type="tns:testPort" name="testBinding">
<operation name="test">
<operation name="test">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<soap:operation soapAction="test">
<input>
@@ -40,7 +53,18 @@
<soap:body use="literal"/>
</output>
</soap:operation>
</operation>
</operation>
<operation name="testRef">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<soap:operation soapAction="testRef">
<input>
<soap:body use="literal"/>
</input>
<output>
<soap:body use="literal"/>
</output>
</soap:operation>
</operation>
</binding>
<service name="testService">
<port name="testPort" binding="tns:testBinding">

View File

@@ -1,7 +1,6 @@
#!/usr/bin/perl
package MyElement;
use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
use SOAP::WSDL::XSD::Typelib::Builtin;
use base (
@@ -14,7 +13,6 @@ sub get_xmlns { 'urn:Test' };
package MyComplexTypeElement;
use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
use MyComplexType;
use base (
@@ -27,7 +25,6 @@ sub get_xmlns { 'urn:Test' };
package MyTestElement;
use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
use SOAP::WSDL::XSD::Typelib::Builtin::string;
use base (
@@ -36,12 +33,11 @@ use base (
);
__PACKAGE__->__set_name('MyTestElement');
sub get_xmlns { 'urn:Test' };
package MyTestElement2;
use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
use SOAP::WSDL::XSD::Typelib::Builtin;
use base (
@@ -57,7 +53,6 @@ sub get_xmlns { 'urn:Test' };
package MyAtomicComplexTypeElement;
use strict;
use Class::Std::Storable;
use SOAP::WSDL::XSD::Typelib::Element;
use SOAP::WSDL::XSD::Typelib::ComplexType;
use SOAP::WSDL::XSD::Typelib::Builtin;

View File

@@ -1,5 +1,5 @@
package Typelib::Base;
use Class::Std::Storable;
use Class::Std::Storable;
sub mk_add_mutators {
my $class = shift;

View File

@@ -1,7 +1,6 @@
package Typelib::TEnqueueMessage;
use strict;
use base qw(Typelib::Base);
use Class::Std::Storable;
my %MMessage_of :ATTR(:name<MMessage> :default<()>);

View File

@@ -1,7 +1,6 @@
package Typelib::TMessage;
use strict;
use base qw(Typelib::Base);
use Class::Std::Storable;
my %MRecipientURI_of :ATTR(:name<MRecipientURI> :default<()>);
my %MMessageContent_of :ATTR(:name<MMessageContent> :default<()>);