Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25548e6296 | ||
|
|
a78d6d15b5 |
@@ -2,17 +2,21 @@ use Module::Build;
|
|||||||
Module::Build->new(
|
Module::Build->new(
|
||||||
dist_abstract => 'SOAP with WSDL support',
|
dist_abstract => 'SOAP with WSDL support',
|
||||||
dist_name => 'SOAP-WSDL',
|
dist_name => 'SOAP-WSDL',
|
||||||
dist_version => '2.00_04',
|
dist_version => '2.00_06',
|
||||||
module_name => 'SOAP::WSDL',
|
module_name => 'SOAP::WSDL',
|
||||||
license => 'artistic',
|
license => 'artistic',
|
||||||
requires => {
|
requires => {
|
||||||
'Class::Std' => q/v0.0.8/,
|
'Class::Std' => q/v0.0.8/,
|
||||||
'Class::Std::Storable' => 0,
|
'Class::Std::Storable' => 0,
|
||||||
'SOAP::Lite' => 0,
|
'SOAP::Lite' => 0,
|
||||||
'XML::XPath' => 0,
|
'List::Util' => 0,
|
||||||
'XML::LibXML' => 0,
|
'File::Basename' => 0,
|
||||||
'XML::SAX::Base' => 0,
|
'File::Path' => 0,
|
||||||
'XML::SAX::ParserFactory' => 0,
|
'XML::XPath' => 0,
|
||||||
|
'XML::LibXML' => 0,
|
||||||
|
'XML::SAX::Base' => 0,
|
||||||
|
'XML::SAX::ParserFactory' => 0,
|
||||||
|
'XML::Parser::Expat' => 0,
|
||||||
},
|
},
|
||||||
buildrequires => {
|
buildrequires => {
|
||||||
'Benchmark' => 0,
|
'Benchmark' => 0,
|
||||||
@@ -21,13 +25,17 @@ Module::Build->new(
|
|||||||
'SOAP::Lite' => 0,
|
'SOAP::Lite' => 0,
|
||||||
'Class::Std' => 0.0.8,
|
'Class::Std' => 0.0.8,
|
||||||
'Class::Std::Storable' => 0,
|
'Class::Std::Storable' => 0,
|
||||||
|
'List::Util' => 0,
|
||||||
|
'File::Basename' => 0,
|
||||||
|
'File::Path' => 0,
|
||||||
'XML::XPath' => 0,
|
'XML::XPath' => 0,
|
||||||
'XML::Simple' => 0,
|
'XML::Simple' => 0,
|
||||||
'XML::LibXML' => 0,
|
'XML::LibXML' => 0,
|
||||||
|
'XML::Parser::Expat' => 0,
|
||||||
'XML::SAX::Base' => 0,
|
'XML::SAX::Base' => 0,
|
||||||
'XML::SAX::ParserFactory' => 0,
|
'XML::SAX::ParserFactory' => 0,
|
||||||
'Pod::Simple::Text' => 0,
|
'Pod::Simple::Text' => 0,
|
||||||
'XML::SAX::ParserFactory' => 0,
|
'XML::SAX::ParserFactory' => 0,
|
||||||
|
|
||||||
},
|
},
|
||||||
|
recursive_test_files => 1,
|
||||||
)->create_build_script;
|
)->create_build_script;
|
||||||
|
|||||||
@@ -1,57 +1 @@
|
|||||||
$Log: CHANGES,v $
|
See perldoc SOAP::WSDL
|
||||||
|
|
||||||
Revision 1.19 2004/07/27 13:00:03 lsc
|
|
||||||
- added missing test file
|
|
||||||
|
|
||||||
Revision 1.18 2004/07/16 07:43:05 lsc
|
|
||||||
fixed test scripts for windows
|
|
||||||
|
|
||||||
Revision 1.17 2004/07/05 08:19:49 lsc
|
|
||||||
- added wsdl_checkoccurs
|
|
||||||
|
|
||||||
Revision 1.16 2004/07/04 09:01:14 lsc
|
|
||||||
- change <definitions> element lookup from find('/definitions') and find('wsdl:definitions') to find('/*[1]') to process arbitrary default (wsdl) namespaces correctly
|
|
||||||
- fixed test output in test 06
|
|
||||||
|
|
||||||
Revision 1.15 2004/07/02 12:28:31 lsc
|
|
||||||
- documentation update
|
|
||||||
- cosmetics
|
|
||||||
|
|
||||||
Revision 1.14 2004/07/02 10:53:36 lsc
|
|
||||||
- API change:
|
|
||||||
- call now behaves (almost) like SOAP::Lite::call
|
|
||||||
- call() takes a list (hash) as second argument
|
|
||||||
- call does no longer support the "dispatch" option
|
|
||||||
- dispatching calls can be suppressed by passing
|
|
||||||
"no_dispatch => 1" to new()
|
|
||||||
- dispatching calls can be suppressed by calling
|
|
||||||
$soap->no_dispatch(1);
|
|
||||||
and re-enabled by calling
|
|
||||||
$soap->no_dispatch(0);
|
|
||||||
- Updated test skripts to reflect API change.
|
|
||||||
|
|
||||||
Revision 1.13 2004/06/30 12:08:40 lsc
|
|
||||||
- added IServiceInstance (ecmed) to acceptance tests
|
|
||||||
- refined documentation
|
|
||||||
|
|
||||||
Revision 1.12 2004/06/26 14:13:29 lsc
|
|
||||||
- refined file caching
|
|
||||||
- added descriptive output to test scripts
|
|
||||||
|
|
||||||
Revision 1.11 2004/06/26 07:55:40 lsc
|
|
||||||
- fixed "freeze" caching bug
|
|
||||||
- improved test scripts to test file system caching (and show the difference)
|
|
||||||
|
|
||||||
Revision 1.10 2004/06/26 06:30:33 lsc
|
|
||||||
- added filesystem caching using Cache::FileCache
|
|
||||||
|
|
||||||
Revision 1.9 2004/06/24 12:27:23 lsc
|
|
||||||
Cleanup
|
|
||||||
|
|
||||||
Revision 1.8 2004/06/11 19:49:15 lsc
|
|
||||||
- moved .t files to more self-describing names
|
|
||||||
- changed WSDL.pm to accept AXIS wsdl files
|
|
||||||
- implemented XPath query result caching on all absolute queries
|
|
||||||
|
|
||||||
Revision 1.7 2004/06/07 13:01:16 lsc
|
|
||||||
added changelog to pod
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
Development of SOAP::WSDL takes place on sourceforge.net.
|
Development of SOAP::WSDL takes place on sourceforge.net.
|
||||||
|
|
||||||
There's a svn repository available at
|
There's a svn repository available at
|
||||||
https://svn.sourceforge.net/svnroot/soap-wsdl
|
https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl
|
||||||
|
|
||||||
Engagement in the further development of this module is highly encouraged -
|
Engagement in the further development of this module is highly encouraged -
|
||||||
many people have already contributed, and many more probably will.
|
many people have already contributed, and many more probably will.
|
||||||
@@ -14,13 +14,36 @@ you as co-author.
|
|||||||
The (my) current roadmap for SOAP::WSDL is:
|
The (my) current roadmap for SOAP::WSDL is:
|
||||||
|
|
||||||
1.2*: Bugfixes and support for more XSD variants
|
1.2*: Bugfixes and support for more XSD variants
|
||||||
|
|
||||||
1.3: Bindings support
|
1.3: Bindings support
|
||||||
|
|
||||||
Development of the 1.* tree has stopped - I won't get past 1.2x anymore...
|
Development of the 1.* tree has stopped - I won't get past 1.2x anymore...
|
||||||
|
|
||||||
2.*: WSDL -> Perl Class factory with offline WSDL processing
|
2.*: WSDL -> Perl Class factory with offline WSDL processing
|
||||||
|
|
||||||
May 2007,
|
2.01
|
||||||
|
- WSDL support for the most common type definitions
|
||||||
|
- Online-facility (SOAP::WSDL) using WSDL object tree directly
|
||||||
|
- usable code generator
|
||||||
|
- full namespace support when processing WSDL
|
||||||
|
- high performance when parsing WSDL messages - get nearly as fast as
|
||||||
|
XML::Simple...
|
||||||
|
|
||||||
|
2.02
|
||||||
|
- Support for Apache-SOAP datatypes
|
||||||
|
- support for embedded atomic simpleType/complexType definitions
|
||||||
|
- Caching of WSDL object tree + generated code (when using SOAP::WSDL).
|
||||||
|
- Online-facility (SOAP::WSDL) using code generator via cache directory
|
||||||
|
|
||||||
|
Somewhere on the TODO list (in no particular order):
|
||||||
|
|
||||||
|
- validation
|
||||||
|
- typemaps for use with the type="tns:MyComplexType" XML attribute
|
||||||
|
- external entities support when parsing WSDL
|
||||||
|
- support all these XML Schema variants
|
||||||
|
- support creating XML Schmema definitions via SOAP::WSDL::XSD::* ('minimal conformant')
|
||||||
|
- support other Schema definition languages than XML::Schema (maybe RelaxNG?)
|
||||||
|
- factor out SOAP::WSDL::XSD into it's own namespace (maybe just XSD ?)
|
||||||
|
|
||||||
|
July 2007,
|
||||||
|
|
||||||
Martin Kutter
|
Martin Kutter
|
||||||
@@ -8,9 +8,12 @@ lib/SOAP/WSDL/Client.pm
|
|||||||
lib/SOAP/WSDL/Client/Base.pm
|
lib/SOAP/WSDL/Client/Base.pm
|
||||||
lib/SOAP/WSDL/Definitions.pm
|
lib/SOAP/WSDL/Definitions.pm
|
||||||
lib/SOAP/WSDL/Envelope.pm
|
lib/SOAP/WSDL/Envelope.pm
|
||||||
|
lib/SOAP/WSDL/Expat/MessageParser.pm
|
||||||
|
lib/SOAP/WSDL/Expat/MessageStreamParser.pm
|
||||||
lib/SOAP/WSDL/Message.pm
|
lib/SOAP/WSDL/Message.pm
|
||||||
lib/SOAP/WSDL/Operation.pm
|
lib/SOAP/WSDL/Operation.pm
|
||||||
lib/SOAP/WSDL/OpMessage.pm
|
lib/SOAP/WSDL/OpMessage.pm
|
||||||
|
lib/SOAP/WSDL/Parser.pod
|
||||||
lib/SOAP/WSDL/Part.pm
|
lib/SOAP/WSDL/Part.pm
|
||||||
lib/SOAP/WSDL/Port.pm
|
lib/SOAP/WSDL/Port.pm
|
||||||
lib/SOAP/WSDL/PortType.pm
|
lib/SOAP/WSDL/PortType.pm
|
||||||
@@ -96,6 +99,7 @@ t/013_complexType.t
|
|||||||
t/014_sax_typelib.t
|
t/014_sax_typelib.t
|
||||||
t/015_to_typemap.t
|
t/015_to_typemap.t
|
||||||
t/016_client_object.t
|
t/016_client_object.t
|
||||||
|
t/017_generator.t
|
||||||
t/020_storable.t
|
t/020_storable.t
|
||||||
t/098_pod.t
|
t/098_pod.t
|
||||||
t/acceptance/results/03_complexType-all.xml
|
t/acceptance/results/03_complexType-all.xml
|
||||||
@@ -123,25 +127,7 @@ t/acceptance/wsdl/contributed/ETest.wsdl
|
|||||||
t/acceptance/wsdl/contributed/OITest.wsdl
|
t/acceptance/wsdl/contributed/OITest.wsdl
|
||||||
t/acceptance/wsdl/contributed/tools.wsdl
|
t/acceptance/wsdl/contributed/tools.wsdl
|
||||||
t/acceptance/wsdl/email_account.wsdl
|
t/acceptance/wsdl/email_account.wsdl
|
||||||
t/attic/01_use.t
|
t/Expat/01_expat.t
|
||||||
t/attic/02_port.t
|
|
||||||
t/attic/03_complexType-all.t
|
|
||||||
t/attic/03_complexType-choice.t
|
|
||||||
t/attic/03_complexType-complexContent.t
|
|
||||||
t/attic/03_complexType-group.t
|
|
||||||
t/attic/03_complexType-sequence.t
|
|
||||||
t/attic/03_complexType-simpleContent.t
|
|
||||||
t/attic/04_element-complexType.t
|
|
||||||
t/attic/04_element-simpleType.t
|
|
||||||
t/attic/04_element.t
|
|
||||||
t/attic/05_simpleType-list.t
|
|
||||||
t/attic/05_simpleType-restriction.t
|
|
||||||
t/attic/05_simpleType-union.t
|
|
||||||
t/attic/10_performance.t
|
|
||||||
t/attic/11_helloworld.NET.t
|
|
||||||
t/attic/12_binding.pl
|
|
||||||
t/attic/97_pod.t
|
|
||||||
t/attic/98_pod_coverage.t
|
|
||||||
t/lib/MyComplexType.pm
|
t/lib/MyComplexType.pm
|
||||||
t/lib/MyElement.pm
|
t/lib/MyElement.pm
|
||||||
t/lib/MySimpleType.pm
|
t/lib/MySimpleType.pm
|
||||||
@@ -149,3 +135,21 @@ t/lib/Test/SOAPMessage.pm
|
|||||||
t/lib/Typelib/Base.pm
|
t/lib/Typelib/Base.pm
|
||||||
t/lib/Typelib/TEnqueueMessage.pm
|
t/lib/Typelib/TEnqueueMessage.pm
|
||||||
t/lib/Typelib/TMessage.pm
|
t/lib/Typelib/TMessage.pm
|
||||||
|
t/SOAP/WSDL/01_use.t
|
||||||
|
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-group.t
|
||||||
|
t/SOAP/WSDL/03_complexType-sequence.t
|
||||||
|
t/SOAP/WSDL/03_complexType-simpleContent.t
|
||||||
|
t/SOAP/WSDL/04_element-complexType.t
|
||||||
|
t/SOAP/WSDL/04_element-simpleType.t
|
||||||
|
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
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
---
|
---
|
||||||
name: SOAP-WSDL
|
name: SOAP-WSDL
|
||||||
version: 2.00_04
|
version: 2.00_06
|
||||||
author:
|
author:
|
||||||
abstract: SOAP with WSDL support
|
abstract: SOAP with WSDL support
|
||||||
license: artistic
|
license: artistic
|
||||||
requires:
|
requires:
|
||||||
Class::Std: v0.0.8
|
Class::Std: v0.0.8
|
||||||
Class::Std::Storable: 0
|
Class::Std::Storable: 0
|
||||||
|
File::Basename: 0
|
||||||
|
File::Path: 0
|
||||||
|
List::Util: 0
|
||||||
SOAP::Lite: 0
|
SOAP::Lite: 0
|
||||||
XML::LibXML: 0
|
XML::LibXML: 0
|
||||||
|
XML::Parser::Expat: 0
|
||||||
XML::SAX::Base: 0
|
XML::SAX::Base: 0
|
||||||
XML::SAX::ParserFactory: 0
|
XML::SAX::ParserFactory: 0
|
||||||
XML::XPath: 0
|
XML::XPath: 0
|
||||||
@@ -19,7 +23,7 @@ meta-spec:
|
|||||||
provides:
|
provides:
|
||||||
SOAP::WSDL:
|
SOAP::WSDL:
|
||||||
file: lib/SOAP/WSDL.pm
|
file: lib/SOAP/WSDL.pm
|
||||||
version: 2.00_04
|
version: 2.00_05
|
||||||
SOAP::WSDL::Base:
|
SOAP::WSDL::Base:
|
||||||
file: lib/SOAP/WSDL/Base.pm
|
file: lib/SOAP/WSDL/Base.pm
|
||||||
SOAP::WSDL::Binding:
|
SOAP::WSDL::Binding:
|
||||||
@@ -33,6 +37,10 @@ provides:
|
|||||||
file: lib/SOAP/WSDL/Definitions.pm
|
file: lib/SOAP/WSDL/Definitions.pm
|
||||||
SOAP::WSDL::Envelope:
|
SOAP::WSDL::Envelope:
|
||||||
file: lib/SOAP/WSDL/Envelope.pm
|
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::Message:
|
SOAP::WSDL::Message:
|
||||||
file: lib/SOAP/WSDL/Message.pm
|
file: lib/SOAP/WSDL/Message.pm
|
||||||
SOAP::WSDL::OpMessage:
|
SOAP::WSDL::OpMessage:
|
||||||
@@ -47,8 +55,6 @@ provides:
|
|||||||
file: lib/SOAP/WSDL/PortType.pm
|
file: lib/SOAP/WSDL/PortType.pm
|
||||||
SOAP::WSDL::SAX::MessageHandler:
|
SOAP::WSDL::SAX::MessageHandler:
|
||||||
file: lib/SOAP/WSDL/SAX/MessageHandler.pm
|
file: lib/SOAP/WSDL/SAX/MessageHandler.pm
|
||||||
SOAP::WSDL::SAX::WSDLHandler:
|
|
||||||
file: lib/SOAP/WSDL/SAX/WSDLHandler.pm
|
|
||||||
SOAP::WSDL::SOAP::Typelib::Fault11:
|
SOAP::WSDL::SOAP::Typelib::Fault11:
|
||||||
file: lib/SOAP/WSDL/SOAP/Typelib/Fault11.pm
|
file: lib/SOAP/WSDL/SOAP/Typelib/Fault11.pm
|
||||||
SOAP::WSDL::Service:
|
SOAP::WSDL::Service:
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
This is a developer release - everything may (and most things will) change.
|
This is a developer release - everything may (and most things will) change.
|
||||||
|
|
||||||
You should not expect the SOAP::WSDL to survive - it will probably be replaced
|
|
||||||
by SOAP::WSDL::Client.
|
|
||||||
+139
-47
@@ -8,7 +8,7 @@ use SOAP::WSDL::SAX::WSDLHandler;
|
|||||||
use base qw(SOAP::Lite);
|
use base qw(SOAP::Lite);
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
our $VERSION='2.00_04';
|
our $VERSION='2.00_05';
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
eval {
|
eval {
|
||||||
@@ -231,7 +231,7 @@ sub call {
|
|||||||
if (blessed $data
|
if (blessed $data
|
||||||
&& $data->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType'))
|
&& $data->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType'))
|
||||||
{
|
{
|
||||||
$envelope = SOAP::WSDL::Envelope->serialize( $method, $data , { readable => 1 });
|
$envelope = SOAP::WSDL::Envelope->serialize( $method, $data );
|
||||||
|
|
||||||
# TODO replace by something derived from binding - this is just a
|
# TODO replace by something derived from binding - this is just a
|
||||||
# workaround...
|
# workaround...
|
||||||
@@ -263,13 +263,12 @@ sub call {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if ( $self->no_dispatch() )
|
if ( $self->no_dispatch() ) {
|
||||||
{
|
return $envelope;
|
||||||
return $envelope;
|
} ## end if ( $self->no_dispatch...
|
||||||
} ## end if ( $self->no_dispatch...
|
|
||||||
|
|
||||||
# get response via transport layer
|
# get response via transport layer
|
||||||
# TODO remove dependency from SOAP::Lite and use a
|
# TODO remove dependency from SOAP::Lite and use a
|
||||||
# SAX-based filter using XML::LibXML to get the
|
# SAX-based filter using XML::LibXML to get the
|
||||||
# result.
|
# result.
|
||||||
# Filter should have the following methods:
|
# Filter should have the following methods:
|
||||||
@@ -279,14 +278,14 @@ sub call {
|
|||||||
# - fault: returns the result of the call if a SOAP fault is sent back
|
# - 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
|
# by the server. Retuns undef (nothing) if the call has been
|
||||||
# processed without errors.
|
# processed without errors.
|
||||||
my $response = $self->transport->send_receive(
|
my $response = $self->transport->send_receive(
|
||||||
context => $self, # this is provided for context
|
context => $self, # this is provided for context
|
||||||
endpoint => $self->endpoint(),
|
endpoint => $self->endpoint(),
|
||||||
action => $methodInfo->{ soap_action }, # SOAPAction from binding
|
action => $methodInfo->{ soap_action }, # SOAPAction from binding
|
||||||
envelope => $envelope, # use custom content
|
envelope => $envelope, # use custom content
|
||||||
);
|
);
|
||||||
|
|
||||||
return $response if ($self->outputxml() );
|
return $response if ($self->outputxml() );
|
||||||
|
|
||||||
if ($self->outputtree()) {
|
if ($self->outputtree()) {
|
||||||
|
|
||||||
@@ -336,30 +335,28 @@ sub call {
|
|||||||
return $handler->get_data();
|
return $handler->get_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
# deserialize and store result
|
# deserialize and store result
|
||||||
my $result = $self->{ '_call' } =
|
my $result = $self->{ '_call' } =
|
||||||
eval { $self->deserializer->deserialize( $response ) }
|
eval { $self->deserializer->deserialize( $response ) }
|
||||||
if $response;
|
if $response;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!$self->transport->is_success || # transport fault
|
!$self->transport->is_success || # transport fault
|
||||||
$@ || # not deserializible
|
$@ || # not deserializible
|
||||||
# fault message even if transport OK
|
# fault message even if transport OK
|
||||||
# or no transport error (for example, fo TCP, POP3, IO implementations)
|
# or no transport error (for example, fo TCP, POP3, IO implementations)
|
||||||
UNIVERSAL::isa( $result => 'SOAP::SOM' ) && $result->fault
|
UNIVERSAL::isa( $result => 'SOAP::SOM' ) && $result->fault
|
||||||
)
|
) {
|
||||||
{
|
return $self->{ '_call' } = (
|
||||||
return $self->{ '_call' } = (
|
$self->on_fault->( $self, ($@)
|
||||||
$self->on_fault->(
|
? $@ . ( $response || '' )
|
||||||
$self, $@ ? $@ . ( $response || '' ) : $result
|
: $result
|
||||||
)
|
) || $result
|
||||||
|| $result
|
);
|
||||||
);
|
} ## end if ( !$self->transport...
|
||||||
# ? # trick editors
|
|
||||||
} ## end if ( !$self->transport...
|
|
||||||
|
|
||||||
return unless $response; # nothing to do for one-ways
|
return unless $response; # nothing to do for one-ways
|
||||||
return $result;
|
return $result;
|
||||||
} ## end sub call
|
} ## end sub call
|
||||||
|
|
||||||
sub explain {
|
sub explain {
|
||||||
@@ -440,30 +437,114 @@ SOAP::Lite's transport mechanism.
|
|||||||
|
|
||||||
=head1 METHODS
|
=head1 METHODS
|
||||||
|
|
||||||
|
=head2 wsdlinit
|
||||||
|
|
||||||
|
Reads the WSDL file and initializes SOAP::WSDL for working with it.
|
||||||
|
|
||||||
|
Must be called after the wsdl URL has been set, and before calling one of
|
||||||
|
|
||||||
|
servicename
|
||||||
|
portname
|
||||||
|
call
|
||||||
|
|
||||||
|
You may set servicename and portname by passing them as attributes to
|
||||||
|
wsdlinit:
|
||||||
|
|
||||||
|
$soap->wsdlinit(
|
||||||
|
servicename => 'MyService',
|
||||||
|
portname => 'MyPort'
|
||||||
|
);
|
||||||
|
|
||||||
|
=head2 call
|
||||||
|
|
||||||
|
Performs a SOAP call. The result is either an object tree (with outputtree),
|
||||||
|
a hash reference (with outputhash), plain XML (with outputxml) or a SOAP::SOM
|
||||||
|
object (with neither of the above set).
|
||||||
|
|
||||||
|
my $result = $soap->call('method', %data);
|
||||||
|
|
||||||
|
=head1 CONFIGURATION METHODS
|
||||||
|
|
||||||
|
=head2 outputtree
|
||||||
|
|
||||||
|
When outputtree is set, SOAP::WSDL will return an object tree instead of a
|
||||||
|
SOAP::SOM object.
|
||||||
|
|
||||||
|
You have to specify a class_resolver for this to work. See
|
||||||
|
<class_resolver|class_resolver>
|
||||||
|
|
||||||
|
=head2 class_resolver
|
||||||
|
|
||||||
|
Set the class resolver class (or object).
|
||||||
|
|
||||||
|
Class resolvers must implement the method get_class which has to return the
|
||||||
|
name of the class name for deserializing a XML node at the current XPath
|
||||||
|
location.
|
||||||
|
|
||||||
|
Class resolvers are typically generated by using the to_typemap method on a
|
||||||
|
SOAP::WSDL::Definitions objects.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
XML structure (SOAP body content):
|
||||||
|
|
||||||
|
<Person>
|
||||||
|
<Name>Smith</Name>
|
||||||
|
<FirstName>John</FirstName>
|
||||||
|
</Person>
|
||||||
|
|
||||||
|
Class resolver
|
||||||
|
|
||||||
|
package MyResolver;
|
||||||
|
my %typemap = (
|
||||||
|
'Person' => 'MyPersonClass',
|
||||||
|
'Person/Name' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
||||||
|
'Person/FirstName' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
||||||
|
);
|
||||||
|
|
||||||
|
sub get_class { return $typemap{ $_[1] } };
|
||||||
|
1;
|
||||||
|
|
||||||
|
You'll need a MyPersonClass module in your search path for this to work - see
|
||||||
|
SOAP::WSDL::XSD::ComplexType on how to build / generate one.
|
||||||
|
|
||||||
=head2 servicename
|
=head2 servicename
|
||||||
|
|
||||||
$soap->servicname('Name');
|
$soap->servicename('Name');
|
||||||
|
|
||||||
Sets the service to operate on. If no service is set via servicename, the
|
Sets the service to operate on. If no service is set via servicename, the
|
||||||
first service found is used.
|
first service found is used.
|
||||||
|
|
||||||
|
Must be called after calling wsdlinit().
|
||||||
|
|
||||||
Returns the soap object, so you can chain calls like
|
Returns the soap object, so you can chain calls like
|
||||||
|
|
||||||
$soap->servicename->('Name')->portname('Port');
|
$soap->servicename->('Name')->portname('Port');
|
||||||
|
|
||||||
|
=head2 portname
|
||||||
|
|
||||||
|
$soap->portname('Name');
|
||||||
|
|
||||||
|
Sets the port to operate on. If no port is set via portname, the
|
||||||
|
first port found is used.
|
||||||
|
|
||||||
|
Must be called after calling wsdlinit().
|
||||||
|
|
||||||
|
Returns the soap object, so you can chain calls like
|
||||||
|
|
||||||
|
$soap->portname('Port')->call('MyMethod', %data);
|
||||||
|
|
||||||
|
=head2 no_dispatch
|
||||||
|
|
||||||
|
When set, call() returns the plain request XML instead of dispatching the
|
||||||
|
SOAP call to the SOAP service. Handy for testing/debugging.
|
||||||
|
|
||||||
=head2 _wsdl_init_methods
|
=head2 _wsdl_init_methods
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item DESCRIPTION
|
|
||||||
|
|
||||||
Creates a lookup table containing the information required for all methods
|
Creates a lookup table containing the information required for all methods
|
||||||
specified for the service/port selected.
|
specified for the service/port selected.
|
||||||
|
|
||||||
The lookup table is used by L<call|call>.
|
The lookup table is used by L<call|call>.
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
|
|
||||||
=head1 Differences to previous versions
|
=head1 Differences to previous versions
|
||||||
|
|
||||||
@@ -480,11 +561,22 @@ The object tree has two main functions: It knows how to serialize data passed
|
|||||||
as hash ref, and how to render the WSDL elements found into perl classes.
|
as hash ref, and how to render the WSDL elements found into perl classes.
|
||||||
|
|
||||||
Yup your're right, there's a builting code generation facility.
|
Yup your're right, there's a builting code generation facility.
|
||||||
|
|
||||||
|
=item * no_dispatch
|
||||||
|
|
||||||
|
call() with outputtxml set to true now returns the complete SOAP
|
||||||
|
envelope, not only the body's content.
|
||||||
|
|
||||||
=item * outputxml
|
=item * outputxml
|
||||||
|
|
||||||
call() with outputtxml set to true now returns the complete SOAP
|
call() with outputxml set to true now returns the complete SOAP
|
||||||
envelope, not only the body's content.
|
envelope, not only the body's content.
|
||||||
|
|
||||||
|
=item * servicename/portname
|
||||||
|
|
||||||
|
Both servicename and portname can only be called B<after> calling wsdlinit().
|
||||||
|
|
||||||
|
You may pass the servicename and portname as attributes to wsdlinit, though.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
+91
-27
@@ -3,11 +3,19 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use Carp;
|
use Carp;
|
||||||
use Class::Std::Storable;
|
use Class::Std::Storable;
|
||||||
|
use List::Util qw(first);
|
||||||
|
|
||||||
my %id_of :ATTR(:name<id> :default<()>);
|
my %id_of :ATTR(:name<id> :default<()>);
|
||||||
my %name_of :ATTR(:name<name> :default<()>);
|
my %name_of :ATTR(:name<name> :default<()>);
|
||||||
my %targetNamespace_of :ATTR(:name<targetNamespace> :default<()>);
|
my %targetNamespace_of :ATTR(:name<targetNamespace> :default<()>);
|
||||||
my %xmlns_of :ATTR(:name<xmlns> :default<{}>);
|
my %xmlns_of :ATTR(:name<xmlns> :default<{}>);
|
||||||
|
my %parent_of :ATTR(:name<parent> :default<()>);
|
||||||
|
|
||||||
|
sub DEMOLISH {
|
||||||
|
my $self = shift;
|
||||||
|
# delete upward references
|
||||||
|
delete $parent_of{ ident $self };
|
||||||
|
}
|
||||||
|
|
||||||
sub STORABLE_freeze_pre :CUMULATIVE {};
|
sub STORABLE_freeze_pre :CUMULATIVE {};
|
||||||
sub STORABLE_freeze_post :CUMULATIVE {};
|
sub STORABLE_freeze_post :CUMULATIVE {};
|
||||||
@@ -20,14 +28,18 @@ sub STORABLE_thaw_post :CUMULATIVE { return $_[0] };
|
|||||||
sub AUTOMETHOD {
|
sub AUTOMETHOD {
|
||||||
my ($self, $ident, @values) = @_;
|
my ($self, $ident, @values) = @_;
|
||||||
my $subname = $_; # Requested subroutine name is passed via $_
|
my $subname = $_; # Requested subroutine name is passed via $_
|
||||||
|
|
||||||
# we're called as $self->push_something(@values);
|
# we're called as $self->push_something(@values);
|
||||||
if ($subname =~s{^push_}{}xms) {
|
if ($subname =~s{^push_}{}xms) {
|
||||||
# we're not paranoid - we could be checking get_subname, too
|
|
||||||
my $getter = "get_$subname";
|
my $getter = "get_$subname";
|
||||||
my $setter = "set_$subname";
|
my $setter = "set_$subname";
|
||||||
croak "no set accessor found for push_$subname"
|
## Checking here is paranoid - will fail fatally if
|
||||||
if not ($self->can( $setter ));
|
## there is no setter...
|
||||||
|
## And we would have to check getters, too.
|
||||||
|
## Maybe do it the Conway way via the Symbol table...
|
||||||
|
## ... can is way slow...
|
||||||
|
# croak "no set accessor found for push_$subname"
|
||||||
|
# if not ($self->can( $setter ));
|
||||||
return sub {
|
return sub {
|
||||||
no strict qw(refs);
|
no strict qw(refs);
|
||||||
my $old_value = $self->$getter();
|
my $old_value = $self->$getter();
|
||||||
@@ -42,12 +54,11 @@ sub AUTOMETHOD {
|
|||||||
# we're called as $obj->find_something($ns, $key)
|
# we're called as $obj->find_something($ns, $key)
|
||||||
elsif ($subname =~s {^find_}{get_}xms) {
|
elsif ($subname =~s {^find_}{get_}xms) {
|
||||||
return sub {
|
return sub {
|
||||||
my @found_at = grep {
|
return first {
|
||||||
$_->get_targetNamespace() eq $values[0] &&
|
$_->get_targetNamespace() eq $values[0] &&
|
||||||
$_->get_name() eq $values[1]
|
$_->get_name() eq $values[1]
|
||||||
}
|
}
|
||||||
@{ $self->$subname() };
|
@{ $self->$subname() };
|
||||||
return $found_at[0];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif ($subname =~s {^first_}{get_}xms) {
|
elsif ($subname =~s {^first_}{get_}xms) {
|
||||||
@@ -61,45 +72,98 @@ sub AUTOMETHOD {
|
|||||||
croak "$subname not found in class " . (ref $self || $self);
|
croak "$subname not found in class " . (ref $self || $self);
|
||||||
}
|
}
|
||||||
|
|
||||||
#sub to_string :STRINGIFY {
|
|
||||||
# $_[0]->_DUMP();
|
|
||||||
#}
|
|
||||||
|
|
||||||
sub init {
|
sub init {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my @args = @_;
|
my @args = @_;
|
||||||
foreach my $value (@args)
|
foreach my $value (@args)
|
||||||
{
|
{
|
||||||
die $value if (not defined ($value->{ Name }));
|
die $value if (not defined ($value->{ Name }));
|
||||||
if ($value->{ Name } =~m{^xmlns\:}xms) {
|
if ($value->{ Name } =~m{^xmlns\:}xms) {
|
||||||
die $xmlns_of{ ident $self }
|
die $xmlns_of{ ident $self }
|
||||||
if ref $xmlns_of{ ident $self } ne 'HASH';
|
if ref $xmlns_of{ ident $self } ne 'HASH';
|
||||||
$xmlns_of{ ident $self }->{ $value->{ Value } } =
|
$xmlns_of{ ident $self }->{ $value->{ Value } } =
|
||||||
$value->{ LocalName };
|
$value->{ LocalName };
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
elsif ($value->{ Name } =~m{^xmlns$}xms) {
|
elsif ($value->{ Name } =~m{^xmlns$}xms) {
|
||||||
# just ignore xmlns = for now
|
# just ignore xmlns = for now
|
||||||
# TODO handle xmlns correctly - maybe via setting a prefix ?
|
# TODO handle xmlns correctly - maybe via setting a prefix ?
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
my $name = $value->{ LocalName };
|
my $name = $value->{ LocalName };
|
||||||
my $method = "set_$name";
|
my $method = "set_$name";
|
||||||
$self->$method( $value->{ Value } ) if ( $method );
|
$self->$method( $value->{ Value } ) if ( $method );
|
||||||
}
|
}
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub add_namespace {
|
sub add_namespace {
|
||||||
my ($self, $uri, $prefix ) = @_;
|
my ($self, $uri, $prefix ) = @_;
|
||||||
return unless $uri;
|
return unless $uri;
|
||||||
$self->{ namespace } ||= {};
|
$self->{ namespace } ||= {};
|
||||||
$self->{ namespace }->{ $uri } = $prefix;
|
$self->{ namespace }->{ $uri } = $prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub to_typemap {
|
sub to_typemap {
|
||||||
warn "to_typemap";
|
warn "to_typemap";
|
||||||
return q{};
|
return q{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub toClass {
|
||||||
|
my $self = shift;
|
||||||
|
warn 'toClass is deprecated and will be removed before reaching 2.01 - '
|
||||||
|
. 'use to_class instead (' . caller() . ')';
|
||||||
|
$self->to_class(@_);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub to_class {
|
||||||
|
my $self = shift;
|
||||||
|
my $opt = shift;
|
||||||
|
my $template = shift;
|
||||||
|
|
||||||
|
$opt->{ base_path } ||= '.';
|
||||||
|
|
||||||
|
my $element_prefix = $opt->{ element_prefix } || $opt->{ prefix };
|
||||||
|
my $type_prefix = $opt->{ type_prefix } || $opt->{ prefix };
|
||||||
|
|
||||||
|
if (($type_prefix) && ($type_prefix !~m{ :: $ }xms ) ) {
|
||||||
|
warn 'type_prefix should end with "::"';
|
||||||
|
$type_prefix .= '::';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($element_prefix) && ($element_prefix !~m{ :: $ }xms) ) {
|
||||||
|
warn 'element_prefix should end with "::"';
|
||||||
|
$element_prefix .= '::';
|
||||||
|
}
|
||||||
|
|
||||||
|
# Be careful: a Element may be ComplexType, too
|
||||||
|
# (but not vice versa)
|
||||||
|
my $prefix = $self->isa('SOAP::WSDL::XSD::Element')
|
||||||
|
? $element_prefix
|
||||||
|
: $type_prefix;
|
||||||
|
|
||||||
|
die 'No prefix specified' if not $prefix;
|
||||||
|
|
||||||
|
my $filename = $prefix . $self->get_name() . '.pm';
|
||||||
|
$filename =~s{::}{/}xmsg;
|
||||||
|
|
||||||
|
my $output = $opt->{ output } || $filename;
|
||||||
|
|
||||||
|
require Template;
|
||||||
|
my $tt = Template->new(
|
||||||
|
RELATIVE => 1,
|
||||||
|
OUTPUT_PATH => $opt->{ base_path },
|
||||||
|
);
|
||||||
|
|
||||||
|
my $code = $tt->process( \$template, {
|
||||||
|
element_prefix => $element_prefix,
|
||||||
|
type_prefix => $type_prefix,
|
||||||
|
self => $self,
|
||||||
|
nsmap => { reverse %{ $opt->{ wsdl }->get_xmlns() } },
|
||||||
|
structure => $self->explain( { wsdl => $opt->{ wsdl } } ),
|
||||||
|
},
|
||||||
|
$output
|
||||||
|
)
|
||||||
|
or die $tt->error();
|
||||||
|
}
|
||||||
1;
|
1;
|
||||||
|
|||||||
+50
-66
@@ -8,45 +8,44 @@ my %operation_of :ATTR(:name<operation> :default<()>);
|
|||||||
my %type_of :ATTR(:name<type> :default<()>);
|
my %type_of :ATTR(:name<type> :default<()>);
|
||||||
my %transport_of :ATTR(:name<transport> :default<()>);
|
my %transport_of :ATTR(:name<transport> :default<()>);
|
||||||
my %style_of :ATTR(:name<style> :default<()>);
|
my %style_of :ATTR(:name<style> :default<()>);
|
||||||
|
|
||||||
|
|
||||||
sub explain {
|
sub explain {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $opt = shift;
|
my $opt = shift;
|
||||||
my $name = $self->get_name();
|
my $name = $self->get_name();
|
||||||
|
|
||||||
my %ns_map = reverse %{ $opt->{ wsdl }->get_xmlns() };
|
die 'required atribute wsdl missing' if not $opt->{ wsdl };
|
||||||
|
|
||||||
my ($prefix, $localname) = split /:/ , $self->get_type();
|
|
||||||
my $portType = $opt->{ wsdl }->find_portType(
|
my $portType = $opt->{ wsdl }->find_portType(
|
||||||
$ns_map{ $prefix }, $localname
|
$opt->{ wsdl }->_expand( $self->get_type() )
|
||||||
) or die "portType $prefix:$localname not found !";
|
) or die 'portType not found: ' . $self->get_type();
|
||||||
|
|
||||||
|
my $txt = <<"EOT";
|
||||||
|
Transport: $transport_of{ ident $self }
|
||||||
|
|
||||||
|
=head2 METHODS
|
||||||
|
|
||||||
my $txt = <<"EOT";
|
B<Note:>
|
||||||
|
|
||||||
=head2 Binding name: $name
|
Input, output and fault messages are stated as perl hash refs.
|
||||||
|
|
||||||
=over
|
These are only for informational purposes - the actual implementation
|
||||||
|
may be object trees, not hash refs, though the input messages may be passed
|
||||||
=item * Style $style_of{ ident $self }
|
to the respective methods as hash refs and will be converted to object trees
|
||||||
|
automatically.
|
||||||
=item * Transport $transport_of{ ident $self }
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head3 Operations
|
|
||||||
|
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
foreach my $operation (@{ $self->get_operation() })
|
foreach my $operation (@{ $self->get_operation() }) {
|
||||||
{
|
|
||||||
my $operation_name = $operation->get_name();
|
my $operation_name = $operation->get_name();
|
||||||
my $operation_style = $operation->get_style() || q{};
|
my $operation_style = $operation->get_style() || q{};
|
||||||
|
|
||||||
my $port_operation = $portType->find_operation( $ns_map{ $prefix },
|
my ($port_operation) = grep { $_->get_name eq $operation_name }
|
||||||
$operation->get_name() )
|
@{ $portType->get_operation() }
|
||||||
or die "operation not found:" . $operation->get_name();
|
or die "operation not found:" . $operation->get_name();
|
||||||
|
|
||||||
# TODO rename lexical $input to "message"
|
# TODO rename lexical $input to "message"
|
||||||
my $input_message = do {
|
my $input_message = do {
|
||||||
my $input = $port_operation->first_input();
|
my $input = $port_operation->first_input();
|
||||||
@@ -60,70 +59,55 @@ EOT
|
|||||||
my $input = $port_operation->first_fault();
|
my $input = $port_operation->first_fault();
|
||||||
$input ? $input->explain($opt) : q{};
|
$input ? $input->explain($opt) : q{};
|
||||||
};
|
};
|
||||||
|
|
||||||
$txt .= <<"EOT";
|
$txt .= <<"EOT";
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item * $operation_name
|
=head3 $operation_name
|
||||||
|
|
||||||
=over 8
|
B<Input Message:>
|
||||||
|
|
||||||
=item * Style: $operation_style
|
|
||||||
|
|
||||||
=item * Input Message:
|
|
||||||
|
|
||||||
$input_message
|
$input_message
|
||||||
|
|
||||||
=item * Output Message:
|
B<Output Message:>
|
||||||
|
|
||||||
$output_message
|
$output_message
|
||||||
|
|
||||||
=item * Fault:
|
B<Fault:>
|
||||||
|
|
||||||
$fault_message
|
$fault_message
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
EOT
|
EOT
|
||||||
}
|
}
|
||||||
|
|
||||||
return $txt;
|
return $txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub to_typemap {
|
sub to_typemap {
|
||||||
my ($self, $opt) = @_;
|
my ($self, $opt) = @_;
|
||||||
my $name = $self->get_name();
|
my $name = $self->get_name();
|
||||||
my %ns_map = reverse %{ $opt->{ wsdl }->get_xmlns() };
|
|
||||||
my ($prefix, $localname) = split /:/ , $self->get_type();
|
|
||||||
my $portType = $opt->{ wsdl }->find_portType(
|
my $portType = $opt->{ wsdl }->find_portType(
|
||||||
$ns_map{ $prefix }, $localname
|
$opt->{ wsdl }->_expand( $self->get_type )
|
||||||
) or die "portType $prefix:$localname not found !";
|
) or die 'portType not found: ' . $self->get_type;
|
||||||
|
|
||||||
my $txt = q{};
|
my $txt = q{};
|
||||||
foreach my $operation (@{ $self->get_operation() })
|
foreach my $operation (@{ $self->get_operation() })
|
||||||
{
|
{
|
||||||
my $operation_name = $operation->get_name();
|
my $operation_name = $operation->get_name();
|
||||||
my $operation_style = $operation->get_style() || q{};
|
my $operation_style = $operation->get_style() || q{};
|
||||||
|
|
||||||
my $port_operation = $portType->find_operation( $ns_map{ $prefix },
|
my ($port_operation) = grep { $_->get_name eq $operation_name }
|
||||||
$operation->get_name() )
|
@{ $portType->get_operation() }
|
||||||
or die "operation not found:" . $operation->get_name();
|
or die "operation not found:" . $operation->get_name();
|
||||||
|
|
||||||
# TODO rename lexical $input to "message"
|
no strict qw(refs);
|
||||||
$txt .= do {
|
$txt .= join q{},
|
||||||
my $input = $port_operation->first_input();
|
map {
|
||||||
$input ? $input->to_typemap($opt) : q{};
|
my $message = $port_operation->$_;
|
||||||
};
|
$message
|
||||||
$txt .= do {
|
? $message->to_typemap($opt)
|
||||||
my $input = $port_operation->first_output();
|
: q{}
|
||||||
$input ? $input->to_typemap($opt) : q{};
|
} qw(first_input first_output first_fault);
|
||||||
};
|
|
||||||
$txt .= do {
|
|
||||||
my $input = $port_operation->first_fault();
|
|
||||||
$input ? $input->to_typemap($opt) : q{};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return $txt;
|
return $txt;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-23
@@ -1,11 +1,12 @@
|
|||||||
package SOAP::WSDL::Client;
|
package SOAP::WSDL::Client;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use Carp;
|
||||||
use Scalar::Util qw(blessed);
|
use Scalar::Util qw(blessed);
|
||||||
use SOAP::WSDL::Envelope;
|
use SOAP::WSDL::Envelope;
|
||||||
use SOAP::Lite;
|
use SOAP::Lite;
|
||||||
use Class::Std::Storable;
|
use Class::Std::Storable;
|
||||||
use SOAP::WSDL::SAX::MessageHandler;
|
use SOAP::WSDL::Expat::MessageParser;
|
||||||
use SOAP::WSDL::SOAP::Typelib::Fault11;
|
use SOAP::WSDL::SOAP::Typelib::Fault11;
|
||||||
|
|
||||||
# Package globals for speed...
|
# Package globals for speed...
|
||||||
@@ -13,9 +14,9 @@ my $PARSER;
|
|||||||
my $MESSAGE_HANDLER;
|
my $MESSAGE_HANDLER;
|
||||||
|
|
||||||
my %class_resolver_of :ATTR(:name<class_resolver> :default<()>);
|
my %class_resolver_of :ATTR(:name<class_resolver> :default<()>);
|
||||||
my %no_dispatch_of :ATTR(:name<no_dispatch> :default<()>);
|
my %no_dispatch_of :ATTR(:name<no_dispatch> :default<()>);
|
||||||
my %outputxml_of :ATTR(:name<outputxml> :default<()>);
|
my %outputxml_of :ATTR(:name<outputxml> :default<()>);
|
||||||
my %proxy_of :ATTR(:name<proxy> :default<()>);
|
my %proxy_of :ATTR(:name<proxy> :default<()>);
|
||||||
|
|
||||||
# TODO remove when preparing 2.01
|
# TODO remove when preparing 2.01
|
||||||
sub outputtree { warn 'outputtree is deprecated and'
|
sub outputtree { warn 'outputtree is deprecated and'
|
||||||
@@ -37,19 +38,7 @@ SUBFACTORY: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
eval {
|
$PARSER = SOAP::WSDL::Expat::MessageParser->new();
|
||||||
require XML::LibXML;
|
|
||||||
$PARSER = XML::LibXML->new();
|
|
||||||
$MESSAGE_HANDLER = SOAP::WSDL::SAX::MessageHandler->new();
|
|
||||||
$PARSER->set_handler( $MESSAGE_HANDLER );
|
|
||||||
};
|
|
||||||
if ($@) {
|
|
||||||
require XML::SAX::ParserFactory;
|
|
||||||
$MESSAGE_HANDLER = SOAP::WSDL::SAX::MessageHandler->new({
|
|
||||||
base => 'XML::SAX::Base' });
|
|
||||||
$PARSER = XML::SAX::ParserFactory->parser(
|
|
||||||
handler => $MESSAGE_HANDLER );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub call {
|
sub call {
|
||||||
@@ -94,19 +83,24 @@ sub call {
|
|||||||
);
|
);
|
||||||
|
|
||||||
# warn 'Received ' . length($response) . ' bytes of content';
|
# warn 'Received ' . length($response) . ' bytes of content';
|
||||||
|
|
||||||
return $response if ($self->outputxml() );
|
return $response if ($self->outputxml() );
|
||||||
|
|
||||||
$MESSAGE_HANDLER->set_class_resolver( $self->get_class_resolver() );
|
$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
|
# or if transport layer failed
|
||||||
if (! $soap->transport->is_success() ) {
|
if (! $soap->transport->is_success() ) {
|
||||||
# Try deserializing response - there may be some
|
# Try deserializing response - there may be some
|
||||||
if ($response) {
|
if ($response) {
|
||||||
eval { $PARSER->parse_string( $response ) };
|
eval { $PARSER->parse( $response ); };
|
||||||
return $MESSAGE_HANDLER->get_data if not $@;
|
if ($@) {
|
||||||
|
warn "could not deserialize response: $@";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $MESSAGE_HANDLER->get_data();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
require SOAP::WSDL::SOAP::Typelib::Fault11;
|
require SOAP::WSDL::SOAP::Typelib::Fault11;
|
||||||
# generate & return fault if we cannot serialize response
|
# generate & return fault if we cannot serialize response
|
||||||
@@ -118,7 +112,7 @@ sub call {
|
|||||||
. $soap->transport->message()
|
. $soap->transport->message()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
eval { $PARSER->parse_string( $response ) };
|
eval { $PARSER->parse( $response ) };
|
||||||
|
|
||||||
# return fault if we cannot deserialize response
|
# return fault if we cannot deserialize response
|
||||||
if ($@) {
|
if ($@) {
|
||||||
@@ -130,7 +124,7 @@ sub call {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return $MESSAGE_HANDLER->get_data();
|
return $PARSER->get_data();
|
||||||
} ## end sub call
|
} ## end sub call
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
+322
-31
@@ -1,6 +1,10 @@
|
|||||||
package SOAP::WSDL::Definitions;
|
package SOAP::WSDL::Definitions;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use Carp;
|
||||||
|
use File::Basename;
|
||||||
|
use File::Path;
|
||||||
|
use List::Util qw(first);
|
||||||
use Class::Std::Storable;
|
use Class::Std::Storable;
|
||||||
use base qw(SOAP::WSDL::Base);
|
use base qw(SOAP::WSDL::Base);
|
||||||
|
|
||||||
@@ -9,11 +13,10 @@ my %message_of :ATTR(:name<message> :default<()>);
|
|||||||
my %portType_of :ATTR(:name<portType> :default<()>);
|
my %portType_of :ATTR(:name<portType> :default<()>);
|
||||||
my %binding_of :ATTR(:name<binding> :default<()>);
|
my %binding_of :ATTR(:name<binding> :default<()>);
|
||||||
my %service_of :ATTR(:name<service> :default<()>);
|
my %service_of :ATTR(:name<service> :default<()>);
|
||||||
|
my %namespace_of :ATTR(:name<namespace> :default<()>);
|
||||||
my %namespace_of :ATTR(:name<namespace> :default<()>);
|
|
||||||
|
# must be attr for Class::Std::Storable
|
||||||
my %attributes_of :ATTR();
|
my %attributes_of :ATTR();
|
||||||
|
|
||||||
%attributes_of = (
|
%attributes_of = (
|
||||||
binding => \%binding_of,
|
binding => \%binding_of,
|
||||||
message => \%message_of,
|
message => \%message_of,
|
||||||
@@ -23,40 +26,328 @@ my %attributes_of :ATTR();
|
|||||||
|
|
||||||
# Function factory - we could be writing this method for all %attribute
|
# Function factory - we could be writing this method for all %attribute
|
||||||
# keys, too, but that's just C&P (eehm, Copy & Paste...)
|
# keys, too, but that's just C&P (eehm, Copy & Paste...)
|
||||||
foreach my $method(keys %attributes_of ) {
|
BLOCK: {
|
||||||
no strict qw/refs/;
|
no strict qw/refs/;
|
||||||
|
foreach my $method(keys %attributes_of ) {
|
||||||
# ... btw, we mean this method here...
|
|
||||||
*{ "find_$method" } = sub {
|
*{ "find_$method" } = sub {
|
||||||
my ($self, @args) = @_;
|
my ($self, @args) = @_;
|
||||||
my @found_at = grep {
|
return first {
|
||||||
$_->get_targetNamespace() eq $args[0] &&
|
$_->get_targetNamespace() eq $args[0]
|
||||||
$_->get_name() eq $args[1]
|
&& $_->get_name() eq $args[1]
|
||||||
}
|
}
|
||||||
@{ $attributes_of{ $method }->{ ident $self } };
|
@{ $attributes_of{ $method }->{ ident $self } };
|
||||||
return $found_at[0];
|
};
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub explain {
|
sub explain {
|
||||||
my $self = shift;
|
|
||||||
my $opt = shift;
|
|
||||||
my $txt = '';
|
|
||||||
foreach my $service (@{ $self->get_service() })
|
|
||||||
{
|
|
||||||
$txt .= $service->explain( $opt );
|
|
||||||
$txt .= "\n";
|
|
||||||
}
|
|
||||||
return $txt;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub to_typemap {
|
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $opt = shift;
|
my $opt = shift;
|
||||||
$opt->{ wsdl } ||= $self;
|
$opt->{ wsdl } ||= $self;
|
||||||
|
$opt->{ namespace } ||= $self->get_xmlns() || {};
|
||||||
|
my $txt = '';
|
||||||
|
|
||||||
|
for my $service (@{ $self->get_service() }) {
|
||||||
|
$txt .= $service->explain( $opt );
|
||||||
|
$txt .= "\n";
|
||||||
|
}
|
||||||
|
return $txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _expand {
|
||||||
|
my ($self, $prefix, $localname) = ($_[0], split /:/, $_[1]);
|
||||||
|
my %ns_map = reverse %{ $self->get_xmlns() };
|
||||||
|
return ($ns_map{ $prefix }, $localname);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub to_typemap {
|
||||||
|
my $self = shift;
|
||||||
|
my $opt = shift;
|
||||||
$opt->{ prefix } ||= q{};
|
$opt->{ prefix } ||= q{};
|
||||||
|
$opt->{ wsdl } ||= $self;
|
||||||
|
$opt->{ type_prefix } ||= $opt->{ prefix };
|
||||||
|
$opt->{ element_prefix } ||= $opt->{ prefix };
|
||||||
return join "\n",
|
return join "\n",
|
||||||
map { $_->to_typemap( $opt ) } @{ $service_of{ ident $self } };
|
map { $_->to_typemap( $opt ) } @{ $service_of{ ident $self } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub create_interface {
|
||||||
|
my $self = shift;
|
||||||
|
my $opt = shift;
|
||||||
|
|
||||||
|
my $base_path = $opt->{ base_path }
|
||||||
|
or croak "missing or empty argument base_path";
|
||||||
|
$opt->{ prefix } ||= q{};
|
||||||
|
$opt->{ type_prefix } ||= $opt->{ prefix };
|
||||||
|
$opt->{ element_prefix } ||= $opt->{ prefix };
|
||||||
|
$opt->{ typemap_prefix } or die 'Required argument typemap_prefix missing';
|
||||||
|
|
||||||
|
mkpath $base_path;
|
||||||
|
|
||||||
|
for my $service (@{ $service_of{ ident $self } }) {
|
||||||
|
warn "creating typemap $opt->{ typemap_prefix }". $service->get_name() . "\n";
|
||||||
|
$self->_create_typemap({ %{ $opt }, service => $service });
|
||||||
|
}
|
||||||
|
|
||||||
|
my @schema = @{ $self->first_types()->get_schema() };
|
||||||
|
for my $type (map { @{ $_->get_type() } , @{ $_->get_element() } } @schema[1..$#schema] ) {
|
||||||
|
warn 'creating class for '. $type->get_name() . "\n";
|
||||||
|
$type->to_class( { %$opt, wsdl => $self } );
|
||||||
|
}
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _create_typemap {
|
||||||
|
my $self = shift;
|
||||||
|
my $opt = shift;
|
||||||
|
my $service_name = $opt->{ service }->get_name();
|
||||||
|
my $file_name = "$opt->{ base_path }/$opt->{ typemap_prefix }/$service_name.pm";
|
||||||
|
$file_name =~s{::}{/}gms;
|
||||||
|
my $path = dirname $file_name;
|
||||||
|
my $name = basename $file_name;
|
||||||
|
|
||||||
|
my $typemap = $opt->{ service }->to_typemap( { %{ $opt }, wsdl => $self } );
|
||||||
|
|
||||||
|
my $template = <<'EOT';
|
||||||
|
package [% typemap_prefix %][% service.get_name %];
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
my %typemap = (
|
||||||
|
[% typemap %]
|
||||||
|
[% custom_types %]
|
||||||
|
);
|
||||||
|
|
||||||
|
sub get_class {
|
||||||
|
my $name = join '/', @{ $_[1] };
|
||||||
|
exists $typemap{ $name } or die "Cannot resolve $name via " . __PACKAGE__;
|
||||||
|
return $typemap{ $name };
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
EOT
|
||||||
|
|
||||||
|
require Template;
|
||||||
|
my $tt = Template->new(
|
||||||
|
OUTPUT_PATH => $path,
|
||||||
|
);
|
||||||
|
$tt->process(\$template, { %{ $opt }, typemap => $typemap }, $name)
|
||||||
|
or die $tt->error();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
SOAP::WSDL::Definitions - model a WSDL E<gt>definitionsE<lt> element
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
=head2 first_service get_service set_service push_service
|
||||||
|
|
||||||
|
Accessors/Mutators for accessing / setting the E<gt>serviceE<lt> child
|
||||||
|
element(s).
|
||||||
|
|
||||||
|
=head2 find_service
|
||||||
|
|
||||||
|
Returns the service matching the namespace/localname pair passed as arguments.
|
||||||
|
|
||||||
|
my $service = $wsdl->find_service($namespace, $localname);
|
||||||
|
|
||||||
|
=head2 first_binding get_binding set_binding push_binding
|
||||||
|
|
||||||
|
Accessors/Mutators for accessing / setting the E<gt>bindingE<lt> child
|
||||||
|
element(s).
|
||||||
|
|
||||||
|
=head2 find_service
|
||||||
|
|
||||||
|
Returns the binding matching the namespace/localname pair passed as arguments.
|
||||||
|
|
||||||
|
my $binding = $wsdl->find_binding($namespace, $localname);
|
||||||
|
|
||||||
|
=head2 first_portType get_portType set_portType push_portType
|
||||||
|
|
||||||
|
Accessors/Mutators for accessing / setting the E<gt>portTypeE<lt> child
|
||||||
|
element(s).
|
||||||
|
|
||||||
|
=head2 find_portType
|
||||||
|
|
||||||
|
Returns the portType matching the namespace/localname pair passed as arguments.
|
||||||
|
|
||||||
|
my $portType = $wsdl->find_portType($namespace, $localname);
|
||||||
|
|
||||||
|
=head2 first_message get_message set_message push_message
|
||||||
|
|
||||||
|
Accessors/Mutators for accessing / setting the E<gt>messageE<lt> child
|
||||||
|
element(s).
|
||||||
|
|
||||||
|
=head2 find_service
|
||||||
|
|
||||||
|
Returns the message matching the namespace/localname pair passed as arguments.
|
||||||
|
|
||||||
|
my $message = $wsdl->find_message($namespace, $localname);
|
||||||
|
|
||||||
|
=head2 first_types get_types set_types push_types
|
||||||
|
|
||||||
|
Accessors/Mutators for accessing / setting the E<gt>typesE<lt> child
|
||||||
|
element(s).
|
||||||
|
|
||||||
|
=head2 explain
|
||||||
|
|
||||||
|
Returns a POD string describing how to call the methods of the service(s)
|
||||||
|
described in the WSDL.
|
||||||
|
|
||||||
|
=head2 to_typemap
|
||||||
|
|
||||||
|
Creates a typemap for use with a generated type class library.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
NAME DESCRIPTION
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
prefix Prefix to use for all classes
|
||||||
|
type_prefix Prefix to use for all (Complex/Simple)Type classes
|
||||||
|
element_prefix Prefix to use for all Element classes (with atomic types)
|
||||||
|
|
||||||
|
As some webservices tend to use globally unique type definitions, but
|
||||||
|
locally unique elements with atomic types, type and element classes may
|
||||||
|
be separated by specifying type_prefix and element_prefix instead of
|
||||||
|
prefix.
|
||||||
|
|
||||||
|
The typemap is plain text which can be used as snipped for building a
|
||||||
|
SOAP::WSDL class_resolver perl class.
|
||||||
|
|
||||||
|
Try something like this for creating typemap classes:
|
||||||
|
|
||||||
|
my $parser = XML::LibXML->new();
|
||||||
|
my $handler = SOAP::WSDL::SAX::WSDLHandler->new()
|
||||||
|
$parser->set_handler( $handler );
|
||||||
|
|
||||||
|
$parser->parse_url('file:///path/to/wsdl');
|
||||||
|
|
||||||
|
my $wsdl = $handler->get_data();
|
||||||
|
my $typemap = $wsdl->to_typemap();
|
||||||
|
|
||||||
|
print <<"EOT"
|
||||||
|
package MyTypemap;
|
||||||
|
my \%typemap = (
|
||||||
|
$typemap
|
||||||
|
);
|
||||||
|
sub get_class { return \$typemap{\$_[1] } };
|
||||||
|
1;
|
||||||
|
"EOT"
|
||||||
|
|
||||||
|
=head2 create_interface
|
||||||
|
|
||||||
|
Creates a typemap class, classes for all types and elements, and interface
|
||||||
|
classes for every service.
|
||||||
|
|
||||||
|
See L<CODE GENERATOR|CODE GENERATOR> below.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
Name Description
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
prefix Prefix to use for types and elements. Should end with '::'.
|
||||||
|
element_prefix Prefix to use for element packages. Should end with '::'.
|
||||||
|
Must be specified if prefix is not given.
|
||||||
|
type_prefix Prefix to use for type packages. Should end with '::'.
|
||||||
|
Must be specified if prefix is not given.
|
||||||
|
typemap_prefix Prefix to use for type packages. Should end with '::'.
|
||||||
|
Mandatory.
|
||||||
|
custom_types A perl source code snippet defining custom types for the
|
||||||
|
class resolver (typemap).
|
||||||
|
Must look like this:
|
||||||
|
q{
|
||||||
|
'path/to/my/element' => 'My::Element',
|
||||||
|
'path/to/my/element/prop' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
||||||
|
'path/to/my/element/prop2' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
||||||
|
};
|
||||||
|
|
||||||
|
=head2 _expand
|
||||||
|
|
||||||
|
Expands a qualified name into a list consisting of namespace URI and
|
||||||
|
localname by using the definition's xmlns table.
|
||||||
|
|
||||||
|
Used internally by SOAP::WSDL::* classes.
|
||||||
|
|
||||||
|
=head1 CODE GENERATOR
|
||||||
|
|
||||||
|
TODO: move somewhere else - maybe SOAP::WSDL::Client ?
|
||||||
|
|
||||||
|
SOAP::WSDL::Definitions features a code generation facility for generating
|
||||||
|
perl classes (packages) from a WSDL definition.
|
||||||
|
|
||||||
|
The following classes are generated:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item * Typemaps
|
||||||
|
|
||||||
|
A typemap class is created for every service.
|
||||||
|
|
||||||
|
Typemaps are basically lookup classes. They allow the
|
||||||
|
SOAP::WSDL::SAX::MessageHandler to find out which class a XML element
|
||||||
|
in a SOAP message shoud be processed as.
|
||||||
|
|
||||||
|
Typemaps are passed to SOAP::WSDL::Client via the class_resolver
|
||||||
|
method.
|
||||||
|
|
||||||
|
=item * Interfaces
|
||||||
|
|
||||||
|
TODO: Implement Interface generation
|
||||||
|
|
||||||
|
Interface classes are just convenience shortcuts for accessing web
|
||||||
|
service methods. They define a method for every web service method,
|
||||||
|
dispatching the request to SOAP::WSDL::Client.
|
||||||
|
|
||||||
|
=item * Type and Element classes
|
||||||
|
|
||||||
|
For every top-level E<lt>elementE<gt>, E<lt>complexTypeE<gt> and
|
||||||
|
E<lt>simpleTypeE<gt> definition in the WSDL's schema, a perl class is
|
||||||
|
created.
|
||||||
|
|
||||||
|
Classes for E<lt>complexTypeE<gt> and E<lt>simpleTypeE<gt> definitions
|
||||||
|
are prefixed by the C<type_prefix> argument passed to
|
||||||
|
L<create_interface|create_interface>, classes for E<lt>elementE<gt>
|
||||||
|
definitions are prefixed by the C<element_prefix> passed to
|
||||||
|
L<create_interface|create_interface>. If the specific prefixes are not
|
||||||
|
specified, the C<prefix> argument is used instead.
|
||||||
|
|
||||||
|
If your web service is part of a bigger framework which defines types
|
||||||
|
globally, you probably do well always using the same C<type_prefix>:
|
||||||
|
This reduces the number of classes generated (provided types
|
||||||
|
are re-used by more than one service).
|
||||||
|
|
||||||
|
You probably should use different element prefixes, though -
|
||||||
|
E<lt>elementE<gt> definitions tend to be unique in the defining WSDL
|
||||||
|
only, especially when using document/literal style/encoding.
|
||||||
|
|
||||||
|
If not, you probably want to specify just C<prefix> (and use a
|
||||||
|
different one for every web service).
|
||||||
|
|
||||||
|
=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>
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
package SOAP::WSDL::Expat::MessageParser;
|
||||||
|
use strict;
|
||||||
|
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 $self = {
|
||||||
|
class_resolver => $args->{ class_resolver }
|
||||||
|
};
|
||||||
|
bless $self, $class;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub class_resolver {
|
||||||
|
my $self = shift;
|
||||||
|
$self->{ class_resolver } = shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub parse {
|
||||||
|
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::Expat->new();
|
||||||
|
|
||||||
|
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 };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$parser->parse( $xml );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_data {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{ 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.
|
||||||
|
|
||||||
|
=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: $
|
||||||
|
$LastChangedRevision: $
|
||||||
|
$LastChangedBy: $
|
||||||
|
|
||||||
|
$HeadURL: $
|
||||||
|
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
package SOAP::WSDL::Expat::MessageStreamParser;
|
||||||
|
use strict;
|
||||||
|
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 $self = {
|
||||||
|
class_resolver => shift->{ class_resolver }
|
||||||
|
};
|
||||||
|
bless $self, $class;
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub class_resolver {
|
||||||
|
my $self = shift;
|
||||||
|
$self->{ class_resolver } = shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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 get_data {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->{ data };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
SOAP::WSDL::Expat::MessageStreamParser - Convert SOAP messages to custom object trees
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
my $lwp = LWP::UserAgent->new();
|
||||||
|
|
||||||
|
my $parser = SOAP::WSDL::Expat::MessageParser->new({
|
||||||
|
class_resolver => 'My::Resolver'
|
||||||
|
});
|
||||||
|
my $chunk_parser = $parser->init();
|
||||||
|
# process response while it comes in, trying to read 32k chunks.
|
||||||
|
$lwp->request( $request, sub { $chunk_parser->parse_more($_[0]) } , 32468 );
|
||||||
|
$chunk_parser->parse_done();
|
||||||
|
|
||||||
|
my $obj = $parser->get_data();
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
ExpatNB based parser for parsing huge documents.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
=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: $
|
||||||
|
$LastChangedRevision: $
|
||||||
|
$LastChangedBy: $
|
||||||
|
|
||||||
|
$HeadURL: $
|
||||||
|
|
||||||
@@ -29,17 +29,14 @@ sub explain
|
|||||||
);
|
);
|
||||||
|
|
||||||
for my $part(@{ $message->[0]->get_part() }) {
|
for my $part(@{ $message->[0]->get_part() }) {
|
||||||
$opt->{ indent } .= "\t";
|
|
||||||
$txt .= $part->explain($opt);
|
$txt .= $part->explain($opt);
|
||||||
$opt->{ indent } =~s/\t//;
|
|
||||||
$txt .= $opt->{ indent } . "\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ($self->use())
|
if ($self->use())
|
||||||
{
|
{
|
||||||
$txt .= $opt->{ indent } . "$name use: " . $self->use(). "\n";
|
$txt .= " $name use: " . $self->use(). "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $txt;
|
return $txt;
|
||||||
|
|||||||
@@ -0,0 +1,213 @@
|
|||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item * WSDL definitions
|
||||||
|
|
||||||
|
=item * SOAP messages
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 Parser implementations
|
||||||
|
|
||||||
|
There are different parser implementations available for SOAP messages -
|
||||||
|
currently there's only one for WSDL definitions.
|
||||||
|
|
||||||
|
=head2 WSDL definitions parser
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item * SOAP::WSDL::SAX::WSDLHandler
|
||||||
|
|
||||||
|
This is a SAX handler for parsing WSDL files into object trees SOAP::WSDL
|
||||||
|
works with.
|
||||||
|
|
||||||
|
It's built as a native handler for XML::LibXML, but will also work with
|
||||||
|
XML::SAX::ParserFactory.
|
||||||
|
|
||||||
|
To parse a WSDL file, use one of the following variants:
|
||||||
|
|
||||||
|
my $parser = XML::LibXML->new();
|
||||||
|
my $handler = SOAP::WSDL::SAX::WSDLHandler->new();
|
||||||
|
$parser->set_handler( $handler );
|
||||||
|
$parser->parse( $xml );
|
||||||
|
my $data = $handler->get_data();
|
||||||
|
|
||||||
|
|
||||||
|
my $handler = SOAP::WSDL::SAX::WSDLHandler->new({
|
||||||
|
base => 'XML::SAX::Base'
|
||||||
|
});
|
||||||
|
my $parser = XML::SAX::ParserFactor->parser(
|
||||||
|
Handler => $handler
|
||||||
|
);
|
||||||
|
$parser->parse( $xml );
|
||||||
|
my $data = $handler->get_data();
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head2 SOAP messages parser
|
||||||
|
|
||||||
|
All SOAP message handler use class resolvers for finding out which class
|
||||||
|
a particular XML element should be of and type libs containing these classes.
|
||||||
|
|
||||||
|
=head3 Writing a class resolver
|
||||||
|
|
||||||
|
The class resolver must returned a method "get_class", which is passed a list
|
||||||
|
ref of the current element's XPath (relative to Body), split by /.
|
||||||
|
|
||||||
|
This method must return a class name appropriate for a XML element.
|
||||||
|
|
||||||
|
A class resolver package might look like this:
|
||||||
|
|
||||||
|
package FakeResolver;
|
||||||
|
|
||||||
|
my %class_list = (
|
||||||
|
'EnqueueMessage' => 'Typelib::TEnqueueMessage',
|
||||||
|
'EnqueueMessage/MMessage' => 'Typelib::TMessage',
|
||||||
|
'EnqueueMessage/MMessage/MRecipientURI' => 'SOAP::WSDL::XSD::Builtin::anyURI',
|
||||||
|
'EnqueueMessage/MMessage/MMessageContent' => 'SOAP::WSDL::XSD::Builtin::string',
|
||||||
|
);
|
||||||
|
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
1;
|
||||||
|
|
||||||
|
=head3 Writing type library classes
|
||||||
|
|
||||||
|
Every element must have a correspondent one in the type library.
|
||||||
|
|
||||||
|
Type library classes must provide the following methods:
|
||||||
|
|
||||||
|
Builtin types should be resolved as SOAP::WSDL::XSD::Builtin::* classes
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item * new
|
||||||
|
|
||||||
|
Constructor
|
||||||
|
|
||||||
|
=item * add_FOO
|
||||||
|
|
||||||
|
The add_FOO method is called for every child element of the XML node.
|
||||||
|
|
||||||
|
Characters are regarded as child element of the last XML node.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
A tyelib class implemented as Inside-Out object using Class::Std::Storable
|
||||||
|
as base class would look like this:
|
||||||
|
|
||||||
|
package Typelib::TEnqueueMessage;
|
||||||
|
use strict;
|
||||||
|
use Class::Std::Storable;
|
||||||
|
|
||||||
|
my %MMessage_of :ATTR(:name<MMessage> :default<()>);
|
||||||
|
|
||||||
|
sub add_MMessage {
|
||||||
|
my ($self, $value) = @_;
|
||||||
|
my $ident = ident $self;
|
||||||
|
|
||||||
|
# we're the first value
|
||||||
|
return $MMessage_of{ $ident } = $value
|
||||||
|
if not defined $MMessage_of{ $ident };
|
||||||
|
|
||||||
|
# we're the second value
|
||||||
|
return $MMessage_of{ $ident } = [
|
||||||
|
$MMessage_of{ $ident }, $value ]
|
||||||
|
if not ref $MMessage_of{ $ident } eq 'ARRAY';
|
||||||
|
|
||||||
|
# we're third or later
|
||||||
|
push @{ $MMessage_of{ $ident } }, $value;
|
||||||
|
return $MMessage_of{ $ident };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1;
|
||||||
|
|
||||||
|
Of course one could use a method factory for these add_FOO methods - see
|
||||||
|
t/lib/Typelib/Base.pm for an example.
|
||||||
|
|
||||||
|
=head3 Parser implementations
|
||||||
|
|
||||||
|
=over
|
||||||
|
|
||||||
|
=item * SOAP::WSDL::SAX::MessageHandler
|
||||||
|
|
||||||
|
This is a SAX handler for parsing WSDL files into object trees SOAP::WSDL
|
||||||
|
works with.
|
||||||
|
|
||||||
|
It's built as a native handler for XML::LibXML, but will also work with
|
||||||
|
XML::SAX::ParserFactory.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
SOAP::WSDL::Expat::MessageParser is the fastest way of parsing SOAP messages
|
||||||
|
into object trees and only slightly slower than converting them into hash
|
||||||
|
data structures:
|
||||||
|
|
||||||
|
Parsing a SOAP message with a length of 5962 bytes:
|
||||||
|
SOAP::WSDL::Expat::MessageParser:
|
||||||
|
3 wallclock secs ( 3.28 usr + 0.05 sys = 3.33 CPU) @ 60.08/s (n=200)
|
||||||
|
|
||||||
|
SOAP::WSDL::SAX::MessageHandler (with raw XML::LibXML):
|
||||||
|
5 wallclock secs ( 4.95 usr + 0.00 sys = 4.95 CPU) @ 40.38/s (n=200)
|
||||||
|
|
||||||
|
XML::Simple (XML::Parser):
|
||||||
|
3 wallclock secs ( 2.36 usr + 0.03 sys = 2.39 CPU) @ 83.65/s (n=200)
|
||||||
|
|
||||||
|
XML::Simple (XML::SAX::Expat):
|
||||||
|
7 wallclock secs ( 6.50 usr + 0.03 sys = 6.53 CPU) @ 30.62/s (n=200)
|
||||||
|
|
||||||
|
As the benchmark shows, all SOAP::WSDL parser variants are faster than
|
||||||
|
XML::Simple with XML::SAX::Expat, and SOAP::WSDL::Expat::MessageParser almost
|
||||||
|
reaches the performance of XML::Simple with XML::Parser as backend.
|
||||||
|
|
||||||
|
Parsing SOAP responses in chunks does not increase speed - at least not up
|
||||||
|
to a response size of around 500k:
|
||||||
|
|
||||||
|
Benchmark: timing 5 iterations of SOAP::WSDL::SAX::MessageHandler,
|
||||||
|
SOAP::WSDL::Expat::MessageParser, SOAP::WSDL::Expat::MessageStreamParser...
|
||||||
|
|
||||||
|
SOAP::WSDL::Expat::MessageStreamParser:
|
||||||
|
13 wallclock secs ( 7.39 usr + 0.09 sys = 7.48 CPU) @ 0.67/s (n=5)
|
||||||
|
|
||||||
|
SOAP::WSDL::Expat::MessageParser:
|
||||||
|
10 wallclock secs ( 5.81 usr + 0.06 sys = 5.88 CPU) @ 0.85/s (n=5)
|
||||||
|
|
||||||
|
SOAP::WSDL::SAX::MessageHandler:
|
||||||
|
14 wallclock secs ( 8.78 usr + 0.03 sys = 8.81 CPU) @ 0.57/s (n=5)
|
||||||
|
|
||||||
|
Response size: 344330 bytes
|
||||||
|
|
||||||
|
=cut
|
||||||
+32
-41
@@ -1,6 +1,7 @@
|
|||||||
package SOAP::WSDL::Part;
|
package SOAP::WSDL::Part;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use Carp qw(croak);
|
||||||
use Class::Std::Storable;
|
use Class::Std::Storable;
|
||||||
|
|
||||||
use base qw(SOAP::WSDL::Base);
|
use base qw(SOAP::WSDL::Base);
|
||||||
@@ -20,20 +21,20 @@ sub serialize
|
|||||||
my $item_name;
|
my $item_name;
|
||||||
if ($item_name = $self->get_type() ) {
|
if ($item_name = $self->get_type() ) {
|
||||||
# resolve type
|
# resolve type
|
||||||
my ($prefix, $localname) = split /:/ , $item_name, 2;
|
my ($prefix, $localname) = split /:/ , $item_name, 2;
|
||||||
my $type = $typelib->find_type( $ns_map{ $prefix }, $localname )
|
my $type = $typelib->find_type( $ns_map{ $prefix }, $localname )
|
||||||
or die "type $item_name , $ns_map{ $prefix } not found";
|
or die "type $item_name , $ns_map{ $prefix } not found";
|
||||||
|
|
||||||
my $name = $self->get_name();
|
my $name = $self->get_name();
|
||||||
return $type->serialize( $name, $data->{ $name }, $opt );
|
return $type->serialize( $name, $data->{ $name }, $opt );
|
||||||
}
|
}
|
||||||
elsif ( $item_name = $self->get_element() ) {
|
elsif ( $item_name = $self->get_element() ) {
|
||||||
my ($prefix, $localname) = split /:/ , $item_name, 2;
|
my ($prefix, $localname) = split /:/ , $item_name, 2;
|
||||||
my $element = $typelib->find_element(
|
my $element = $typelib->find_element(
|
||||||
$ns_map{ $prefix },
|
$ns_map{ $prefix },
|
||||||
$localname
|
$localname
|
||||||
)
|
)
|
||||||
or die "element $item_name , $ns_map{ $prefix } not found";
|
or die "element $item_name , $ns_map{ $prefix } not found";
|
||||||
$opt->{ qualify } = 1;
|
$opt->{ qualify } = 1;
|
||||||
return $element->serialize( undef, $data->{ $element->get_name() }, $opt );
|
return $element->serialize( undef, $data->{ $element->get_name() }, $opt );
|
||||||
}
|
}
|
||||||
@@ -41,54 +42,44 @@ sub serialize
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub explain {
|
sub explain {
|
||||||
my ($self, $opt, $name ) = @_;
|
my ($self, $opt, $name ) = @_;
|
||||||
my $typelib = $opt->{ wsdl }->first_types()
|
my $typelib = $opt->{ wsdl }->first_types() || die "No typelib";
|
||||||
|| die "No typelib";
|
my $element = $self->get_type() || $self->get_element();
|
||||||
|
|
||||||
my %ns_map = reverse %{ $opt->{ namespace } };
|
# resolve type
|
||||||
my $element = $self->get_type() || $self->get_element();
|
my $type = $typelib->find_type( $opt->{ wsdl }->_expand( $element ) )
|
||||||
|
|| $typelib->find_element( $opt->{ wsdl }->_expand( $element ) );
|
||||||
|
|
||||||
# resolve type
|
if (not $type)
|
||||||
my ($prefix, $localname) = split /:/ , $element;
|
{
|
||||||
my $type = $typelib->find_type(
|
warn "no type/element $element found for part " . $self->get_name();
|
||||||
$ns_map{ $prefix },
|
return q{};
|
||||||
$localname
|
}
|
||||||
)
|
return " {\n" . $type->explain( $opt, $self->get_name() ) . " }\n";
|
||||||
|| $typelib->find_element(
|
|
||||||
$ns_map{ $prefix },
|
|
||||||
$localname
|
|
||||||
);
|
|
||||||
|
|
||||||
if (not $type)
|
|
||||||
{
|
|
||||||
warn "no type/element $element ({ $ns_map{ $prefix } }$localname) found for part " . $self->get_name();
|
|
||||||
return q{};
|
|
||||||
}
|
|
||||||
return $type->explain( $opt, $self->get_name() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub to_typemap {
|
sub to_typemap {
|
||||||
my ($self, $opt, $name ) = @_;
|
my ($self, $opt, $name ) = @_;
|
||||||
my $txt = q{};
|
my $txt = q{};
|
||||||
|
my $wsdl = $opt->{ wsdl };
|
||||||
my $typelib = $opt->{ wsdl }->first_types()
|
my $typelib = $opt->{ wsdl }->first_types()
|
||||||
|| die "No typelib";
|
|| die "No typelib";
|
||||||
|
|
||||||
my %ns_map = reverse %{ $opt->{ wsdl }->get_xmlns() };
|
|
||||||
my $element = $self->get_type() || $self->get_element();
|
|
||||||
|
|
||||||
# resolve type
|
# resolve type
|
||||||
my ($prefix, $localname) = split /:/ , $element;
|
|
||||||
my $type;
|
my $type;
|
||||||
if ($type = $typelib->find_type( $ns_map{ $prefix }, $localname ) ) {
|
if (my $type_name = $self->get_type()) {
|
||||||
$txt .= "'/' => " . $type->get_name() . "\n";
|
$type = $typelib->find_type( $wsdl->_expand( $type_name ) )
|
||||||
|
|| croak "no type/element $type_name found for part " . $self->get_name();
|
||||||
|
$txt .= "q{} => " . $type->get_name() . "\n";
|
||||||
|
}
|
||||||
|
elsif ( my $element_name = $self->get_element() ) {
|
||||||
|
$type = $typelib->find_element( $wsdl->_expand( $element_name ) )
|
||||||
|
|| croak "no type/element $element_name found for part " . $self->get_name();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$type = $typelib->find_element( $ns_map{ $prefix }, $localname );
|
warn 'neither type nor element - do not know what to do for part '
|
||||||
}
|
. $self->get_name();
|
||||||
|
return q{};
|
||||||
if (not $type) {
|
|
||||||
warn "no type/element $element ({ $ns_map{ $prefix } }$localname) found for part " . $self->get_name();
|
|
||||||
return q{};
|
|
||||||
}
|
}
|
||||||
$opt->{ path } = [];
|
$opt->{ path } = [];
|
||||||
$txt .= $type->to_typemap( $opt, $self->get_name() );
|
$txt .= $type->to_typemap( $opt, $self->get_name() );
|
||||||
|
|||||||
+15
-18
@@ -8,26 +8,23 @@ my %binding_of :ATTR(:name<binding> :default<()>);
|
|||||||
my %location_of :ATTR(:name<location> :default<()>);
|
my %location_of :ATTR(:name<location> :default<()>);
|
||||||
|
|
||||||
sub explain {
|
sub explain {
|
||||||
my $self = shift;
|
|
||||||
my $opt = shift;
|
|
||||||
my $txt =
|
|
||||||
"=head2 Port name: " . $self->get_name() . "\n\n"
|
|
||||||
. "=over\n\n"
|
|
||||||
. "=item * Binding: " . $self->get_binding() ."\n\n"
|
|
||||||
. "=item * Location: " . $self->get_location() ."\n\n"
|
|
||||||
. "=back\n\n";
|
|
||||||
# if ( $self->location() );
|
|
||||||
|
|
||||||
my %ns_map = reverse %{ $opt->{ namespace } };
|
my $self = shift;
|
||||||
|
my $opt = shift;
|
||||||
|
$opt->{ wsdl } || die 'required attribute wsdl missing';
|
||||||
|
|
||||||
|
my $binding = $opt->{ wsdl }->find_binding(
|
||||||
|
$opt->{ wsdl }->_expand( $self->get_binding() )
|
||||||
|
) or die 'binding ' . $self->get_binding() . ' not found !';
|
||||||
|
|
||||||
|
|
||||||
|
my $txt = "=head2 Service information:\n\n"
|
||||||
|
. " Port name: " . $self->get_name() . "\n"
|
||||||
|
. " Binding: " . $self->get_binding() ."\n"
|
||||||
|
. " Location: " . $self->get_location() ."\n"
|
||||||
|
. $binding->explain($opt);
|
||||||
|
|
||||||
my ($prefix, $localname) = split /:/ , $self->get_binding();
|
return $txt;
|
||||||
my $binding = $opt->{ wsdl }->find_binding(
|
|
||||||
$ns_map{ $prefix }, $localname
|
|
||||||
) or die "binding $prefix:$localname not found !";
|
|
||||||
|
|
||||||
$txt .= $binding->explain($opt);
|
|
||||||
|
|
||||||
return $txt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub to_typemap {
|
sub to_typemap {
|
||||||
|
|||||||
@@ -76,6 +76,11 @@ my %data_of :ATTR(:default<()>);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub class_resolver {
|
||||||
|
my $self = shift;
|
||||||
|
$class_resolver_of{ ident $self } = shift;
|
||||||
|
}
|
||||||
|
|
||||||
sub start_document {
|
sub start_document {
|
||||||
my $ident = ident $_[0];
|
my $ident = ident $_[0];
|
||||||
$list_of{ $ident } = [];
|
$list_of{ $ident } = [];
|
||||||
@@ -114,11 +119,17 @@ sub start_element {
|
|||||||
# TODO replace with UNIVERSAL->isa()
|
# TODO replace with UNIVERSAL->isa()
|
||||||
# match is a bit faster if the string does not match, but WAY slower
|
# match is a bit faster if the string does not match, but WAY slower
|
||||||
# if $class matches...
|
# if $class matches...
|
||||||
# if (not $class=~m{^SOAP::WSDL::XSD::Typelib::Builtin}xms) {
|
# if (not $class=~m{^SOAP::WSDL::XSD::Typelib::Builtin}xms) {
|
||||||
|
|
||||||
if (index $class, 'SOAP::WSDL::XSD::Typelib::Builtin', 0 < 0) {
|
if (index $class, 'SOAP::WSDL::XSD::Typelib::Builtin', 0 < 0) {
|
||||||
eval "require $class" ## no critic qw(ProhibitStringyEval)
|
|
||||||
or die $@;
|
# 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
|
||||||
|
no strict qw(refs);
|
||||||
|
*{ "$class\::new" }{ CODE }
|
||||||
|
or eval "require $class" ## no critic qw(ProhibitStringyEval)
|
||||||
|
or die $@;
|
||||||
}
|
}
|
||||||
# create object
|
# create object
|
||||||
# set current object
|
# set current object
|
||||||
@@ -223,121 +234,18 @@ SOAP::WSDL::SAX::MessageHandler - Convert SOAP messages to custom object trees
|
|||||||
class_resolver => FakeResolver->new(),
|
class_resolver => FakeResolver->new(),
|
||||||
base => 'XML::SAX::Base',
|
base => 'XML::SAX::Base',
|
||||||
), "Object creation");
|
), "Object creation");
|
||||||
my $parser = XML::LibXML->new();
|
my $parser = XML::SAX::ParserFactor->parser(
|
||||||
$parser->set_handler( $filter );
|
Handler => $handler
|
||||||
|
);
|
||||||
$parser->parse_string( $soap_message );
|
$parser->parse_string( $soap_message );
|
||||||
|
|
||||||
my $object_tree = $filter->get_data();
|
my $object_tree = $filter->get_data();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
Parses a SOAP message into an object tree.
|
SAX handler for parsing SOAP messages.
|
||||||
|
|
||||||
For every element in the SOAP message, an object is created. The class
|
See L<SOAP::WSDL::Parser> for details.
|
||||||
of the object is determined via a Resolver object which has to be passed
|
|
||||||
to new via the class_resolver parameter.
|
|
||||||
|
|
||||||
=head1 Writing a class resolver
|
|
||||||
|
|
||||||
The class resolver must returned a method "get_class", which is passed a list
|
|
||||||
ref of the current element's XPath (relative to Body), split by /.
|
|
||||||
|
|
||||||
This method must return a class name appropriate for a XML element.
|
|
||||||
|
|
||||||
A class resolver package might look like this:
|
|
||||||
|
|
||||||
package FakeResolver;
|
|
||||||
|
|
||||||
my %class_list = (
|
|
||||||
'EnqueueMessage' => 'Typelib::TEnqueueMessage',
|
|
||||||
'EnqueueMessage/MMessage' => 'Typelib::TMessage',
|
|
||||||
'EnqueueMessage/MMessage/MRecipientURI' => 'SOAP::WSDL::XSD::Builtin::anyURI',
|
|
||||||
'EnqueueMessage/MMessage/MMessageContent' => 'SOAP::WSDL::XSD::Builtin::string',
|
|
||||||
);
|
|
||||||
|
|
||||||
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";
|
|
||||||
};
|
|
||||||
1;
|
|
||||||
|
|
||||||
=head1 Writing type library classes
|
|
||||||
|
|
||||||
Every element must have a correspondent one in the type library.
|
|
||||||
|
|
||||||
Type library classes must provide the following methods:
|
|
||||||
|
|
||||||
Builtin types should be resolved as SOAP::WSDL::XSD::Builtin::* classes
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item * new
|
|
||||||
|
|
||||||
Constructor
|
|
||||||
|
|
||||||
=item * add_FOO
|
|
||||||
|
|
||||||
The add_FOO method is called for every child element of the XML node.
|
|
||||||
|
|
||||||
Characters are regarded as child element of the last XML node.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
A tyelib class implemented as Inside-Out object using Class::Std::Storable
|
|
||||||
as base class would look like this:
|
|
||||||
|
|
||||||
package Typelib::TEnqueueMessage;
|
|
||||||
use strict;
|
|
||||||
use Class::Std::Storable;
|
|
||||||
|
|
||||||
my %MMessage_of :ATTR(:name<MMessage> :default<()>);
|
|
||||||
|
|
||||||
sub add_MMessage {
|
|
||||||
my ($self, $value) = @_;
|
|
||||||
my $ident = ident $self;
|
|
||||||
|
|
||||||
# we're the first value
|
|
||||||
return $MMessage_of{ $ident } = $value
|
|
||||||
if not defined $MMessage_of{ $ident };
|
|
||||||
|
|
||||||
# we're the second value
|
|
||||||
return $MMessage_of{ $ident } = [
|
|
||||||
$MMessage_of{ $ident }, $value ]
|
|
||||||
if not ref $MMessage_of{ $ident } eq 'ARRAY';
|
|
||||||
|
|
||||||
# we're third or later
|
|
||||||
push @{ $MMessage_of{ $ident } }, $value;
|
|
||||||
return $MMessage_of{ $ident };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1;
|
|
||||||
|
|
||||||
Of course one could use a method factory for these add_FOO methods - see
|
|
||||||
t/lib/Typelib/Base.pm for an example.
|
|
||||||
|
|
||||||
=head1 Performance
|
|
||||||
|
|
||||||
SOAP::WSDL::SAX::MessageHandler with a raw XML::LibXML parser almost reaches
|
|
||||||
the performance of XML::Simple with XML::Parser (and expat) as low-level
|
|
||||||
parser.
|
|
||||||
|
|
||||||
And SOAP::WSDL::SAX::MessageHandler builds up a object tree, while
|
|
||||||
XML::Simple just emits hash data structures:
|
|
||||||
|
|
||||||
SOAP::WSDL::SAX::MessageHandler:
|
|
||||||
1 wallclock secs ( 1.39 usr + 0.00 sys = 1.39 CPU) @ 719.42/s (n=1000)
|
|
||||||
|
|
||||||
XML::Simple:
|
|
||||||
2 wallclock secs ( 1.25 usr + 0.01 sys = 1.26 CPU) @ 790.51/s (n=1000)
|
|
||||||
|
|
||||||
If you know a faster way for parsing XML with a reasonable simple API than
|
|
||||||
XML::LibXML, please let me know...
|
|
||||||
|
|
||||||
=head1 Bugs and Limitations
|
=head1 Bugs and Limitations
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package SOAP::WSDL::SAX::WSDLHandler;
|
package SOAP::WSDL::SAX::WSDLHandler;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Carp;
|
use Carp;
|
||||||
@@ -19,10 +19,10 @@ my %current_of :ATTR(:name<current> :default<()>);
|
|||||||
my $class = shift;
|
my $class = shift;
|
||||||
my $self = {}; # $class->SUPER::new(@_);
|
my $self = {}; # $class->SUPER::new(@_);
|
||||||
my $args = shift || {};
|
my $args = shift || {};
|
||||||
|
|
||||||
die "arguments to new must be single hash ref"
|
die "arguments to new must be single hash ref"
|
||||||
if @_ or ! ref $args eq 'HASH';
|
if @_ or ! ref $args eq 'HASH';
|
||||||
|
|
||||||
# nasty, but for those who want to use XML::SAX::Base or similar
|
# nasty, but for those who want to use XML::SAX::Base or similar
|
||||||
# as parser factory
|
# as parser factory
|
||||||
if ($args->{base}) {
|
if ($args->{base}) {
|
||||||
@@ -34,34 +34,34 @@ my %current_of :ATTR(:name<current> :default<()>);
|
|||||||
# ...we ignore em all...
|
# ...we ignore em all...
|
||||||
no strict qw(refs);
|
no strict qw(refs);
|
||||||
foreach my $method ( qw(
|
foreach my $method ( qw(
|
||||||
characters
|
characters
|
||||||
processing_instruction
|
processing_instruction
|
||||||
ignorable_whitespace
|
ignorable_whitespace
|
||||||
set_document_locator
|
set_document_locator
|
||||||
start_prefix_mapping
|
start_prefix_mapping
|
||||||
end_prefix_mapping
|
end_prefix_mapping
|
||||||
skipped_entity
|
skipped_entity
|
||||||
start_cdata
|
start_cdata
|
||||||
end_cdata
|
end_cdata
|
||||||
comment
|
comment
|
||||||
entity_reference
|
entity_reference
|
||||||
notation_decl
|
notation_decl
|
||||||
unparsed_entity_decl
|
unparsed_entity_decl
|
||||||
element_decl
|
element_decl
|
||||||
attlist_decl
|
attlist_decl
|
||||||
doctype_decl
|
doctype_decl
|
||||||
xml_decl
|
xml_decl
|
||||||
entity_decl
|
entity_decl
|
||||||
attribute_decl
|
attribute_decl
|
||||||
internal_entity_decl
|
internal_entity_decl
|
||||||
external_entity_decl
|
external_entity_decl
|
||||||
resolve_entity
|
resolve_entity
|
||||||
start_dtd
|
start_dtd
|
||||||
end_dtd
|
end_dtd
|
||||||
start_entity
|
start_entity
|
||||||
end_entity
|
end_entity
|
||||||
warning
|
warning
|
||||||
error
|
error
|
||||||
) ) {
|
) ) {
|
||||||
*{ "$method" } = sub {};
|
*{ "$method" } = sub {};
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ my %current_of :ATTR(:name<current> :default<()>);
|
|||||||
};
|
};
|
||||||
|
|
||||||
sub start_document {
|
sub start_document {
|
||||||
my ($self, $ident) = ($_[0], ident $_[0]);
|
my $ident = ident $_[0];
|
||||||
$tree_of{ $ident } = {};
|
$tree_of{ $ident } = {};
|
||||||
$order_of{ $ident } = [];
|
$order_of{ $ident } = [];
|
||||||
$targetNamespace_of{ $ident } = undef;
|
$targetNamespace_of{ $ident } = undef;
|
||||||
@@ -80,69 +80,63 @@ sub start_document {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub start_element {
|
sub start_element {
|
||||||
my ($self, $element) = @_;
|
my ($self, $element) = @_;
|
||||||
my $ident = ident $self;
|
my $ident = ident $self;
|
||||||
|
|
||||||
my $action = SOAP::WSDL::TypeLookup->lookup(
|
my $action = SOAP::WSDL::TypeLookup->lookup(
|
||||||
$element->{ NamespaceURI },
|
$element->{ NamespaceURI },
|
||||||
$element->{ LocalName }
|
$element->{ LocalName }
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($action)
|
return if not $action;
|
||||||
{
|
|
||||||
if ($action->{ type } eq 'CLASS')
|
if ($action->{ type } eq 'CLASS') {
|
||||||
{
|
eval "require $action->{ class }";
|
||||||
eval "require $action->{ class }";
|
croak $@, $tree_of{ $ident } if ($@);
|
||||||
croak $@, $tree_of{ $ident } if ($@);
|
|
||||||
|
|
||||||
my $class = $action->{ class };
|
my $class = $action->{ class };
|
||||||
my $obj = $class->new()->init(
|
my $obj = $class->new({ parent => $current_of{ $ident } })->init(
|
||||||
values %{ $element->{ Attributes } }
|
values %{ $element->{ Attributes } }
|
||||||
);
|
);
|
||||||
|
|
||||||
# set element in parent
|
# set element in parent
|
||||||
if ($current_of{ $ident })
|
if ($current_of{ $ident }) {
|
||||||
{
|
# inherit namespace, but don't override
|
||||||
# inherit namespace, but don't override
|
$obj->set_targetNamespace(
|
||||||
$obj->set_targetNamespace(
|
$current_of{ $ident }->get_targetNamespace() )
|
||||||
$current_of{ $ident }->get_targetNamespace() )
|
if not $obj->get_targetNamespace();
|
||||||
if not $obj->get_targetNamespace();
|
|
||||||
|
|
||||||
# push on name list
|
# push on name list
|
||||||
my $method = "push_$element->{ LocalName }";
|
my $method = "push_$element->{ LocalName }";
|
||||||
no strict qw(refs);
|
no strict qw(refs);
|
||||||
$current_of{ $ident }->$method( $obj );
|
$current_of{ $ident }->$method( $obj );
|
||||||
|
|
||||||
# remember element for stepping back
|
# remember element for stepping back
|
||||||
push @{ $order_of{ $ident } }, $current_of{ $ident };
|
push @{ $order_of{ $ident } }, $current_of{ $ident };
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
$tree_of{ $ident } = $obj;
|
||||||
$tree_of{ $ident } = $obj;
|
}
|
||||||
}
|
# set new element (step down)
|
||||||
# set new element (step down)
|
$current_of{ $ident } = $obj;
|
||||||
$current_of{ $ident } = $obj;
|
}
|
||||||
}
|
elsif ($action->{ type } eq 'PARENT') {
|
||||||
elsif ($action->{ type } eq 'PARENT')
|
$current_of{ $ident }->init( values %{ $element->{ Attributes } } );
|
||||||
{
|
}
|
||||||
$current_of{ $ident }->init( values %{ $element->{ Attributes } } );
|
elsif ($action->{ type } eq 'METHOD') {
|
||||||
}
|
my $method = $action->{ method } || $element->{ LocalName };
|
||||||
elsif ($action->{ type } eq 'METHOD')
|
|
||||||
{
|
no strict qw(refs);
|
||||||
my $method = $action->{ method } || $element->{ LocalName };
|
# call method with
|
||||||
|
# - default value ($action->{ value } if defined,
|
||||||
no strict qw(refs);
|
# dereferencing lists
|
||||||
# call method with
|
# - the values of the elements Attributes hash
|
||||||
# - default value ($action->{ value } if defined,
|
$current_of{ $ident }->$method( defined $action->{ value }
|
||||||
# dereferencing lists
|
? ref $action->{ value }
|
||||||
# - the values of the elements Attributes hash
|
? @{ $action->{ value } }
|
||||||
$current_of{ $ident }->$method( defined $action->{ value }
|
: ($action->{ value })
|
||||||
? ref $action->{ value }
|
: values %{ $element->{ Attributes } } );
|
||||||
? @{ $action->{ value } }
|
}
|
||||||
: ($action->{ value })
|
|
||||||
: values %{ $element->{ Attributes } } );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub end_element {
|
sub end_element {
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ use base qw(
|
|||||||
my %faultcode_of :ATTR(:get<faultcode>);
|
my %faultcode_of :ATTR(:get<faultcode>);
|
||||||
my %faultstring_of :ATTR(:get<faultstring>);
|
my %faultstring_of :ATTR(:get<faultstring>);
|
||||||
my %faultactor_of :ATTR(:get<faultactor>);
|
my %faultactor_of :ATTR(:get<faultactor>);
|
||||||
my %detail_of :ATTR(:get<faultdetail>);
|
my %detail_of :ATTR(:get<detail>);
|
||||||
|
|
||||||
# always return false in boolean context - a fault is never true...
|
# always return false in boolean context - a fault is never true...
|
||||||
sub as_bool :BOOLIFY { return; }
|
sub as_bool :BOOLIFY { return; }
|
||||||
|
|
||||||
__PACKAGE__->_factory(
|
__PACKAGE__->_factory(
|
||||||
[ qw(faultcode faultstring faultactor faultdetail) ],
|
[ qw(faultcode faultstring faultactor detail) ],
|
||||||
{
|
{
|
||||||
faultcode => \%faultcode_of,
|
faultcode => \%faultcode_of,
|
||||||
faultstring => \%faultstring_of,
|
faultstring => \%faultstring_of,
|
||||||
@@ -44,4 +44,57 @@ __PACKAGE__->__set_minOccurs();
|
|||||||
__PACKAGE__->__set_maxOccurs();
|
__PACKAGE__->__set_maxOccurs();
|
||||||
__PACKAGE__->__set_ref('');
|
__PACKAGE__->__set_ref('');
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
SOAP::WSDL::SOAP::Typelib::Fault11 - SOAP 1.1 Fault class
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Models a SOAP 1.1 Fault.
|
||||||
|
|
||||||
|
SOAP::WSDL::SOAP::Typelib::Fault11 objects are false in boolean context
|
||||||
|
and serialize to XML on stringification.
|
||||||
|
|
||||||
|
This means you can do something like:
|
||||||
|
|
||||||
|
my $soap = SOAP::WSDL::Client->new();
|
||||||
|
# ...
|
||||||
|
my $result = $soap->call($method, $data);
|
||||||
|
if (not $result) {
|
||||||
|
die "Error calling SOAP method: ", $result->get_faultstring();
|
||||||
|
}
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
=head2 get_faultcode / set_faultcode
|
||||||
|
|
||||||
|
Getter/setter for object's the faultcode property.
|
||||||
|
|
||||||
|
=head2 get_faultstring / set_faultstring
|
||||||
|
|
||||||
|
Getter/setter for object's the faultstring property.
|
||||||
|
|
||||||
|
=head2 get_faultactor / set_faultactor
|
||||||
|
|
||||||
|
Getter/setter for object's the faultactor property.
|
||||||
|
|
||||||
|
=head2 get_detail / set_detail
|
||||||
|
|
||||||
|
Getter/setter for detail object's detail property.
|
||||||
|
|
||||||
|
=head1 LICENSE
|
||||||
|
|
||||||
|
Copyright 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>
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ my %port_of :ATTR(:name<port> :default<()>);
|
|||||||
sub explain {
|
sub explain {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $opt = shift;
|
my $opt = shift;
|
||||||
my $txt ="=head1 Service name\n\n" . $self->get_name() . "\n\n";
|
my $txt ="=head1 Service " . $self->get_name() . "\n\n";
|
||||||
foreach my $port (@{ $self->get_port() } )
|
foreach my $port (@{ $self->get_port() } )
|
||||||
{
|
{
|
||||||
$txt .= $port->explain( $opt );
|
$txt .= $port->explain( $opt );
|
||||||
@@ -23,5 +23,10 @@ sub to_typemap {
|
|||||||
return join "\n",
|
return join "\n",
|
||||||
map { $_->to_typemap( $opt ) } @{ $port_of{ ident $self } };
|
map { $_->to_typemap( $opt ) } @{ $port_of{ ident $self } };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO implement to_class as class generator for a (complete) interface
|
||||||
|
sub to_class {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -57,8 +57,7 @@ sub init {
|
|||||||
$self->SUPER::init( @args );
|
$self->SUPER::init( @args );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub serialize
|
sub serialize {
|
||||||
{
|
|
||||||
my ($self, $name, $value, $opt) = @_;
|
my ($self, $name, $value, $opt) = @_;
|
||||||
|
|
||||||
$opt->{ indent } ||= q{};
|
$opt->{ indent } ||= q{};
|
||||||
@@ -74,7 +73,7 @@ sub serialize
|
|||||||
|
|
||||||
|
|
||||||
$xml .= join q{ } , "<$name" , @{ $opt->{ attributes } };
|
$xml .= join q{ } , "<$name" , @{ $opt->{ attributes } };
|
||||||
delete $opt->{ attributes }; # don't propagate...
|
delete $opt->{ attributes }; # don't propagate...
|
||||||
|
|
||||||
if ( $opt->{ autotype }) {
|
if ( $opt->{ autotype }) {
|
||||||
my $ns = $self->get_targetNamespace();
|
my $ns = $self->get_targetNamespace();
|
||||||
@@ -120,39 +119,38 @@ sub serialize
|
|||||||
return $xml;
|
return $xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub explain
|
sub explain {
|
||||||
{
|
my ($self, $opt, $name ) = @_;
|
||||||
my ($self, $opt, $name ) = @_;
|
my $flavor = $self->get_flavor();
|
||||||
my $flavor = $self->get_flavor();
|
|
||||||
my $xml = '';
|
|
||||||
$xml .= $opt->{ indent } if ($opt->{ readable }); # add indentation
|
|
||||||
$xml .= q{'} . $name . q{' => };
|
|
||||||
|
|
||||||
return q{} if not $flavor; # empty complexType
|
$name ||= q{};
|
||||||
|
|
||||||
if ( ($flavor eq "sequence") or ($flavor eq "all") )
|
return q{} if not $flavor; # empty complexType
|
||||||
{
|
$opt->{ indent } ||= q{ };
|
||||||
$xml .= "{\n";
|
my $xml = q{};
|
||||||
$opt->{ indent } .= "\t";
|
$xml .= "$opt->{indent}\'$name'=> " if $name;
|
||||||
|
|
||||||
|
if ( ($flavor eq "sequence") or ($flavor eq "all") ) {
|
||||||
|
$xml .= "{\n";
|
||||||
|
$opt->{ indent } .= " ";
|
||||||
$xml .= join q{}, map { $_->explain( $opt ) }
|
$xml .= join q{}, map { $_->explain( $opt ) }
|
||||||
@{ $self->get_element() };
|
@{ $self->get_element() };
|
||||||
$opt->{ indent } =~s/\t$//; # step back
|
$opt->{ indent } =~s/\s{2}$//; # step back
|
||||||
$xml .= $opt->{ indent } . "},\n";
|
$xml .= "$opt->{ indent }},\n";
|
||||||
}
|
}
|
||||||
elsif ($flavor eq "complexContent")
|
elsif ($flavor eq "complexContent")
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
elsif ($flavor eq "simpleContent")
|
elsif ($flavor eq "simpleContent")
|
||||||
{
|
{
|
||||||
|
warn "found unsupported complexType definition $flavor";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
warn "unknown complexType definition $flavor";
|
warn "found unsupported complexType definition $flavor";
|
||||||
}
|
}
|
||||||
$xml .= "\n" if ($opt->{ readable } ); # add linebreak
|
return $xml;
|
||||||
return $xml;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub to_typemap {
|
sub to_typemap {
|
||||||
@@ -172,12 +170,12 @@ sub to_typemap {
|
|||||||
return $txt;
|
return $txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub toClass {
|
sub to_class {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $opt = shift;
|
my $opt = shift;
|
||||||
|
|
||||||
my $template = <<'EOT';
|
my $template = <<'EOT';
|
||||||
package [% class_prefix %]::[% self.get_name %];
|
package [% type_prefix %][% self.get_name %];
|
||||||
use strict;
|
use strict;
|
||||||
use Class::Std::Storable;
|
use Class::Std::Storable;
|
||||||
use SOAP::WSDL::XSD::Typelib::ComplexType;
|
use SOAP::WSDL::XSD::Typelib::ComplexType;
|
||||||
@@ -194,19 +192,38 @@ __PACKAGE__->_factory(
|
|||||||
[% element.get_name %]
|
[% element.get_name %]
|
||||||
[% END %]) ],
|
[% END %]) ],
|
||||||
{
|
{
|
||||||
[% FOREACH element=self.get_element %] [% element.get_name %] => \%[% element.get_name %]_of,
|
[% FOREACH element=self.get_element %][% element.get_name %] => \%[% element.get_name %]_of,
|
||||||
[% END %]
|
[% END %]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
[%- FOREACH element=self.get_element;
|
[%-
|
||||||
split_name = element.get_type.split(':');
|
FOREACH element=self.get_element;
|
||||||
prefix = split_name.0;
|
IF (element.get_type);
|
||||||
localname = split_name.1;
|
split_name = element.get_type.split(':');
|
||||||
IF nsmap.$prefix == 'http://www.w3.org/2001/XMLSchema' -%]
|
prefix = split_name.0;
|
||||||
[% element.get_name %] => 'SOAP::WSDL::XSD::Typelib::Builtin::[% localname %]',
|
localname = split_name.1;
|
||||||
[% ELSE %]
|
IF nsmap.$prefix == 'http://www.w3.org/2001/XMLSchema' -%]
|
||||||
[% element.get_name %] => '[% class_prefix %]::[% localname %]',
|
[% element.get_name %] => 'SOAP::WSDL::XSD::Typelib::Builtin::[% localname %]',
|
||||||
[%- END;
|
[% ELSE -%]
|
||||||
|
[% element.get_name %] => '[% type_prefix %][% localname %]',
|
||||||
|
[%- END;
|
||||||
|
ELSIF (simpleType = element.first_simpleType);
|
||||||
|
base = simpleType.get_base();
|
||||||
|
%]
|
||||||
|
# basic simple type handling: we treat atomic simple types
|
||||||
|
# in complexType elements as their base types
|
||||||
|
# - and we only treat <restriction base="..."> yet.
|
||||||
|
# our base here is [% base %]
|
||||||
|
[%
|
||||||
|
split_name = base.split(':');
|
||||||
|
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 %]',
|
||||||
|
[% ELSE -%]
|
||||||
|
[% element.get_name %] => '[% type_prefix %][% localname %]',
|
||||||
|
[%- END;
|
||||||
|
END;
|
||||||
END %]
|
END %]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -214,21 +231,68 @@ __PACKAGE__->_factory(
|
|||||||
sub get_xmlns { '[% self.get_targetNamespace %]' }
|
sub get_xmlns { '[% self.get_targetNamespace %]' }
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 NAME [% type_prefix %][% self.get_name %]
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Type class for the XML type [% self.get_name %].
|
||||||
|
|
||||||
|
=head1 PROPERTIES
|
||||||
|
|
||||||
|
The following properties may be accessed using get_PROPERTY / set_PROPERTY
|
||||||
|
methods:
|
||||||
|
|
||||||
|
[%- FOREACH element = self.get_element %]
|
||||||
|
[% element.get_name -%]
|
||||||
|
[% END %]
|
||||||
|
|
||||||
|
=head1 Object structure
|
||||||
|
|
||||||
|
[% FOREACH element=self.get_element;
|
||||||
|
IF (element.get_type);
|
||||||
|
split_name = element.get_type.split(':');
|
||||||
|
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 %]',
|
||||||
|
[% ELSE -%]
|
||||||
|
[% element.get_name %] => '[% type_prefix %][% localname %]',
|
||||||
|
[%- END;
|
||||||
|
ELSIF (simpleType = element.first_simpleType);
|
||||||
|
base = simpleType.get_base();
|
||||||
|
split_name = base.split(':');
|
||||||
|
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 %]',
|
||||||
|
[% ELSE -%]
|
||||||
|
[% element.get_name %] => '[% type_prefix %][% localname %]',
|
||||||
|
[%- END;
|
||||||
|
END;
|
||||||
|
END %]
|
||||||
|
|
||||||
|
Structure as perl hash:
|
||||||
|
|
||||||
|
The object structure is displayed as hash below though this is not correct.
|
||||||
|
Complex hash elements actually are objects of their corresponding classes
|
||||||
|
(look for classes of the same name in your typleib).
|
||||||
|
new() will accept a hash structure like this, but transform it to a object
|
||||||
|
tree.
|
||||||
|
|
||||||
|
[% structure %]
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
EOT
|
EOT
|
||||||
|
|
||||||
$opt->{ base_path } ||= '.';
|
$self->SUPER::to_class($opt, $template);
|
||||||
|
|
||||||
require Template;
|
|
||||||
my $tt = Template->new(
|
|
||||||
RELATIVE => 1,
|
|
||||||
);
|
|
||||||
my $code = $tt->process( \$template, {
|
|
||||||
class_prefix => $opt->{ prefix },
|
|
||||||
self => $self,
|
|
||||||
nsmap => { reverse %{ $opt->{ wsdl }->get_xmlns() } },
|
|
||||||
},
|
|
||||||
$opt->{ output },
|
|
||||||
) or die $tt->error();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _check_value {
|
sub _check_value {
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ sub first_complexType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# serialize type instead...
|
# serialize type instead...
|
||||||
sub serialize
|
sub serialize {
|
||||||
{
|
|
||||||
my ($self, $name, $value, $opt) = @_;
|
my ($self, $name, $value, $opt) = @_;
|
||||||
my $type;
|
my $type;
|
||||||
my $typelib = $opt->{ typelib };
|
my $typelib = $opt->{ typelib };
|
||||||
@@ -109,8 +108,7 @@ sub serialize
|
|||||||
return $type->serialize( $name, $value, $opt );
|
return $type->serialize( $name, $value, $opt );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub explain
|
sub explain {
|
||||||
{
|
|
||||||
my ($self, $opt, $name) = @_;
|
my ($self, $opt, $name) = @_;
|
||||||
my $type;
|
my $type;
|
||||||
my $text = q{};
|
my $text = q{};
|
||||||
@@ -119,10 +117,12 @@ sub explain
|
|||||||
if ($type = $self->first_simpleType() )
|
if ($type = $self->first_simpleType() )
|
||||||
{
|
{
|
||||||
$text .= $type->explain( $opt, $self->get_name() );
|
$text .= $type->explain( $opt, $self->get_name() );
|
||||||
|
return $text;
|
||||||
}
|
}
|
||||||
elsif ($type = $self->first_complexType() )
|
elsif ($type = $self->first_complexType() )
|
||||||
{
|
{
|
||||||
$text .= $type->explain( $opt, $self->get_name() )
|
$text .= $type->explain( $opt, $self->get_name() );
|
||||||
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
# return if it's not a derived type - we don't handle
|
# return if it's not a derived type - we don't handle
|
||||||
@@ -131,14 +131,17 @@ sub explain
|
|||||||
|
|
||||||
# if we have a derived type, fetch type and explain
|
# if we have a derived type, fetch type and explain
|
||||||
my ($prefix, $localname) = split /:/ , $self->get_type();
|
my ($prefix, $localname) = split /:/ , $self->get_type();
|
||||||
my %ns_map = reverse %{ $opt->{ namespace } };
|
my %ns_map = reverse %{ $opt->{ wsdl }->get_xmlns };
|
||||||
my $ns = $ns_map{ $prefix };
|
|
||||||
|
|
||||||
$type = $opt->{ wsdl }->first_types()->find_type(
|
$type = $opt->{ wsdl }->first_types()->find_type(
|
||||||
$ns, $localname
|
$ns_map{ $prefix }, $localname
|
||||||
);
|
);
|
||||||
|
|
||||||
die "no type for $prefix:$localname ($ns)" if (not $type);
|
use Data::Dumper;
|
||||||
|
die "no type for $prefix:$localname ($ns_map{ $prefix })"
|
||||||
|
. Dumper $opt->{ wsdl }->first_types()->first_schema()->_DUMP
|
||||||
|
|
||||||
|
if (not $type);
|
||||||
|
|
||||||
return $text .= $type->explain( $opt, $self->get_name() );
|
return $text .= $type->explain( $opt, $self->get_name() );
|
||||||
return 'ERROR: '. $@;
|
return 'ERROR: '. $@;
|
||||||
@@ -150,9 +153,10 @@ sub to_typemap {
|
|||||||
my $txt = q{};
|
my $txt = q{};
|
||||||
|
|
||||||
my %nsmap = reverse %{ $opt->{ wsdl }->get_xmlns() };
|
my %nsmap = reverse %{ $opt->{ wsdl }->get_xmlns() };
|
||||||
|
|
||||||
my $type;
|
my $type;
|
||||||
|
|
||||||
push @{ $opt->{path} }, $self->get_name();
|
push @{ $opt->{path} }, $self->get_name();
|
||||||
|
|
||||||
if ( my $typename = $self->get_type() ) {
|
if ( my $typename = $self->get_type() ) {
|
||||||
my ($prefix, $localname) = split /:/, $self->get_type();
|
my ($prefix, $localname) = split /:/, $self->get_type();
|
||||||
my $ns = $nsmap{ $prefix };
|
my $ns = $nsmap{ $prefix };
|
||||||
@@ -165,12 +169,21 @@ sub to_typemap {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
$type = $opt->{ wsdl }->first_types()->find_type( $ns, $localname );
|
$type = $opt->{ wsdl }->first_types()->find_type( $ns, $localname );
|
||||||
$typeclass = $opt->{ prefix } . $type->get_name();
|
|
||||||
|
# referenced types need type_prefix (may be globally unique)
|
||||||
|
$typeclass = $opt->{ type_prefix } . $type->get_name();
|
||||||
$txt .= $type->to_typemap($opt);
|
$txt .= $type->to_typemap($opt);
|
||||||
}
|
}
|
||||||
$txt .= q{'} . join( q{/}, @{ $opt->{path} } ) . "' => '$typeclass',\n";
|
$txt .= q{'} . join( q{/}, @{ $opt->{path} } ) . "' => '$typeclass',\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# atomic types need element prefix
|
||||||
elsif ($type = $self->first_simpleType() ) {
|
elsif ($type = $self->first_simpleType() ) {
|
||||||
|
# atomic types need element prefix (may be locally unique)
|
||||||
|
# TODO fix simpletype Typemap
|
||||||
|
my $typeclass = $opt->{ element_prefix } . $self->get_name();
|
||||||
|
$txt .= q{'} . join( q{/}, @{ $opt->{path} } ) . "' => '$typeclass',\n";
|
||||||
|
|
||||||
my $flavor = $type->get_flavor();
|
my $flavor = $type->get_flavor();
|
||||||
if ( $flavor eq 'sequence' ) {
|
if ( $flavor eq 'sequence' ) {
|
||||||
$txt .= "# atomic simple type (sequence)\n";
|
$txt .= "# atomic simple type (sequence)\n";
|
||||||
@@ -185,9 +198,10 @@ sub to_typemap {
|
|||||||
|
|
||||||
}
|
}
|
||||||
elsif ($type = $self->first_complexType() ) {
|
elsif ($type = $self->first_complexType() ) {
|
||||||
my $typeclass = $opt->{ prefix } . $self->get_name();
|
my $typeclass = $opt->{ element_prefix } . $self->get_name();
|
||||||
$txt .= q{'} . join( q{/}, @{ $opt->{path} } ) . "' => '$typeclass',\n";
|
$txt .= q{'} . join( q{/}, @{ $opt->{path} } ) . "' => '$typeclass',\n";
|
||||||
my $flavor = $type->get_flavor();
|
my $flavor = $type->get_flavor()
|
||||||
|
|| 'UNKNOWN';
|
||||||
if ( $flavor eq 'sequence' ) {
|
if ( $flavor eq 'sequence' ) {
|
||||||
$txt .= "# atomic complex type (sequence)\n";
|
$txt .= "# atomic complex type (sequence)\n";
|
||||||
$txt .= $type->to_typemap($opt). "\n";;
|
$txt .= $type->to_typemap($opt). "\n";;
|
||||||
@@ -198,18 +212,22 @@ sub to_typemap {
|
|||||||
$txt .= $type->to_typemap($opt). "\n";
|
$txt .= $type->to_typemap($opt). "\n";
|
||||||
$txt .= "# end atomic complex type (all)\n";
|
$txt .= "# end atomic complex type (all)\n";
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
warn "flavor $flavor in element " . $self->get_name() . "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pop @{ $opt->{ path } };
|
pop @{ $opt->{ path } };
|
||||||
|
|
||||||
return $txt;
|
return $txt;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub toClass {
|
|
||||||
|
sub to_class {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $opt = shift;
|
my $opt = shift;
|
||||||
|
|
||||||
my $template = <<'EOT';
|
my $template = <<'EOT';
|
||||||
package [% class_prefix %]::[% self.get_name %];
|
package [% element_prefix %][% self.get_name %];
|
||||||
use strict;
|
use strict;
|
||||||
use Class::Std::Storable;
|
use Class::Std::Storable;
|
||||||
use SOAP::WSDL::XSD::Typelib::Element;
|
use SOAP::WSDL::XSD::Typelib::Element;
|
||||||
@@ -220,9 +238,10 @@ use base qw(
|
|||||||
SOAP::WSDL::XSD::Typelib::Element
|
SOAP::WSDL::XSD::Typelib::Element
|
||||||
SOAP::WSDL::XSD::Typelib::SimpleType
|
SOAP::WSDL::XSD::Typelib::SimpleType
|
||||||
[% type.flavor_class %]
|
[% type.flavor_class %]
|
||||||
[% type.base_class($class_prefix) %]
|
[% type.base_class($type_prefix) %]
|
||||||
);
|
);
|
||||||
[% ELSIF (type = self.first_complexType) %]
|
[% ELSIF (type = self.first_complexType) %]
|
||||||
|
# atomic complexType
|
||||||
# <element name="[% self.get_name %]"><complexType> definition
|
# <element name="[% self.get_name %]"><complexType> definition
|
||||||
use SOAP::WSDL::XSD::Typelib::ComplexType;
|
use SOAP::WSDL::XSD::Typelib::ComplexType;
|
||||||
use base qw(
|
use base qw(
|
||||||
@@ -250,23 +269,24 @@ __PACKAGE__->_factory(
|
|||||||
IF nsmap.$prefix == 'http://www.w3.org/2001/XMLSchema' %]
|
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 %]
|
[% ELSE %]
|
||||||
[% element.get_name %] => '[% class_prefix %]::[% localname %]',
|
[% element.get_name %] => '[% type_prefix %][% localname %]',
|
||||||
[% END %]
|
[% END %]
|
||||||
[% END %]
|
[% END %]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
[%# END complexType %]
|
[%# END complexType %]
|
||||||
[% ELSIF (type = self.get_type) %]
|
[% ELSIF (type = self.get_type) %]
|
||||||
|
#
|
||||||
# <element name="[% self.get_name %]" type="[% self.get_type %]"/> definition
|
# <element name="[% self.get_name %]" type="[% self.get_type %]"/> definition
|
||||||
[% (typename = self.get_type);
|
#
|
||||||
split_name = element.type.split(':');
|
[% split_name = self.get_type.split(':');
|
||||||
prefix = split_name.0;
|
prefix = split_name.0;
|
||||||
localname = split_name.1;
|
localname = split_name.1;
|
||||||
-%]
|
|
||||||
[% IF (nsmap.$prefix == 'http://www.w3.org/2001/XMLSchema');
|
IF (nsmap.$prefix == 'http://www.w3.org/2001/XMLSchema');
|
||||||
base_class = 'SOAP::WSDL::XSD::Typelib::Builtin::' _ localname ;
|
base_class = 'SOAP::WSDL::XSD::Typelib::Builtin::' _ localname ;
|
||||||
ELSE;
|
ELSE;
|
||||||
base_class = class_prefix _ '::' _ localname;
|
base_class = type_prefix _ localname;
|
||||||
-%]
|
-%]
|
||||||
|
|
||||||
use [% base_class %];
|
use [% base_class %];
|
||||||
@@ -290,20 +310,61 @@ __PACKAGE__->__set_maxOccurs([% self.get_maxOccurs %]);
|
|||||||
__PACKAGE__->__set_ref('[% self.get_ref %]');
|
__PACKAGE__->__set_ref('[% self.get_ref %]');
|
||||||
|
|
||||||
1;
|
1;
|
||||||
EOT
|
|
||||||
|
|
||||||
require Template;
|
|
||||||
my $tt = Template->new(
|
__END__
|
||||||
RELATIVE => 1,
|
|
||||||
);
|
=pod
|
||||||
my $code = $tt->process( \$template, {
|
|
||||||
class_prefix => $opt->{ prefix },
|
=head1 NAME [% element_prefix %][% self.get_name %]
|
||||||
self => $self,
|
|
||||||
nsmap => { reverse %{ $opt->{ wsdl }->get_xmlns() } },
|
=head1 SYNOPSIS
|
||||||
},
|
|
||||||
$opt->{ output },
|
=head1 DESCRIPTION
|
||||||
)
|
|
||||||
or die $tt->error();
|
Type class for the XML element [% self.get_name %].
|
||||||
|
|
||||||
|
=head1 PROPERTIES
|
||||||
|
|
||||||
|
The following properties may be accessed using get_PROPERTY / set_PROPERTY
|
||||||
|
methods:
|
||||||
|
|
||||||
|
[%- IF (type = self.first_complexType);
|
||||||
|
FOREACH element = type.get_element %]
|
||||||
|
[% element.get_name -%]
|
||||||
|
[% END;
|
||||||
|
END %]
|
||||||
|
|
||||||
|
=head1 Object structure
|
||||||
|
|
||||||
|
[%- IF (type = self.first_complexType);
|
||||||
|
FOREACH element = type.get_element;
|
||||||
|
split_name = element.get_type.split(':');
|
||||||
|
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 %]',
|
||||||
|
[% ELSE %]
|
||||||
|
[% element.get_name %] => '[% type_prefix %]::[% localname %]',
|
||||||
|
[% END;
|
||||||
|
END;
|
||||||
|
END %]
|
||||||
|
|
||||||
|
Structure as perl hash:
|
||||||
|
|
||||||
|
The object structure is displayed as hash below though this is not correct.
|
||||||
|
Complex hash elements actually are objects of their corresponding classes
|
||||||
|
(look for classes of the same name in your typleib).
|
||||||
|
new() will accept a hash structure like this, but transform it to a object
|
||||||
|
tree.
|
||||||
|
|
||||||
|
[% structure %]
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
EOT
|
||||||
|
|
||||||
|
$self->SUPER::to_class($opt, $template);
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -40,13 +40,8 @@ sub serialize
|
|||||||
sub explain
|
sub explain
|
||||||
{
|
{
|
||||||
my ($self, $opt, $name ) = @_;
|
my ($self, $opt, $name ) = @_;
|
||||||
my $perl;
|
|
||||||
$opt->{ indent } ||= "";
|
$opt->{ indent } ||= "";
|
||||||
$perl .= $opt->{ indent } if ($opt->{ readable });
|
return "$opt->{ indent }'$name' => \$someValue,\n"
|
||||||
|
|
||||||
$perl .= q{'} . $name . q{' => $someValue };
|
|
||||||
$perl .= "\n" if ($opt->{ readable });
|
|
||||||
return $perl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub toClass {
|
sub toClass {
|
||||||
|
|||||||
@@ -5,43 +5,42 @@ use Class::Std::Storable;
|
|||||||
use base qw(SOAP::WSDL::Base);
|
use base qw(SOAP::WSDL::Base);
|
||||||
|
|
||||||
my %base_of :ATTR(:name<base> :default<()>);
|
my %base_of :ATTR(:name<base> :default<()>);
|
||||||
my %flavor_of :ATTR(:name<flavor> :default<()>);
|
|
||||||
my %itemType_of :ATTR(:name<itemType> :default<()>);
|
my %itemType_of :ATTR(:name<itemType> :default<()>);
|
||||||
my %enumeration_of :ATTR(:name<enumeration> :default<()>);
|
my %enumeration_of :ATTR(:name<enumeration> :default<()>);
|
||||||
# is set to simpleContent/complexContent
|
# is set to simpleContent/complexContent
|
||||||
my %content_Model_of :ATTR(:name<contentModel> :default<()>);
|
my %content_Model_of :ATTR(:name<contentModel> :default<()>);
|
||||||
|
|
||||||
|
# set to restriction|list|union|enumeration
|
||||||
|
my %flavor_of :ATTR(:name<flavor> :default<()>);
|
||||||
|
|
||||||
sub set_restriction {
|
sub set_restriction {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my @attributes = @_;
|
my @attributes = @_;
|
||||||
$self->set_flavor( 'restriction' );
|
$self->set_flavor( 'restriction' );
|
||||||
foreach my $attr (@attributes)
|
for (@attributes) {
|
||||||
{
|
next if (not $_->{ LocalName } eq 'base');
|
||||||
next if (not $attr->{ LocalName } eq 'restriction');
|
$self->set_base( $_->{ Value } );
|
||||||
$self->base( $attr->{ Value } );
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub set_list {
|
sub set_list {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my @attributes = @_;
|
my @attributes = @_;
|
||||||
$self->set_flavor( 'list' );
|
$self->set_flavor( 'list' );
|
||||||
foreach my $attr (@attributes)
|
for (@attributes) {
|
||||||
{
|
next if (not $_->{ LocalName } eq 'type');
|
||||||
next if (not $attr->{ LocalName } eq 'list');
|
$self->set_base( $_->{ Value } );
|
||||||
$self->set_base( $attr->{ Value } );
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub set_union {
|
sub set_union {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my @attributes = @_;
|
my @attributes = @_;
|
||||||
$self->set_flavor( 'union' );
|
$self->set_flavor( 'union' );
|
||||||
foreach my $attr (@attributes)
|
for (@attributes) {
|
||||||
{
|
next if (not $_->{ LocalName } eq 'memberTypes');
|
||||||
next if (not $attr->{ LocalName } eq 'memberTypes');
|
$self->set_base( [ split /\s/, $_->{ Value } ] );
|
||||||
$self->set_base( [ split /\s/, $attr->{ Value } ] );
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub push_enumeration
|
sub push_enumeration
|
||||||
@@ -50,10 +49,9 @@ sub push_enumeration
|
|||||||
my @attr = @_;
|
my @attr = @_;
|
||||||
my @attributes = @_;
|
my @attributes = @_;
|
||||||
$self->set_flavor( 'enumeration' );
|
$self->set_flavor( 'enumeration' );
|
||||||
foreach my $attr (@attributes)
|
for (@attributes) {
|
||||||
{
|
next if (not $_->{ LocalName } eq 'value');
|
||||||
next if (not $attr->{ LocalName } eq 'value');
|
push @{ $enumeration_of{ ident $self } }, $_->{ 'Value' };
|
||||||
push @{ $enumeration_of{ ident $self } }, $attr->{ 'Value' };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,11 +113,13 @@ sub explain {
|
|||||||
sub _check_value {
|
sub _check_value {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO: implement to_class based on template...
|
||||||
|
|
||||||
sub toClass {
|
sub to_class {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $opt = shift;
|
my $opt = shift;
|
||||||
my $class_prefix = $opt->{ prefix };
|
my $class_prefix = $opt->{ type_prefix };
|
||||||
my $name = $opt->{name} || $self->get_name();
|
my $name = $opt->{name} || $self->get_name();
|
||||||
my $flavor = $self->get_flavor() eq 'list'
|
my $flavor = $self->get_flavor() eq 'list'
|
||||||
? 'SOAP::WSDL::XSD::Typelib::Builtin::list'
|
? 'SOAP::WSDL::XSD::Typelib::Builtin::list'
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType;
|
package SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Class::Std::Storable;
|
|
||||||
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anyType);
|
BEGIN {
|
||||||
|
use Class::Std::Storable;
|
||||||
|
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anyType);
|
||||||
|
}
|
||||||
|
|
||||||
my %value_of :ATTR(:get<value> :init_arg<value> :default<()>);
|
my %value_of :ATTR(:get<value> :init_arg<value> :default<()>);
|
||||||
|
|
||||||
@@ -27,7 +30,8 @@ sub as_bool :BOOLIFY {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Class::Std::initialize(); # make :BOOLIFY overloading serializable
|
Class::Std::initialize(); # make :BOOLIFY overloading serializable
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|||||||
@@ -1,13 +1,34 @@
|
|||||||
package SOAP::WSDL::XSD::Typelib::Builtin::boolean;
|
package SOAP::WSDL::XSD::Typelib::Builtin::boolean;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Class::Std::Storable;
|
|
||||||
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType);
|
# Speed up. Class::Std::new is slow - and we don't need it's functionality...
|
||||||
|
BEGIN {
|
||||||
|
use Class::Std::Storable;
|
||||||
|
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType);
|
||||||
|
}
|
||||||
|
|
||||||
|
my %pattern_of :ATTR(:name<pattern> :default<()>);
|
||||||
|
my %whiteSpace_of :ATTR(:name<whiteSpace> :default<()>);
|
||||||
|
my %value_of :ATTR(:get<value> :init_attr<value> :default<()>);
|
||||||
|
|
||||||
|
{
|
||||||
|
no warnings qw(redefine);
|
||||||
|
no strict qw(refs);
|
||||||
|
|
||||||
|
# Yes, I know it's ugly - but this is the fastest constructor to write
|
||||||
|
# for Class::Std-Style inside out objects..
|
||||||
|
*{ __PACKAGE__ . '::new' } = sub {
|
||||||
|
my $self = bless \do { my $foo } , shift;
|
||||||
|
if (@_) {
|
||||||
|
$value_of{ ident $self } = $_[0]->{ value }
|
||||||
|
if exists $_[0]->{ value }
|
||||||
|
}
|
||||||
|
return $self;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
my %pattern_of :ATTR(:name<pattern> :default<()>);
|
|
||||||
my %whiteSpace_of :ATTR(:name<whiteSpace> :default<()>);
|
|
||||||
|
|
||||||
my %value_of :ATTR(:get<value> :init_attr<value> :default<()>);
|
|
||||||
|
|
||||||
sub serialize {
|
sub serialize {
|
||||||
my ($self, $opt) = @_;
|
my ($self, $opt) = @_;
|
||||||
@@ -33,6 +54,8 @@ sub set_value {
|
|||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Class::Std::initialize(); # make :BOOLIFY overloading serializable
|
Class::Std::initialize(); # make :BOOLIFY overloading serializable
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -1,9 +1,27 @@
|
|||||||
package SOAP::WSDL::XSD::Typelib::Builtin::int;
|
package SOAP::WSDL::XSD::Typelib::Builtin::int;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Class::Std::Storable;
|
|
||||||
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::long);
|
|
||||||
|
|
||||||
|
# Speed up. Class::Std::new is slow - and we don't need it's functionality...
|
||||||
|
BEGIN {
|
||||||
|
use Class::Std::Storable;
|
||||||
|
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::long);
|
||||||
|
|
||||||
|
no warnings qw(redefine);
|
||||||
|
no strict qw(refs);
|
||||||
|
|
||||||
|
# Yes, I know it's ugly - but this is the fastest constructor to write
|
||||||
|
# for Class::Std-Style inside out objects..
|
||||||
|
*{ __PACKAGE__ . '::new' } = sub {
|
||||||
|
my $self = bless \do { my $foo } , shift;
|
||||||
|
if (@_) {
|
||||||
|
$self->set_value( $_[0]->{ value } )
|
||||||
|
if exists $_[0]->{ value }
|
||||||
|
}
|
||||||
|
return $self;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,28 @@
|
|||||||
package SOAP::WSDL::XSD::Typelib::Builtin::integer;
|
package SOAP::WSDL::XSD::Typelib::Builtin::integer;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Class::Std::Storable;
|
|
||||||
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::decimal);
|
# Speed up. Class::Std::new is slow - and we don't need it's functionality...
|
||||||
|
BEGIN {
|
||||||
|
use Class::Std::Storable;
|
||||||
|
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::decimal);
|
||||||
|
|
||||||
|
no warnings qw(redefine);
|
||||||
|
no strict qw(refs);
|
||||||
|
|
||||||
|
# Yes, I know it's ugly - but this is the fastest constructor to write
|
||||||
|
# for Class::Std-Style inside out objects..
|
||||||
|
*{ __PACKAGE__ . '::new' } = sub {
|
||||||
|
my $self = bless \do { my $foo } , shift;
|
||||||
|
if (@_) {
|
||||||
|
$self->set_value( $_[0]->{ value } )
|
||||||
|
if exists $_[0]->{ value }
|
||||||
|
}
|
||||||
|
return $self;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
sub as_num :NUMERIFY {
|
sub as_num :NUMERIFY {
|
||||||
return $_[0]->get_value();
|
return $_[0]->get_value();
|
||||||
|
|||||||
@@ -1,8 +1,27 @@
|
|||||||
package SOAP::WSDL::XSD::Typelib::Builtin::long;
|
package SOAP::WSDL::XSD::Typelib::Builtin::long;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Class::Std::Storable;
|
|
||||||
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::integer);
|
# Speed up. Class::Std::new is slow - and we don't need it's functionality...
|
||||||
|
BEGIN {
|
||||||
|
use Class::Std::Storable;
|
||||||
|
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::integer);
|
||||||
|
|
||||||
|
no warnings qw(redefine);
|
||||||
|
no strict qw(refs);
|
||||||
|
|
||||||
|
# Yes, I know it's ugly - but this is the fastest constructor to write
|
||||||
|
# for Class::Std-Style inside out objects..
|
||||||
|
*{ __PACKAGE__ . '::new' } = sub {
|
||||||
|
my $self = bless \do { my $foo } , shift;
|
||||||
|
if (@_) {
|
||||||
|
$self->set_value( $_[0]->{ value } )
|
||||||
|
if exists $_[0]->{ value }
|
||||||
|
}
|
||||||
|
return $self;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -1,15 +1,62 @@
|
|||||||
package SOAP::WSDL::XSD::Typelib::Builtin::string;
|
package SOAP::WSDL::XSD::Typelib::Builtin::string;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Class::Std::Storable;
|
|
||||||
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType);
|
# Speed up. Class::Std::new is slow - and we don't need it's functionality...
|
||||||
|
BEGIN {
|
||||||
|
use Class::Std::Storable;
|
||||||
|
use base qw(SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType);
|
||||||
|
|
||||||
|
no warnings qw(redefine);
|
||||||
|
no strict qw(refs);
|
||||||
|
|
||||||
|
# Yes, I know it's ugly - but this is the fastest constructor to write
|
||||||
|
# for Class::Std-Style inside out objects..
|
||||||
|
*{ __PACKAGE__ . '::new' } = sub {
|
||||||
|
my $self = bless \do { my $foo } , shift;
|
||||||
|
if (@_) {
|
||||||
|
$self->set_value( $_[0]->{ value } )
|
||||||
|
if exists $_[0]->{ value }
|
||||||
|
}
|
||||||
|
return $self;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
my %length_of :ATTR(:name<length> :default<()>);
|
||||||
|
my %minLength_of :ATTR(:name<minLength> :default<()>);
|
||||||
|
my %maxLength_of :ATTR(:name<maxLength> :default<()>);
|
||||||
|
my %pattern_of :ATTR(:name<pattern> :default<()>);
|
||||||
|
my %enumeration_of :ATTR(:name<enumeration> :default<()>);
|
||||||
|
my %whiteSpace_of :ATTR(:name<whiteSpace> :default<()>);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
my %length_of :ATTR(:name<length> :default<()>);
|
my %char2entity = (
|
||||||
my %minLength_of :ATTR(:name<minLength> :default<()>);
|
q{&} => q{&},
|
||||||
my %maxLength_of :ATTR(:name<maxLength> :default<()>);
|
q{<} => q{<},
|
||||||
my %pattern_of :ATTR(:name<pattern> :default<()>);
|
q{>} => q{>},
|
||||||
my %enumeration_of :ATTR(:name<enumeration> :default<()>);
|
q{"} => q{&qout;},
|
||||||
my %whiteSpace_of :ATTR(:name<whiteSpace> :default<()>);
|
q{'} => q{'},
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
sub serialize {
|
||||||
|
my ($self, $opt) = @_;
|
||||||
|
my $ident = ident $self;
|
||||||
|
$opt ||= {};
|
||||||
|
my $value = $self->get_value();
|
||||||
|
return $self->start_tag({ %$opt, nil => 1})
|
||||||
|
if not defined $value;
|
||||||
|
|
||||||
|
# HTML::Entities does the same - and more, thus it's around 1/3 slower...
|
||||||
|
$value =~ s{([&<>"'])}{$char2entity{$1}}xgmso;
|
||||||
|
|
||||||
|
return join q{}, $self->start_tag($opt, $value)
|
||||||
|
#, encode_entities( $value, q{&<>"'} )
|
||||||
|
, $value
|
||||||
|
, $self->end_tag($opt);
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
@@ -20,6 +67,11 @@ __END__
|
|||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
SOAP::WSDL::XSD::Typelib::Builtin::string - string objects
|
SOAP::WSDL::XSD::Typelib::Builtin::string - string objects
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
String objects. XML entities (&, E<lt> E<gt> " ') are encoded on
|
||||||
|
serialization.
|
||||||
|
|
||||||
=head1 LICENSE
|
=head1 LICENSE
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,19 @@ my %CLASSES_OF;
|
|||||||
|
|
||||||
# we store per-class elements.
|
# we store per-class elements.
|
||||||
# call as __PACKAGE__->_factory
|
# call as __PACKAGE__->_factory
|
||||||
sub _factory {
|
sub _factory {
|
||||||
my $class = shift;
|
my $class = shift;
|
||||||
$ELEMENTS_FROM{ $class } = shift;
|
$ELEMENTS_FROM{ $class } = shift;
|
||||||
$ATTRIBUTES_OF{ $class } = shift;
|
$ATTRIBUTES_OF{ $class } = shift;
|
||||||
$CLASSES_OF{ $class } = shift;
|
$CLASSES_OF{ $class } = shift;
|
||||||
|
|
||||||
no strict qw(refs);
|
no strict qw(refs);
|
||||||
|
no warnings qw(redefine);
|
||||||
while (my ($name, $attribute_ref) = each %{ $ATTRIBUTES_OF{ $class } } )
|
while (my ($name, $attribute_ref) = each %{ $ATTRIBUTES_OF{ $class } } )
|
||||||
{
|
{
|
||||||
my $type = $CLASSES_OF{ $class }->{ $name }
|
my $type = $CLASSES_OF{ $class }->{ $name }
|
||||||
or die "No class given for $name";
|
or die "No class given for $name";
|
||||||
|
|
||||||
$type->isa('UNIVERSAL')
|
$type->isa('UNIVERSAL')
|
||||||
or eval "require $type"
|
or eval "require $type"
|
||||||
or croak $@;
|
or croak $@;
|
||||||
@@ -35,27 +36,40 @@ sub _factory {
|
|||||||
*{ "$class\::set_$name" } = sub {
|
*{ "$class\::set_$name" } = sub {
|
||||||
my ($self, $value) = @_;
|
my ($self, $value) = @_;
|
||||||
|
|
||||||
# set to
|
# 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
|
# a) value if it's an object
|
||||||
# b) New object with value for simple values
|
# b) New object with value for simple values
|
||||||
# c) New object with value for list values and list type
|
# c 1) New object with value for list values and list type
|
||||||
# d) List ref of new objects with value for list values and non-list type
|
# c 2) List ref of new objects with value for list values and non-list type
|
||||||
# e) New object with values passed to new for HASH references
|
# c + e) List ref of objects for list values (list of objects) and non-list type
|
||||||
|
# d) New object with values passed to new for HASH references
|
||||||
#
|
#
|
||||||
# Die on non-ARRAY/HASH references - if you can define semantics
|
# Die on non-ARRAY/HASH references - if you can define semantics
|
||||||
# for GLOB references, feel free to add them.
|
# for GLOB references, feel free to add them.
|
||||||
$attribute_ref->{ ident $self } = (blessed $value)
|
$attribute_ref->{ ident $self } = blessed $value
|
||||||
? $value
|
? $value
|
||||||
: (ref $value ) ?
|
: ref $value
|
||||||
(ref $value eq 'ARRAY')
|
? ref $value eq 'ARRAY'
|
||||||
? $type->isa('SOAP::WSDL::XSD::Typelib::Builtin::list')
|
? $type->isa('SOAP::WSDL::XSD::Typelib::Builtin::list')
|
||||||
? $type->new({ value => $value })
|
? $type->new({ value => $value })
|
||||||
: [ map { $type->new({ value => $_ }) } @{ $value } ]
|
: [ map {
|
||||||
: (ref $value eq 'HASH')
|
blessed($_)
|
||||||
? $type->new( $value )
|
? ($_->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType'))
|
||||||
: die "Cannot use non-ARRAY/HASH as data"
|
? $_
|
||||||
: $type->new({ value => $value });
|
: croak 'cannot use non-XSD object as value'
|
||||||
|
: $type->new({ value => $_ })
|
||||||
|
} @{ $value }
|
||||||
|
]
|
||||||
|
: ref $value eq 'HASH'
|
||||||
|
? $type->new( $value )
|
||||||
|
: die 'Cannot use non-ARRAY/HASH as data'
|
||||||
|
: $type->new({ value => $value });
|
||||||
};
|
};
|
||||||
|
|
||||||
*{ "$class\::add_$name" } = sub {
|
*{ "$class\::add_$name" } = sub {
|
||||||
@@ -74,94 +88,110 @@ sub _factory {
|
|||||||
|
|
||||||
# add to list
|
# add to list
|
||||||
return push @{ $attribute_ref->{ $ident } }, $value;
|
return push @{ $attribute_ref->{ $ident } }, $value;
|
||||||
|
};
|
||||||
|
|
||||||
|
*{ "$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\::_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 = $_;
|
||||||
|
|
||||||
|
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) = @_;
|
||||||
|
$opt ||= {};
|
||||||
|
|
||||||
|
# do we have a empty element ?
|
||||||
|
return $self->start_tag({ %$opt, empty => 1 })
|
||||||
|
if not defined $ELEMENTS_FROM{ $class } or not @{ $ELEMENTS_FROM{ $class } };
|
||||||
|
return join q{}, $self->start_tag($opt),
|
||||||
|
$self->_serialize(), $self->end_tag();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub START {
|
|
||||||
my ($self, $ident, $args_of) = @_;
|
|
||||||
my $class = ref $self;
|
|
||||||
|
|
||||||
# iterate over keys of arguments
|
|
||||||
# and call set appropriate field in clase
|
|
||||||
map { ($ATTRIBUTES_OF{ $class }->{ $_ })
|
|
||||||
? do {
|
|
||||||
my $method = "set_$_";
|
|
||||||
$self->$method( $args_of->{ $_ } );
|
|
||||||
}
|
|
||||||
: $_ eq 'xmlns'
|
|
||||||
? do {}
|
|
||||||
: croak "unknown field $_ in $class";
|
|
||||||
} keys %$args_of;
|
|
||||||
};
|
|
||||||
|
|
||||||
sub _get_elements {
|
|
||||||
my $self = shift;
|
|
||||||
my $class = ref $self;
|
|
||||||
my $ident = ident $self;
|
|
||||||
return map { $_->{ $ident } } @{ $ELEMENTS_FROM{ $class } };
|
|
||||||
}
|
|
||||||
|
|
||||||
# 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 ?
|
|
||||||
#
|
|
||||||
sub _serialize {
|
|
||||||
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 = $_;
|
|
||||||
|
|
||||||
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 => $_ } );
|
|
||||||
}
|
|
||||||
# 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 } });
|
|
||||||
}
|
|
||||||
|
|
||||||
sub serialize {
|
|
||||||
my ($self, $opt) = @_;
|
|
||||||
$opt ||= {};
|
|
||||||
|
|
||||||
# do we have a empty element ?
|
|
||||||
return $self->start_tag({ %$opt, empty => 1 })
|
|
||||||
if not @{ $ELEMENTS_FROM{ ref $self } };
|
|
||||||
return join q{}, $self->start_tag($opt),
|
|
||||||
$self->_serialize(), $self->end_tag();
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
SOAP::WSDL::XSD::Typelib::ComplexType - ComplexType XML Schema definitions
|
||||||
|
|
||||||
=head1 Bugs and limitations
|
=head1 Bugs and limitations
|
||||||
|
|
||||||
=over
|
=over
|
||||||
|
|
||||||
|
=item * Incomplete API
|
||||||
|
|
||||||
|
Not all variants of XML Schema ComplexType definitions are supported yet.
|
||||||
|
|
||||||
|
Variants known to work are:
|
||||||
|
|
||||||
|
sequence
|
||||||
|
all
|
||||||
|
complexContent containing sequence/all definitions
|
||||||
|
|
||||||
=item * Thread safety
|
=item * Thread safety
|
||||||
|
|
||||||
SOAP::WSDL::XSD::Typelib::Builtin uses Class::Std::Storable which uses
|
SOAP::WSDL::XSD::Typelib::Builtin uses Class::Std::Storable which uses
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ sub start_tag {
|
|||||||
my $class = ref $self;
|
my $class = ref $self;
|
||||||
my $ending = '>';
|
my $ending = '>';
|
||||||
my @attr_from = ();
|
my @attr_from = ();
|
||||||
|
my $name = $opt->{ name } || $NAME{$class};
|
||||||
$ending = '/>' if ($opt->{ empty });
|
$ending = '/>' if ($opt->{ empty });
|
||||||
|
|
||||||
if ($opt->{qualified}) {
|
if ($opt->{qualified}) {
|
||||||
@@ -51,12 +51,13 @@ sub start_tag {
|
|||||||
push @attr_from, 'xsi:nil="true"';
|
push @attr_from, 'xsi:nil="true"';
|
||||||
$ending = '/>';
|
$ending = '/>';
|
||||||
}
|
}
|
||||||
return join q{ }, "<$NAME{$class}" , @attr_from , $ending;
|
return join q{ }, "<$name" , @attr_from , $ending;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub end_tag {
|
sub end_tag {
|
||||||
my ($self, $class) = ($_[0], ref $_[0]);
|
my ($class, $opt) = (ref $_[0], $_[1]);
|
||||||
return "</$NAME{$class}>";
|
my $name = $opt->{ name } || $NAME{$class};
|
||||||
|
return "</$name>";
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
+3
-4
@@ -1,8 +1,7 @@
|
|||||||
#!/usr/bin/perl -w
|
#!/usr/bin/perl -w
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use diagnostics;
|
use Test::More tests => 18; # qw/no_plan/; # TODO: change to tests => N;
|
||||||
use Test::More tests => 17; # qw/no_plan/; # TODO: change to tests => N;
|
|
||||||
use lib '../lib';
|
use lib '../lib';
|
||||||
use XML::SAX::ParserFactory;
|
use XML::SAX::ParserFactory;
|
||||||
|
|
||||||
@@ -28,9 +27,9 @@ $parser->parse_string( xml() );
|
|||||||
my $wsdl;
|
my $wsdl;
|
||||||
ok( $wsdl = $filter->get_data() , "get object tree");
|
ok( $wsdl = $filter->get_data() , "get object tree");
|
||||||
|
|
||||||
# print Dumper $wsdl;
|
|
||||||
|
|
||||||
my $types = $wsdl->first_types();
|
my $types = $wsdl->first_types();
|
||||||
|
|
||||||
|
is $types->get_parent(), $wsdl , 'types parent';
|
||||||
|
|
||||||
my $serializer_options = {
|
my $serializer_options = {
|
||||||
readable => 1,
|
readable => 1,
|
||||||
|
|||||||
+12
-7
@@ -7,6 +7,7 @@ use lib 't/lib';
|
|||||||
|
|
||||||
use_ok qw(SOAP::WSDL::XSD::Typelib::Element);
|
use_ok qw(SOAP::WSDL::XSD::Typelib::Element);
|
||||||
use_ok qw( MyElement );
|
use_ok qw( MyElement );
|
||||||
|
|
||||||
# simple type derived from builtin via restriction
|
# simple type derived from builtin via restriction
|
||||||
my $obj = MyElement->new({ value => 'test'});
|
my $obj = MyElement->new({ value => 'test'});
|
||||||
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType')
|
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType')
|
||||||
@@ -20,10 +21,10 @@ ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
|||||||
ok $obj->get_test->isa('SOAP::WSDL::XSD::Typelib::Builtin::string')
|
ok $obj->get_test->isa('SOAP::WSDL::XSD::Typelib::Builtin::string')
|
||||||
, 'element isa';
|
, 'element isa';
|
||||||
|
|
||||||
is $obj, '<MyAtomicComplexTypeElement xmlns="urn:Test" ><MyTestElement >Test</MyTestElement>'
|
is $obj, '<MyAtomicComplexTypeElement xmlns="urn:Test" ><test >Test</test>'
|
||||||
. '<MyTestElement2 >Test2</MyTestElement2></MyAtomicComplexTypeElement>'
|
. '<test2 >Test2</test2></MyAtomicComplexTypeElement>'
|
||||||
, 'stringification';
|
, 'stringification';
|
||||||
|
|
||||||
$obj = MyElement->new({ value => undef});
|
$obj = MyElement->new({ value => undef});
|
||||||
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType')
|
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType')
|
||||||
, 'inherited class';
|
, 'inherited class';
|
||||||
@@ -33,12 +34,16 @@ ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anySimpleType')
|
|||||||
$obj = MyAtomicComplexTypeElement->new({ test=> 'Test', test2 => [ 'Test2', 'Test3' ]});
|
$obj = MyAtomicComplexTypeElement->new({ test=> 'Test', test2 => [ 'Test2', 'Test3' ]});
|
||||||
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
||||||
, 'inherited class';
|
, 'inherited class';
|
||||||
is $obj, '<MyAtomicComplexTypeElement xmlns="urn:Test" ><MyTestElement >Test</MyTestElement>'
|
is $obj, '<MyAtomicComplexTypeElement xmlns="urn:Test" ><test >Test</test>'
|
||||||
. '<MyTestElement2 >Test2</MyTestElement2>'
|
. '<test2 >Test2</test2>'
|
||||||
. '<MyTestElement2 >Test3</MyTestElement2>'
|
. '<test2 >Test3</test2>'
|
||||||
. '</MyAtomicComplexTypeElement>'
|
. '</MyAtomicComplexTypeElement>'
|
||||||
, 'multi value stringification';
|
, 'multi value stringification';
|
||||||
|
|
||||||
|
use diagnostics;
|
||||||
|
|
||||||
|
ok $obj = MyComplexTypeElement->new({ MyTestName => 'test' });
|
||||||
|
is $obj, '<MyComplexTypeElement xmlns="urn:Test" ><MyTestName >test</MyTestName ></MyComplexTypeElement>';
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -11,12 +11,12 @@ use_ok qw( MyComplexType );
|
|||||||
my $obj = MyComplexType->new({ MyTestName => 'test' });
|
my $obj = MyComplexType->new({ MyTestName => 'test' });
|
||||||
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
||||||
, 'inherited class';
|
, 'inherited class';
|
||||||
is $obj, '<MyElementName >test</MyElementName>', 'stringification';
|
is $obj, '<MyTestName >test</MyTestName >', 'stringification';
|
||||||
|
|
||||||
$obj = MyComplexType->new({ MyTestName => [ 'test', 'test2' ] });
|
$obj = MyComplexType->new({ MyTestName => [ 'test', 'test2' ] });
|
||||||
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
||||||
, 'inherited class';
|
, 'inherited class';
|
||||||
is $obj, '<MyElementName >test</MyElementName><MyElementName >test2</MyElementName>',
|
is $obj, '<MyTestName >test</MyTestName ><MyTestName >test2</MyTestName >',
|
||||||
'stringification';
|
'stringification';
|
||||||
|
|
||||||
# try on the fly factory
|
# try on the fly factory
|
||||||
@@ -35,7 +35,7 @@ is $obj, '<MyElementName >test</MyElementName><MyElementName >test2</MyElementNa
|
|||||||
$obj = MyComplexType2->new({ MyTestName => [ 'test', 'test2' ] });
|
$obj = MyComplexType2->new({ MyTestName => [ 'test', 'test2' ] });
|
||||||
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
||||||
, 'inherited class (on the fly-factory object)';
|
, 'inherited class (on the fly-factory object)';
|
||||||
is $obj, '<MyElementName >test</MyElementName><MyElementName >test2</MyElementName>',
|
is $obj, '<MyTestName >test</MyTestName><MyTestName >test2</MyTestName>',
|
||||||
'stringification (on the fly-factory object)';
|
'stringification (on the fly-factory object)';
|
||||||
# print Dumper $obj->get_MyTestName();
|
# print Dumper $obj->get_MyTestName();
|
||||||
|
|
||||||
|
|||||||
+33
-20
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/perl -w
|
#!/usr/bin/perl -w
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Test::More tests => 5;
|
use Test::More tests => 16;
|
||||||
use lib '../lib';
|
use lib '../lib';
|
||||||
use XML::SAX::ParserFactory;
|
use XML::SAX::ParserFactory;
|
||||||
|
|
||||||
@@ -32,29 +32,42 @@ else
|
|||||||
{
|
{
|
||||||
pass("parsing XML");
|
pass("parsing XML");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
my $TMessage;
|
||||||
my $wsdl;
|
my $wsdl;
|
||||||
ok( $wsdl = $filter->get_data() , "get object tree");
|
ok( $wsdl = $filter->get_data() , "get object tree");
|
||||||
|
|
||||||
|
my %content;
|
||||||
|
|
||||||
for my $element (@{ $wsdl->first_types()->get_schema()->[1]->get_type() } ) {
|
for my $element (@{ $wsdl->first_types()->get_schema()->[1]->get_type() } ) {
|
||||||
# print Dumper $element;
|
local $SIG{__WARN__} = sub {
|
||||||
|
like $_[0], qr{toClass \s is \s deprecated}xms, 'deprecated method warning';
|
||||||
|
};
|
||||||
my $output;
|
my $output;
|
||||||
$element->toClass({ prefix => 'MessageGateway', wsdl => $wsdl,
|
$element->to_class({ prefix => 'MessageGateway::', wsdl => $wsdl,
|
||||||
output => \$output
|
output => \$output
|
||||||
});
|
});
|
||||||
eval "$output";
|
|
||||||
|
# skip eval'ing TMessage - it requires evalling other
|
||||||
|
# types first
|
||||||
|
if ($element->get_name() =~ m{\A (TMessage|TEnqueueMessage) \Z}xmsg ) {
|
||||||
|
$content{$1} = $output;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
my $name = 'MessageGateway::' . $element->get_name();
|
||||||
|
ok eval $output, $name;
|
||||||
|
|
||||||
|
ok $name->can('serialize'), "$name\->can('serialize')";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($@) {
|
while ( my ($name, $code) = (each %content) ) {
|
||||||
fail "evalling generated class";
|
ok eval "$code", $name;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
ok MessageGateway::TMessage->can('serialize'), 'MessageGateway::TMessage->can("serialize")';
|
||||||
pass "evalling generated class";
|
ok MessageGateway::TEnqueueMessage->can('serialize'), "MessageGateway::TEnqueueMessage->can('serialize')";
|
||||||
}
|
|
||||||
|
|
||||||
exit;
|
|
||||||
|
|
||||||
sub xml {
|
sub xml {
|
||||||
return q{<?xml version="1.0" encoding="UTF-8"?>
|
return q{<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<wsdl:definitions name="MessageGateway"
|
<wsdl:definitions name="MessageGateway"
|
||||||
@@ -302,7 +315,7 @@ sub xml {
|
|||||||
|
|
||||||
<wsdl:portType name="MGWPortType">
|
<wsdl:portType name="MGWPortType">
|
||||||
<wsdl:documentation>
|
<wsdl:documentation>
|
||||||
generic port type for all methods required for sending messages over the mosaic
|
generic port type for all methods required for sending messages over the
|
||||||
message gatewa
|
message gatewa
|
||||||
</wsdl:documentation>
|
</wsdl:documentation>
|
||||||
<wsdl:operation name="EnqueueMessage">
|
<wsdl:operation name="EnqueueMessage">
|
||||||
@@ -350,11 +363,11 @@ sub xml {
|
|||||||
</wsdl:binding>
|
</wsdl:binding>
|
||||||
<wsdl:service name="MessageGateway">
|
<wsdl:service name="MessageGateway">
|
||||||
<wsdl:documentation>
|
<wsdl:documentation>
|
||||||
Web Service for sending messages over the mosaic message gatewa
|
Web Service for sending messages over the message gatewa
|
||||||
</wsdl:documentation>
|
</wsdl:documentation>
|
||||||
|
|
||||||
<wsdl:port name="HTTPPort" binding="tns:MGWBinding">
|
<wsdl:port name="HTTPPort" binding="tns:MGWBinding">
|
||||||
<wsdl:documentation>HTTP(S) port for the mosaic message gatewa</wsdl:documentation>
|
<wsdl:documentation>HTTP(S) port for the message gatewa</wsdl:documentation>
|
||||||
<soap:address location="https://www.example.org/MessageGateway/" />
|
<soap:address location="https://www.example.org/MessageGateway/" />
|
||||||
</wsdl:port>
|
</wsdl:port>
|
||||||
</wsdl:service>
|
</wsdl:service>
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ ok $obj->isa('SOAP::WSDL::XSD::Typelib::Builtin::anyType')
|
|||||||
ok $obj->get_test->isa('SOAP::WSDL::XSD::Typelib::Builtin::string')
|
ok $obj->get_test->isa('SOAP::WSDL::XSD::Typelib::Builtin::string')
|
||||||
, 'element isa';
|
, 'element isa';
|
||||||
|
|
||||||
is $obj, '<MyAtomicComplexTypeElement xmlns="urn:Test" ><MyTestElement >Test</MyTestElement>'
|
is $obj, '<MyAtomicComplexTypeElement xmlns="urn:Test" ><test >Test</test>'
|
||||||
. '<MyTestElement2 >Test2</MyTestElement2></MyAtomicComplexTypeElement>'
|
. '<test2 >Test2</test2></MyAtomicComplexTypeElement>'
|
||||||
, 'stringification';
|
, 'stringification';
|
||||||
|
|
||||||
my $soap = SOAP::WSDL::Client->new( {
|
my $soap = SOAP::WSDL::Client->new( {
|
||||||
@@ -34,8 +34,8 @@ is $soap->call('Test', $obj), q{<SOAP-ENV:Envelope }
|
|||||||
. q{xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" }
|
. q{xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" }
|
||||||
. q{xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >}
|
. q{xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" >}
|
||||||
. q{<SOAP-ENV:Body><MyAtomicComplexTypeElement xmlns="urn:Test" >}
|
. q{<SOAP-ENV:Body><MyAtomicComplexTypeElement xmlns="urn:Test" >}
|
||||||
. q{<MyTestElement >Test</MyTestElement>}
|
. q{<test >Test</test>}
|
||||||
. q{<MyTestElement2 >Test2</MyTestElement2>}
|
. q{<test2 >Test2</test2>}
|
||||||
. q{</MyAtomicComplexTypeElement></SOAP-ENV:Body></SOAP-ENV:Envelope>}
|
. q{</MyAtomicComplexTypeElement></SOAP-ENV:Body></SOAP-ENV:Envelope>}
|
||||||
, 'SOAP Envelope generation with objects';
|
, 'SOAP Envelope generation with objects';
|
||||||
|
|
||||||
@@ -56,5 +56,6 @@ sub get_class {
|
|||||||
'Fault/faultstring' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
'Fault/faultstring' => 'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
||||||
'Fault/detail' => 'SOAP::WSDL::XSD::Typelib::Builtin::anyType',
|
'Fault/detail' => 'SOAP::WSDL::XSD::Typelib::Builtin::anyType',
|
||||||
);
|
);
|
||||||
|
return $class_list{ $_[1] };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,401 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Test::More tests => 18;
|
||||||
|
use lib '../lib';
|
||||||
|
use XML::LibXML;
|
||||||
|
use SOAP::WSDL::SAX::WSDLHandler;
|
||||||
|
use SOAP::WSDL::SAX::MessageHandler;
|
||||||
|
use File::Path;
|
||||||
|
use File::Basename;
|
||||||
|
|
||||||
|
my $path = dirname __FILE__;
|
||||||
|
|
||||||
|
my $filter = SOAP::WSDL::SAX::WSDLHandler->new();
|
||||||
|
my $parser = XML::LibXML->new();
|
||||||
|
$parser->set_handler( $filter );
|
||||||
|
$parser->parse_string( xml() );
|
||||||
|
|
||||||
|
my $wsdl;
|
||||||
|
ok( $wsdl = $filter->get_data() , "get object tree");
|
||||||
|
|
||||||
|
ok $wsdl->create_interface({
|
||||||
|
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 $handler = SOAP::WSDL::SAX::MessageHandler->new({
|
||||||
|
class_resolver => 'Test::Typemap::MessageGateway'
|
||||||
|
});
|
||||||
|
$parser->set_handler( $handler );
|
||||||
|
|
||||||
|
TODO: {
|
||||||
|
local $TODO = 'support embedded atomic simpleType/complexType definitions';
|
||||||
|
eval { $parser->parse_string( xml_message() ) };
|
||||||
|
ok ( !$@, 'parse XML message into object tree');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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>};
|
||||||
|
}
|
||||||
+2
-1
@@ -3,7 +3,8 @@ use lib '../lib';
|
|||||||
eval "require SOAP::WSDL::XSD::Typelib::Builtin";
|
eval "require SOAP::WSDL::XSD::Typelib::Builtin";
|
||||||
use Storable;
|
use Storable;
|
||||||
|
|
||||||
my $long = SOAP::WSDL::XSD::Typelib::Builtin::long->new( { value => 9 });
|
my $long = SOAP::WSDL::XSD::Typelib::Builtin::long->new();
|
||||||
|
$long->set_value( 9 );
|
||||||
my $clone = Storable::thaw( Storable::freeze( $long ) );
|
my $clone = Storable::thaw( Storable::freeze( $long ) );
|
||||||
|
|
||||||
is $clone->serialize, 9 , 'clone via freeze/thaw';
|
is $clone->serialize, 9 , 'clone via freeze/thaw';
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
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/);
|
||||||
|
|
||||||
|
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/" >
|
||||||
|
<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'
|
||||||
|
});
|
||||||
|
|
||||||
|
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" >}
|
||||||
|
. q{<test >Test</test><test2 >Test2</test2></MyAtomicComplexTypeElement>}
|
||||||
|
, 'Content comparison';
|
||||||
|
|
||||||
|
# data classes reside in t/lib/Typelib/
|
||||||
|
BEGIN {
|
||||||
|
package FakeResolver;
|
||||||
|
{
|
||||||
|
my %class_list = (
|
||||||
|
'MyAtomicComplexTypeElement' => 'MyAtomicComplexTypeElement',
|
||||||
|
'MyAtomicComplexTypeElement/test' => 'MyTestElement',
|
||||||
|
'MyAtomicComplexTypeElement/test2' => 'MyTestElement2',
|
||||||
|
);
|
||||||
|
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
@@ -19,7 +19,7 @@ chdir $path;
|
|||||||
|
|
||||||
$path = cwd;
|
$path = cwd;
|
||||||
|
|
||||||
$path =~s{/attic}{}xms;
|
$path =~s{/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
#2
|
#2
|
||||||
ok( $soap = SOAP::WSDL->new(
|
ok( $soap = SOAP::WSDL->new(
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use Test::More tests => 8;
|
use Test::More tests => 7;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use lib '../lib';
|
use lib '../lib';
|
||||||
@@ -15,11 +15,11 @@ if ($@)
|
|||||||
}
|
}
|
||||||
|
|
||||||
my $path = cwd();
|
my $path = cwd();
|
||||||
my $name = $0;
|
my $name = basename $0;
|
||||||
$name =~s/\.t$//;
|
$name =~s/\.t$//;
|
||||||
$name =~s/^t\///;
|
$name =~s/^t\///;
|
||||||
|
|
||||||
$path =~s{/attic}{}xms;
|
$path =~s{(/t)?/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
use_ok(qw/SOAP::WSDL/);
|
use_ok(qw/SOAP::WSDL/);
|
||||||
|
|
||||||
@@ -30,30 +30,27 @@ my $soap;
|
|||||||
|
|
||||||
#2
|
#2
|
||||||
ok( $soap = SOAP::WSDL->new(
|
ok( $soap = SOAP::WSDL->new(
|
||||||
wsdl => 'file://' . $path . '/acceptance/wsdl/' . $name . '.wsdl',
|
wsdl => 'file://' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl',
|
||||||
readable =>1,
|
readable =>1,
|
||||||
), 'Instantiated object' );
|
), 'Instantiated object' );
|
||||||
|
|
||||||
|
|
||||||
#3
|
#3
|
||||||
ok $soap->wsdlinit( checkoccurs => 1, ), 'parse WSDL';
|
ok $soap->wsdlinit(
|
||||||
|
checkoccurs => 1,
|
||||||
|
servicename => 'testService',
|
||||||
|
), 'parse WSDL';
|
||||||
ok $soap->no_dispatch(1), 'set no dispatch';
|
ok $soap->no_dispatch(1), 'set no dispatch';
|
||||||
|
|
||||||
ok ($xml = $soap->call('test',
|
ok ($xml = $soap->call('test',
|
||||||
Test1 => 'Test 1',
|
testAll => {
|
||||||
Test2 => 'Test 2',
|
Test1 => 'Test 1',
|
||||||
|
Test2 => [ 'Test 2', 'Test 3' ]
|
||||||
|
}
|
||||||
), 'Serialized complexType' );
|
), 'Serialized complexType' );
|
||||||
|
|
||||||
|
|
||||||
open (my $fh, $path . '/acceptance/results/' . $name . '.xml')
|
# print $xml;
|
||||||
|| die "Cannot open acceptance results file";
|
|
||||||
my $testXML = <$fh>;
|
|
||||||
close $fh;
|
|
||||||
|
|
||||||
SKIP: {
|
|
||||||
skip( $SKIP, 1 ) if ($SKIP);
|
|
||||||
eval { soap_eq_or_diff( $xml, $testXML, 'Got expected result') };
|
|
||||||
};
|
|
||||||
|
|
||||||
# $soap->wsdl_checkoccurs(1);
|
# $soap->wsdl_checkoccurs(1);
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
use Test::More tests => 2;
|
||||||
|
use lib '../lib';
|
||||||
|
|
||||||
|
use_ok qw/SOAP::WSDL/;
|
||||||
|
|
||||||
|
my $soap = SOAP::WSDL->new();
|
||||||
|
|
||||||
|
|
||||||
|
TODO: {
|
||||||
|
local $TODO="implement <choice> support";
|
||||||
|
fail "serialize choice element";
|
||||||
|
}
|
||||||
@@ -1,17 +1,15 @@
|
|||||||
BEGIN
|
BEGIN {
|
||||||
{
|
use Test::More tests => 6;
|
||||||
chdir 't/' if (-d 't/');
|
use lib '../lib';
|
||||||
use Test::More tests => 7;;
|
use lib 't/lib';
|
||||||
use lib '../lib';
|
use lib 'lib';
|
||||||
use lib 't/lib';
|
use Cwd;
|
||||||
use lib 'lib';
|
use File::Basename;
|
||||||
use Cwd;
|
|
||||||
use File::Basename;
|
our $SKIP;
|
||||||
|
eval "use Test::SOAPMessage";
|
||||||
our $SKIP;
|
if ($@)
|
||||||
eval "use Test::SOAPMessage";
|
{
|
||||||
if ($@)
|
|
||||||
{
|
|
||||||
$SKIP = "Test::Differences required for testing. $@";
|
$SKIP = "Test::Differences required for testing. $@";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,19 +19,20 @@ use_ok(qw/SOAP::WSDL/);
|
|||||||
my $xml;
|
my $xml;
|
||||||
|
|
||||||
my $path = cwd();
|
my $path = cwd();
|
||||||
my $name = $0;
|
my $name = basename $0;
|
||||||
$name =~s/\.t$//;
|
$name =~s/\.t$//;
|
||||||
|
|
||||||
$path=~s{/attic}{}xms;
|
$path=~s{(/t)?/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
#2
|
#2
|
||||||
ok( $soap = SOAP::WSDL->new(
|
ok( $soap = SOAP::WSDL->new(
|
||||||
wsdl => 'file://' . $path . '/acceptance/wsdl/' . $name . '.wsdl'
|
wsdl => 'file://' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl'
|
||||||
), 'Instantiated object' );
|
), 'Instantiated object' );
|
||||||
|
|
||||||
#3
|
#3
|
||||||
ok( $soap->wsdlinit(
|
ok( $soap->wsdlinit(
|
||||||
checkoccurs => 1,
|
checkoccurs => 1,
|
||||||
|
servicename => 'testService',
|
||||||
), 'parsed WSDL' );
|
), 'parsed WSDL' );
|
||||||
$soap->no_dispatch(1);
|
$soap->no_dispatch(1);
|
||||||
$soap->serializer()->envprefix('SOAP-ENV');
|
$soap->serializer()->envprefix('SOAP-ENV');
|
||||||
@@ -48,17 +47,6 @@ ok $xml = $soap->call('test',
|
|||||||
), 'Serialized complexType';
|
), 'Serialized complexType';
|
||||||
|
|
||||||
#5
|
#5
|
||||||
open (my $fh, $path . '/acceptance/results/' . $name . '.xml')
|
|
||||||
|| die "Cannot open acceptance results file";
|
|
||||||
my $testXML = <$fh>;
|
|
||||||
close $fh;
|
|
||||||
|
|
||||||
SKIP:
|
|
||||||
{
|
|
||||||
skip( $SKIP, 1 ) if ($SKIP);
|
|
||||||
soap_eq_or_diff( $xml, $testXML, 'Got expected result');
|
|
||||||
}
|
|
||||||
#6
|
|
||||||
eval
|
eval
|
||||||
{
|
{
|
||||||
$xml = $soap->serializer->method(
|
$xml = $soap->serializer->method(
|
||||||
@@ -73,7 +61,7 @@ ok( ($@),
|
|||||||
"Died on illegal number of elements"
|
"Died on illegal number of elements"
|
||||||
);
|
);
|
||||||
|
|
||||||
#7
|
#6
|
||||||
eval
|
eval
|
||||||
{
|
{
|
||||||
$xml = $soap->serializer->method(
|
$xml = $soap->serializer->method(
|
||||||
@@ -1,40 +1,34 @@
|
|||||||
use Test::More;
|
use Test::More tests => 6;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
plan qw/no_plan/;
|
|
||||||
use lib '../lib';
|
use lib '../lib';
|
||||||
use lib 't/lib';
|
use lib 't/lib';
|
||||||
use lib 'lib';
|
use lib 'lib';
|
||||||
use Cwd;
|
use Cwd;
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
|
|
||||||
our $SKIP;
|
|
||||||
eval "use Test::SOAPMessage";
|
|
||||||
if ($@) {
|
|
||||||
$SKIP = "Test::Differences required for testing.";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
use_ok(qw/SOAP::WSDL/);
|
use_ok(qw/SOAP::WSDL/);
|
||||||
|
|
||||||
my $xml;
|
my $xml;
|
||||||
|
|
||||||
my $soap = undef;
|
my $soap = undef;
|
||||||
my $name = basename( $0 );
|
my $name = basename $0;
|
||||||
$name =~s/\.(t|pl)$//;
|
$name =~s/\.(t|pl)$//;
|
||||||
|
|
||||||
my $path = cwd;
|
my $path = cwd;
|
||||||
|
|
||||||
$path =~s{/attic}{}xms;
|
$path =~s{(/t)?/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
#2
|
#2
|
||||||
ok( $soap = SOAP::WSDL->new(
|
ok( $soap = SOAP::WSDL->new(
|
||||||
wsdl => 'file:///' . $path . '/acceptance/wsdl/' . $name . '.wsdl'
|
wsdl => 'file:///' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl'
|
||||||
), 'Instantiated object' );
|
), 'Instantiated object' );
|
||||||
|
|
||||||
#3
|
#3
|
||||||
$soap->readable(1);
|
$soap->readable(1);
|
||||||
ok( $soap->wsdlinit(), 'parsed WSDL' );
|
ok( $soap->wsdlinit(
|
||||||
|
servicename => 'testService',
|
||||||
|
), 'parsed WSDL' );
|
||||||
$soap->no_dispatch(1);
|
$soap->no_dispatch(1);
|
||||||
|
|
||||||
ok ( $xml = $soap->call('test', testElement1 => 1 ) ,
|
ok ( $xml = $soap->call('test', testElement1 => 1 ) ,
|
||||||
@@ -43,17 +37,6 @@ ok ( $xml = $soap->call('test', testElement1 => 1 ) ,
|
|||||||
# print $xml, "\n";
|
# print $xml, "\n";
|
||||||
|
|
||||||
|
|
||||||
open (my $fh, $path . '/acceptance/results/' . $name . '.xml')
|
|
||||||
|| die 'Cannot open acceptance file '
|
|
||||||
. $path . '/acceptance/results/' . $name . '.xml';
|
|
||||||
my $testXML = <$fh>;
|
|
||||||
close $fh;
|
|
||||||
|
|
||||||
SKIP: {
|
|
||||||
skip($SKIP, 1) if ($SKIP);
|
|
||||||
soap_eq_or_diff( $xml, $testXML, 'Got expected result');
|
|
||||||
}
|
|
||||||
|
|
||||||
TODO: {
|
TODO: {
|
||||||
local $TODO="implement min/maxOccurs checks";
|
local $TODO="implement min/maxOccurs checks";
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use Test::More tests => 7;;
|
use Test::More tests => 6;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use lib '../lib';
|
use lib '../lib';
|
||||||
@@ -18,39 +18,27 @@ use_ok(qw/SOAP::WSDL/);
|
|||||||
my $soap;
|
my $soap;
|
||||||
my $xml;
|
my $xml;
|
||||||
my $path = cwd();
|
my $path = cwd();
|
||||||
my $name = $0;
|
my $name = basename $0;
|
||||||
$name =~s/\.t$//;
|
$name =~s/\.t$//;
|
||||||
|
|
||||||
$path =~s{/attic}{}xsm;
|
$path =~s{(/t)?/SOAP/WSDL}{}xsm;
|
||||||
|
|
||||||
#2
|
#2
|
||||||
ok( $soap = SOAP::WSDL->new(
|
ok( $soap = SOAP::WSDL->new(
|
||||||
wsdl => 'file://' . $path . '/acceptance/wsdl/' . $name . '.wsdl'
|
wsdl => 'file://' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl'
|
||||||
), 'Instantiated object' );
|
), 'Instantiated object' );
|
||||||
|
|
||||||
#3
|
#3
|
||||||
$soap->readable(1);
|
$soap->readable(1);
|
||||||
ok( $soap->wsdlinit(), 'parsed WSDL' );
|
ok( $soap->wsdlinit(
|
||||||
|
servicename => 'testService',
|
||||||
|
), 'parsed WSDL' );
|
||||||
$soap->no_dispatch(1);
|
$soap->no_dispatch(1);
|
||||||
|
|
||||||
ok ($xml = $soap->call('test',
|
ok ($xml = $soap->call('test',
|
||||||
testElement1 => 'Test'
|
testElement1 => 'Test'
|
||||||
), 'Serialized (simple) element' );
|
), 'Serialized (simple) element' );
|
||||||
|
|
||||||
open (my $fh, $path . '/acceptance/results/' . $name . '.xml')
|
|
||||||
|| die "Cannot open acceptance results file";
|
|
||||||
my $testXML = <$fh>;
|
|
||||||
close $fh;
|
|
||||||
|
|
||||||
SKIP: {
|
|
||||||
if ($SKIP){
|
|
||||||
print $xml;
|
|
||||||
skip( $SKIP, 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
soap_eq_or_diff( $xml, $testXML, 'Got expected result');
|
|
||||||
};
|
|
||||||
|
|
||||||
TODO: {
|
TODO: {
|
||||||
local $TODO="implement min/maxOccurs checks";
|
local $TODO="implement min/maxOccurs checks";
|
||||||
|
|
||||||
@@ -15,24 +15,24 @@ my $name = basename( $0 );
|
|||||||
$name =~s/\.(t|pl)$//;
|
$name =~s/\.(t|pl)$//;
|
||||||
|
|
||||||
my $path = cwd;
|
my $path = cwd;
|
||||||
$path =~s{/attic}{}xms;
|
$path =~s{(/t)/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
#2
|
#2
|
||||||
ok( $soap = SOAP::WSDL->new(
|
ok( $soap = SOAP::WSDL->new(
|
||||||
wsdl => 'file:///' . $path . '/acceptance/wsdl/' . $name . '.wsdl'
|
wsdl => 'file:///' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl'
|
||||||
), 'Instantiated object' );
|
), 'Instantiated object' );
|
||||||
|
|
||||||
$soap->readable(1);
|
$soap->readable(1);
|
||||||
|
|
||||||
#3
|
#3
|
||||||
ok( $soap->wsdlinit(), 'parsed WSDL' );
|
ok( $soap->wsdlinit(
|
||||||
|
servicename => 'testService',
|
||||||
|
), 'parsed WSDL' );
|
||||||
$soap->no_dispatch(1);
|
$soap->no_dispatch(1);
|
||||||
|
|
||||||
#4
|
#4
|
||||||
ok $xml = $soap->call('test', testAll => [ 1, 2 ] ), 'Serialize list call';
|
ok $xml = $soap->call('test', testAll => [ 1, 2 ] ), 'Serialize list call';
|
||||||
|
|
||||||
print $xml, "\n";
|
|
||||||
|
|
||||||
#5
|
#5
|
||||||
ok ( $xml2 = $soap->call('test', testAll => "1 2" ) , 'Serialized scalar call' );
|
ok ( $xml2 = $soap->call('test', testAll => "1 2" ) , 'Serialized scalar call' );
|
||||||
#6
|
#6
|
||||||
@@ -12,21 +12,23 @@ use_ok(qw/SOAP::WSDL/);
|
|||||||
|
|
||||||
my $xml;
|
my $xml;
|
||||||
|
|
||||||
my $name = basename( $0 );
|
my $name = basename $0;
|
||||||
$name =~s/\.(t|pl)$//;
|
$name =~s/\.(t|pl)$//;
|
||||||
|
|
||||||
my $path = cwd;
|
my $path = cwd;
|
||||||
$path =~s{/attic}{}xms;
|
$path =~s{(/t)/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
my $soap;
|
my $soap;
|
||||||
#2
|
#2
|
||||||
ok( $soap = SOAP::WSDL->new(
|
ok( $soap = SOAP::WSDL->new(
|
||||||
wsdl => 'file:///' . $path . '/acceptance/wsdl/' . $name . '.wsdl'
|
wsdl => 'file:///' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl'
|
||||||
), 'Instantiated object' );
|
), 'Instantiated object' );
|
||||||
|
|
||||||
#3
|
#3
|
||||||
$soap->readable(1);
|
$soap->readable(1);
|
||||||
ok( $soap->wsdlinit(), 'parsed WSDL' );
|
ok( $soap->wsdlinit(
|
||||||
|
servicename => 'testService',
|
||||||
|
), 'parsed WSDL' );
|
||||||
$soap->no_dispatch(1);
|
$soap->no_dispatch(1);
|
||||||
$soap->autotype(0);
|
$soap->autotype(0);
|
||||||
|
|
||||||
@@ -15,11 +15,11 @@ $name =~s/\.(t|pl)$//;
|
|||||||
|
|
||||||
my $path = cwd;
|
my $path = cwd;
|
||||||
|
|
||||||
$path =~s{/attic}{}xms;
|
$path =~s{(/t)?/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
#2
|
#2
|
||||||
ok $soap = SOAP::WSDL->new(
|
ok $soap = SOAP::WSDL->new(
|
||||||
wsdl => 'file:///' . $path . '/acceptance/wsdl/' . $name . '.wsdl'
|
wsdl => 'file:///' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl'
|
||||||
), 'Instantiated object';
|
), 'Instantiated object';
|
||||||
|
|
||||||
#3
|
#3
|
||||||
@@ -30,18 +30,6 @@ $soap->no_dispatch(1);
|
|||||||
#4
|
#4
|
||||||
ok $xml = $soap->call('test', testAll => 1 ) , 'Serialized call';
|
ok $xml = $soap->call('test', testAll => 1 ) , 'Serialized call';
|
||||||
|
|
||||||
print $xml, "\n";
|
|
||||||
|
|
||||||
SKIP: {
|
|
||||||
|
|
||||||
open (my $fh, $path . '/acceptance/results/' . $name . '.xml')
|
|
||||||
|| skip("Cannot open acceptance results file ". $name . '.xml', 1);
|
|
||||||
my $testXML = <$fh>;
|
|
||||||
close $fh;
|
|
||||||
|
|
||||||
is( $xml, $testXML, 'Got expected result');
|
|
||||||
}
|
|
||||||
|
|
||||||
# 6
|
# 6
|
||||||
eval {
|
eval {
|
||||||
$xml = $soap->serializer->method(
|
$xml = $soap->serializer->method(
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/perl -w
|
#!/usr/bin/perl -w
|
||||||
use strict;
|
use strict;
|
||||||
use Test::More tests=> 6;
|
use Test::More tests=> 5;
|
||||||
use Time::HiRes qw( gettimeofday tv_interval );
|
use Time::HiRes qw( gettimeofday tv_interval );
|
||||||
use lib '../..';
|
use lib '../..';
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
@@ -9,24 +9,22 @@ use File::Basename;
|
|||||||
use_ok qw/ SOAP::WSDL /;
|
use_ok qw/ SOAP::WSDL /;
|
||||||
use Benchmark;
|
use Benchmark;
|
||||||
|
|
||||||
# print "Testing SOAP::WSDL ". $SOAP::WSDL::VERSION."\n";
|
print "# Testing SOAP::WSDL ". $SOAP::WSDL::VERSION."\n";
|
||||||
# print "Performance test with simple WSDL file\n";
|
print "# Performance test with simple WSDL file\n";
|
||||||
|
my $soap;
|
||||||
my $data = {
|
my $data = {
|
||||||
|
sayHello => {
|
||||||
name => 'Mein Name',
|
name => 'Mein Name',
|
||||||
givenName => 'Vorname'
|
givenName => 'Vorname',
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
# chdir to my location
|
|
||||||
my $cwd = cwd;
|
|
||||||
my $path = dirname( $0 );
|
|
||||||
my $soap = undef;
|
|
||||||
my $name = basename( $0 );
|
my $name = basename( $0 );
|
||||||
$name =~s/\.(t|pl)$//;
|
$name =~s/\.(t|pl)$//;
|
||||||
chdir $path;
|
|
||||||
|
|
||||||
$path = cwd;
|
my $path = cwd;
|
||||||
|
|
||||||
|
$path=~s{(/t)?/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
my $cacheDir;
|
my $cacheDir;
|
||||||
if ($^O =~ m/Win/)
|
if ($^O =~ m/Win/)
|
||||||
@@ -42,7 +40,7 @@ else
|
|||||||
my $t0 = [gettimeofday];
|
my $t0 = [gettimeofday];
|
||||||
ok(
|
ok(
|
||||||
$soap=SOAP::WSDL->new(
|
$soap=SOAP::WSDL->new(
|
||||||
wsdl => "file://$path/acceptance/wsdl/10_helloworld.asmx.xml",
|
wsdl => "file://$path/t/acceptance/wsdl/10_helloworld.asmx.xml",
|
||||||
no_dispatch => 1
|
no_dispatch => 1
|
||||||
),
|
),
|
||||||
"Create SOAP::WSDL object (".tv_interval ( $t0, [gettimeofday]) ."ms)" );
|
"Create SOAP::WSDL object (".tv_interval ( $t0, [gettimeofday]) ."ms)" );
|
||||||
@@ -51,8 +49,10 @@ $soap->proxy('http://helloworld/helloworld.asmx');
|
|||||||
|
|
||||||
$t0 = [gettimeofday];
|
$t0 = [gettimeofday];
|
||||||
eval{
|
eval{
|
||||||
$soap->wsdlinit(caching => 1,
|
$soap->wsdlinit(
|
||||||
cache_directory => $cacheDir ) };
|
caching => 1,
|
||||||
|
cache_directory => $cacheDir,
|
||||||
|
servicename => 'Service1' ) };
|
||||||
|
|
||||||
unless ($@) {
|
unless ($@) {
|
||||||
pass("wsdl file init (".tv_interval ( $t0, [gettimeofday]) ."s)");
|
pass("wsdl file init (".tv_interval ( $t0, [gettimeofday]) ."s)");
|
||||||
@@ -69,7 +69,7 @@ $t0 = [gettimeofday];
|
|||||||
ok($soap->call(sayHello => %{ $data }),
|
ok($soap->call(sayHello => %{ $data }),
|
||||||
"1 x call pre-work (".tv_interval ( $t0, [gettimeofday]) ."s)" );
|
"1 x call pre-work (".tv_interval ( $t0, [gettimeofday]) ."s)" );
|
||||||
|
|
||||||
timethis 500, sub { $soap->call(sayHello => %{ $data }) };
|
timethis 1000, sub { $soap->call(sayHello => %{ $data }) };
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
#######################################################################################
|
||||||
|
#
|
||||||
|
# 2_helloworld.t
|
||||||
|
#
|
||||||
|
# Acceptance test for message encoding, based on .NET wsdl and example code.
|
||||||
|
# SOAP::WSDL's encoding doesn't I<exactly> match the .NET example, because
|
||||||
|
# .NET doesn't always specify types (SOAP::WSDL does), and the namespace
|
||||||
|
# prefixes chosen are different (maybe the encoding style, too ? this would be a bug !)
|
||||||
|
#
|
||||||
|
########################################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use Test::More tests => 4;
|
||||||
|
use lib '../..';
|
||||||
|
use Cwd;
|
||||||
|
use File::Basename;
|
||||||
|
|
||||||
|
|
||||||
|
use_ok q/SOAP::WSDL/;
|
||||||
|
|
||||||
|
### test vars END
|
||||||
|
print "# Testing SOAP::WSDL ". $SOAP::WSDL::VERSION."\n";
|
||||||
|
print "# Acceptance test against sample output with simple WSDL\n";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
my $data = {
|
||||||
|
name => 'test',
|
||||||
|
givenName => 'test',
|
||||||
|
};
|
||||||
|
|
||||||
|
my $soap = undef;
|
||||||
|
my $name = basename( $0 );
|
||||||
|
$name =~s/\.(t|pl)$//;
|
||||||
|
|
||||||
|
my $path = cwd;
|
||||||
|
|
||||||
|
$path =~s{(/t)?/SOAP/WSDL}{}xms;
|
||||||
|
|
||||||
|
ok $soap = SOAP::WSDL->new(
|
||||||
|
wsdl => 'file:///'.$path.'/t/acceptance/wsdl/11_helloworld.wsdl',
|
||||||
|
no_dispatch => 1
|
||||||
|
), 'Create SOAP::WSDL object';
|
||||||
|
|
||||||
|
$soap->proxy('http://helloworld/helloworld.asmx');
|
||||||
|
|
||||||
|
ok $soap->wsdlinit(
|
||||||
|
servicename => 'Service1',
|
||||||
|
), 'wsdlinit';
|
||||||
|
|
||||||
|
|
||||||
|
ok $soap->call('sayHello', 'sayHello' => $data), 'soap call';
|
||||||
|
|
||||||
@@ -1,36 +1,34 @@
|
|||||||
|
use strict;
|
||||||
use lib '../lib';
|
use lib '../lib';
|
||||||
use Test;
|
use Test::More tests => 4;
|
||||||
use SOAP::WSDL;
|
use SOAP::WSDL;
|
||||||
use Cwd;
|
use Cwd;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
use File::Basename;
|
||||||
plan tests => 9;
|
|
||||||
|
|
||||||
print "# Using SOAP::WSDL Version $SOAP::WSDL::VERSION\n";
|
print "# Using SOAP::WSDL Version $SOAP::WSDL::VERSION\n";
|
||||||
|
|
||||||
my $name = '02_port';
|
my $name = '02_port';
|
||||||
|
|
||||||
# chdir to my location
|
# chdir to my location
|
||||||
my $cwd = cwd;
|
my $soap = undef;
|
||||||
|
|
||||||
|
my $path = cwd;
|
||||||
|
|
||||||
if (-d 't')
|
$path =~s{(/t)?/SOAP/WSDL}{}xms;
|
||||||
{
|
|
||||||
$cwd .= '/t';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
my $url = 'http://127.0.0.1/testPort';
|
my $url = 'http://127.0.0.1/testPort';
|
||||||
|
|
||||||
|
|
||||||
ok(1);
|
|
||||||
|
|
||||||
ok( $soap = SOAP::WSDL->new(
|
ok( $soap = SOAP::WSDL->new(
|
||||||
wsdl => 'file:///' . $cwd . '/acceptance/wsdl/' . $name . '.wsdl'
|
wsdl => 'file:///' . $path . '/t/acceptance/wsdl/' . $name . '.wsdl'
|
||||||
) );
|
) );
|
||||||
ok( ($soap->servicename('testService') eq 'testService' ) );
|
|
||||||
ok( ($soap->portname('testPort') eq 'testPort' ) );
|
|
||||||
|
|
||||||
ok( $soap->wsdlinit( url => $url ) );
|
ok $soap->wsdlinit( url => $url );
|
||||||
|
ok $soap->servicename('testService');
|
||||||
|
ok $soap->portname('testPort');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
use Test::More tests => 3;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use lib '../lib';
|
||||||
|
|
||||||
|
use_ok('SOAP::WSDL::XSD::Typelib::Builtin::string');
|
||||||
|
my $obj;
|
||||||
|
|
||||||
|
$obj = SOAP::WSDL::XSD::Typelib::Builtin::string->new();
|
||||||
|
|
||||||
|
$obj->set_value( '& "Aber" <test>');
|
||||||
|
|
||||||
|
|
||||||
|
is $obj, '& &qout;Aber&qout; <test>'
|
||||||
|
, 'escape text on serialization';
|
||||||
|
|
||||||
|
is $obj->serialize({ name => 'test'})
|
||||||
|
, '<test >& &qout;Aber&qout; <test></test >'
|
||||||
|
, 'Serialization with name';
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
use Test::More tests => 2;
|
|
||||||
use lib '../lib';
|
|
||||||
use lib 't/lib';
|
|
||||||
use lib 'lib';
|
|
||||||
use Cwd;
|
|
||||||
use File::Basename;
|
|
||||||
|
|
||||||
our $SKIP;
|
|
||||||
eval "use Test::SOAPMessage";
|
|
||||||
if ($@) {
|
|
||||||
$SKIP = "Test::Differences required for testing. $@";
|
|
||||||
}
|
|
||||||
|
|
||||||
use_ok qw/SOAP::WSDL/;
|
|
||||||
|
|
||||||
my $soap = SOAP::WSDL->new();
|
|
||||||
|
|
||||||
|
|
||||||
TODO: {
|
|
||||||
local $TODO="implement <choice> support";
|
|
||||||
fail "serialize choice element";
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
#!/usr/bin/perl -w
|
|
||||||
#######################################################################################
|
|
||||||
#
|
|
||||||
# 2_helloworld.t
|
|
||||||
#
|
|
||||||
# Acceptance test for message encoding, based on .NET wsdl and example code.
|
|
||||||
# SOAP::WSDL's encoding doesn't I<exactly> match the .NET example, because
|
|
||||||
# .NET doesn't always specify types (SOAP::WSDL does), and the namespace
|
|
||||||
# prefixes chosen are different (maybe the encoding style, too ? this would be a bug !)
|
|
||||||
#
|
|
||||||
########################################################################################
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use diagnostics;
|
|
||||||
use Test;
|
|
||||||
plan tests => 5;
|
|
||||||
use Time::HiRes qw( gettimeofday tv_interval );
|
|
||||||
use lib '../..';
|
|
||||||
use Cwd;
|
|
||||||
use File::Basename;
|
|
||||||
|
|
||||||
use SOAP::WSDL;
|
|
||||||
ok 1; # if we made it this far, we're ok
|
|
||||||
### test vars END
|
|
||||||
print "Testing SOAP::WSDL ". $SOAP::WSDL::VERSION."\n";
|
|
||||||
print "Acceptance test against sample output with simple WSDL\n";
|
|
||||||
|
|
||||||
my $data = {
|
|
||||||
name => 'test',
|
|
||||||
givenName => 'test',
|
|
||||||
};
|
|
||||||
|
|
||||||
my $t0 = [gettimeofday];
|
|
||||||
# chdir to my location
|
|
||||||
my $cwd = cwd;
|
|
||||||
my $path = dirname( $0 );
|
|
||||||
my $soap = undef;
|
|
||||||
my $name = basename( $0 );
|
|
||||||
$name =~s/\.(t|pl)$//;
|
|
||||||
chdir $path;
|
|
||||||
|
|
||||||
$path = cwd;
|
|
||||||
|
|
||||||
$path =~s{/attic}{}xms;
|
|
||||||
|
|
||||||
|
|
||||||
ok( $soap=SOAP::WSDL->new(
|
|
||||||
wsdl => 'file:///'.$path.'/acceptance/wsdl/11_helloworld.wsdl',
|
|
||||||
no_dispatch => 1
|
|
||||||
) );
|
|
||||||
|
|
||||||
$soap->serializer()->namespace('SOAP-ENV');
|
|
||||||
$soap->serializer()->encodingspace('SOAP-ENC');
|
|
||||||
|
|
||||||
print "Create SOAP::WSDL object (".tv_interval ( $t0, [gettimeofday]) ."s)\n" ;
|
|
||||||
$soap->proxy('http://helloworld/helloworld.asmx');
|
|
||||||
$t0 = [gettimeofday];
|
|
||||||
ok($soap->wsdlinit());
|
|
||||||
print "WSDL init (".tv_interval ( $t0, [gettimeofday]) ."s)\n" ;
|
|
||||||
|
|
||||||
$t0 = [gettimeofday];
|
|
||||||
do {
|
|
||||||
my $xml = $soap->call('sayHello', 'sayHello' => %{ $data });
|
|
||||||
|
|
||||||
open (FILE, "../acceptance/results/11_helloworld.xml")
|
|
||||||
|| open (FILE, "t/acceptance/results/11_helloworld.xml") || die "can't open acceptance file";
|
|
||||||
my $xml_test=<FILE>;
|
|
||||||
close FILE;
|
|
||||||
$xml=~s/^.+\<([^\/]+?)\:Body\>//;
|
|
||||||
$xml=~s/\<\/$1\:Body\>.*//;
|
|
||||||
|
|
||||||
$xml_test=~s/^.+\<([^\/]+?)\:Body\>//;
|
|
||||||
$xml_test=~s/\<\/$1\:Body\>.*//;
|
|
||||||
|
|
||||||
if ( ($xml) && ($xml eq $xml_test) ) {
|
|
||||||
ok 1;
|
|
||||||
print "Message encoding (" .tv_interval ( $t0, [gettimeofday]) ."s)\n"
|
|
||||||
} else {
|
|
||||||
ok 0;
|
|
||||||
print "Message encoding (".tv_interval ( $t0, [gettimeofday]) ."s)\n" ;
|
|
||||||
print "$xml\n$xml_test\n"; };
|
|
||||||
};
|
|
||||||
|
|
||||||
$t0 = [gettimeofday];
|
|
||||||
do {
|
|
||||||
my $xml = $soap->call(sayHello => %{ $data });
|
|
||||||
|
|
||||||
open (FILE, "../acceptance/results/11_helloworld.xml")
|
|
||||||
|| open FILE, ("t/acceptance/results/11_helloworld.xml") || die "can't open acceptance file";
|
|
||||||
my $xml_test=<FILE>;
|
|
||||||
close FILE;
|
|
||||||
$xml=~s/^.+\<([^\/]+?)\:Body\>//;
|
|
||||||
$xml=~s/\<\/$1\:Body\>.*//;
|
|
||||||
|
|
||||||
$xml_test=~s/^.+\<([^\/]+?)\:Body\>//;
|
|
||||||
$xml_test=~s/\<\/$1\:Body\>.*//;
|
|
||||||
|
|
||||||
if ( ($xml) && ($xml eq $xml_test) ) {
|
|
||||||
ok 1;
|
|
||||||
print "Message encoding (" .tv_interval ( $t0, [gettimeofday]) ."s)\n";
|
|
||||||
} else {
|
|
||||||
ok 0;
|
|
||||||
print "Message encoding (".tv_interval ( $t0, [gettimeofday]) ."s)\n" ;
|
|
||||||
print "$xml\n$xml_test\n"; };
|
|
||||||
};
|
|
||||||
|
|
||||||
chdir $cwd;
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
use Test::More;
|
|
||||||
eval "use Test::Pod 1.00";
|
|
||||||
plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
|
|
||||||
|
|
||||||
use Cwd;
|
|
||||||
|
|
||||||
my $dir = cwd;
|
|
||||||
|
|
||||||
if ( $dir =~ /t$/ )
|
|
||||||
{
|
|
||||||
@directories = ('../lib/');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@directories = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
my @files = all_pod_files(
|
|
||||||
@directories
|
|
||||||
);
|
|
||||||
|
|
||||||
plan tests => scalar(@files);
|
|
||||||
|
|
||||||
foreach my $module (@files)
|
|
||||||
{
|
|
||||||
pod_file_ok( $module )
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
use Test::More;
|
|
||||||
eval "use Test::Pod::Coverage 1.00";
|
|
||||||
plan skip_all => "Test::Pod::Coverage 1.00 required for testing POD" if $@;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BEGIN
|
|
||||||
{
|
|
||||||
if (-d 't') # chdir into test directory if we
|
|
||||||
{ # are not there (make test)
|
|
||||||
chdir 't';
|
|
||||||
@dirs = '../blib/lib';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
@dirs = ('../lib');
|
|
||||||
use lib '../lib'; # use our lib if we are in t/ (if we are, we're)
|
|
||||||
# not run from "make test" / "Build test"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@files = all_modules( @dirs );
|
|
||||||
plan tests => scalar @files;
|
|
||||||
foreach (@files)
|
|
||||||
{
|
|
||||||
s/^\.\.::blib::lib:://;
|
|
||||||
s/^\.\.::lib:://;
|
|
||||||
pod_coverage_ok( $_ );
|
|
||||||
}
|
|
||||||
@@ -6,12 +6,12 @@ use lib '../../lib';
|
|||||||
use SOAP::WSDL::XSD::Typelib::ComplexType;
|
use SOAP::WSDL::XSD::Typelib::ComplexType;
|
||||||
use base ('SOAP::WSDL::XSD::Typelib::ComplexType');
|
use base ('SOAP::WSDL::XSD::Typelib::ComplexType');
|
||||||
|
|
||||||
my %MyTestName_of; # no :ATTR - _factory takes care of
|
my %MyTestName_of :ATTR(:get<MyTestName>);
|
||||||
|
|
||||||
__PACKAGE__->_factory(
|
__PACKAGE__->_factory(
|
||||||
[ qw(MyTestName) ], # order
|
[ qw(MyTestName) ], # order
|
||||||
{ MyTestName => \%MyTestName_of }, # attribute lookup map
|
{ MyTestName => \%MyTestName_of }, # attribute lookup map
|
||||||
{ MyTestName => 'MyElement' } # class name lookup map
|
{ MyTestName => 'SOAP::WSDL::XSD::Typelib::Builtin::string' } # class name lookup map
|
||||||
);
|
);
|
||||||
|
|
||||||
sub get_xmlns { 'urn:Test' };
|
sub get_xmlns { 'urn:Test' };
|
||||||
|
|||||||
+18
-16
@@ -9,11 +9,20 @@ use base (
|
|||||||
'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
||||||
);
|
);
|
||||||
|
|
||||||
sub START {
|
__PACKAGE__->__set_name('MyElementName');
|
||||||
my ($self, $ident, $args_of) =@_;
|
sub get_xmlns { 'urn:Test' };
|
||||||
$self->__set_name('MyElementName');
|
|
||||||
}
|
package MyComplexTypeElement;
|
||||||
|
use strict;
|
||||||
|
use Class::Std::Storable;
|
||||||
|
use SOAP::WSDL::XSD::Typelib::Element;
|
||||||
|
use MyComplexType;
|
||||||
|
use base (
|
||||||
|
'SOAP::WSDL::XSD::Typelib::Element',
|
||||||
|
'MyComplexType',
|
||||||
|
);
|
||||||
|
|
||||||
|
__PACKAGE__->__set_name('MyComplexTypeElement');
|
||||||
sub get_xmlns { 'urn:Test' };
|
sub get_xmlns { 'urn:Test' };
|
||||||
|
|
||||||
package MyTestElement;
|
package MyTestElement;
|
||||||
@@ -26,10 +35,6 @@ use base (
|
|||||||
'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
||||||
);
|
);
|
||||||
|
|
||||||
sub START {
|
|
||||||
my ($self, $ident, $args_of) =@_;
|
|
||||||
}
|
|
||||||
|
|
||||||
__PACKAGE__->__set_name('MyTestElement');
|
__PACKAGE__->__set_name('MyTestElement');
|
||||||
|
|
||||||
sub get_xmlns { 'urn:Test' };
|
sub get_xmlns { 'urn:Test' };
|
||||||
@@ -44,12 +49,9 @@ use base (
|
|||||||
'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
'SOAP::WSDL::XSD::Typelib::Builtin::string',
|
||||||
);
|
);
|
||||||
|
|
||||||
sub START {
|
__PACKAGE__->__set_name('MyTestElement2');
|
||||||
my ($self, $ident, $args_of) =@_;
|
|
||||||
$self->__set_name('MyTestElement2');
|
|
||||||
}
|
|
||||||
sub get_xmlns { 'urn:Test' };
|
sub get_xmlns { 'urn:Test' };
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
package MyAtomicComplexTypeElement;
|
package MyAtomicComplexTypeElement;
|
||||||
@@ -63,7 +65,7 @@ use base (
|
|||||||
'SOAP::WSDL::XSD::Typelib::Element',
|
'SOAP::WSDL::XSD::Typelib::Element',
|
||||||
'SOAP::WSDL::XSD::Typelib::ComplexType',
|
'SOAP::WSDL::XSD::Typelib::ComplexType',
|
||||||
);
|
);
|
||||||
|
|
||||||
my %test_of :ATTR(:get<test>);
|
my %test_of :ATTR(:get<test>);
|
||||||
my %test2_of :ATTR(:get<test2>);
|
my %test2_of :ATTR(:get<test2>);
|
||||||
|
|
||||||
@@ -76,12 +78,12 @@ __PACKAGE__->_factory(
|
|||||||
test2 => \%test2_of,
|
test2 => \%test2_of,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
# this is the <element ref="" variant....
|
||||||
test => 'MyTestElement',
|
test => 'MyTestElement',
|
||||||
test2 => 'MyTestElement2',
|
test2 => 'MyTestElement2',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
__PACKAGE__->__set_name('MyAtomicComplexTypeElement');
|
__PACKAGE__->__set_name('MyAtomicComplexTypeElement');
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
Reference in New Issue
Block a user