package SOAP::WSDL::Generator::Iterator::WSDL11;
use strict; use warnings;
use Class::Std::Fast;
our $VERSION = 3.003;
my %definitions_of :ATTR(:name<definitions> :default<[]>);
my %nodes_of :ATTR(:name<nodes> :default<[]>);
# memoization attributes
my %portType_of :ATTR();
my %types_of :ATTR();
my %METHOD_OF = (
'SOAP::WSDL::Definitions' => 'get_service',
'SOAP::WSDL::Service' => 'get_port',
'SOAP::WSDL::Port' => sub {
my ($self, $node) = @_;
return if ! $node->first_address()
or ! $node->first_address()->isa('SOAP::WSDL::SOAP::Address');
return [ $self->get_definitions()
->find_binding( $node->expand( $node->get_binding() ) ) || () ];
},
'SOAP::WSDL::Binding' => sub {
my ($self, $node) = @_;
# remember referenced portType
$portType_of{ ident $self } = $self->get_definitions()
->find_portType( $node->expand( $node->get_type ) )
or return [];
return $node->get_operation();
},
'SOAP::WSDL::Operation' => sub {
my ($self, $node) = @_;
my $name = $node->get_name();
# get the equally named operation from the portType
my ($op) = grep { $_->get_name() eq $name }
@{ $portType_of{ ident $self }->get_operation() }
or return [];
return [ @{ $op->get_input }, @{ $op->get_output }, @{ $op->get_fault } ]
},
'SOAP::WSDL::OpMessage' => sub {
my ($self, $node) = @_;
return if ( ref $node->get_parent() eq 'SOAP::WSDL::Binding' ); # we're in binding
# TODO maybe allow more messages && overloading by specifying name
return [ $self->get_definitions()->find_message(
$node->expand( $node->get_message() )
) || () ];
},
'SOAP::WSDL::Message' => 'get_part',
'SOAP::WSDL::Part' => sub {
my ($self, $node) = @_;
my $ident = ident $self;
my $types = $types_of{ $ident } = $definitions_of{ $ident }->get_types()->[0]
or return [];
return [
# If we have a type, this type is to be used in document/literal
# as global type. However this is forbidden, at least by WS-I.
# We should store the style/encoding somewhere, and regard it.
# TODO: auto-generate element for RPC bindings
$node->get_type()
? do {
die "unsupported global type <"
. $node->get_type . "> found in part <". $node->get_name() . ">\n"
. "Looks like a rpc/literal WSDL, which is not supported by SOAP::WSDL\n";
## use this once we can auto-generate an element for RPC bindings
# $types->find_type( $node->expand($node->get_type) )
}
: (),
$node->get_element()
? $types->find_element( $node->expand($node->get_element) )
: (),
];
},
);
sub init {
my ($self, $arg_of) = @_;
my $ident = ident $self;
undef $portType_of{ $ident };
undef $types_of{ $ident };
$nodes_of{ $ident } = [
exists($arg_of->{ node })
? $arg_of->{ node }
: $definitions_of{ ident $self }
];
}
sub get_next {
my $self = shift;
my $ident = ident $self;
my $node = shift @{ $nodes_of{ $ident }};
return if ! defined $node;
unshift @{ $nodes_of{ $ident }}, @{ $self->get_nextNodes( $node ) || [] };
return $node;
}
sub get_nextNodes {
my ($self, $node) = @_;
my $method = $METHOD_OF{ ref $node }
or return [];
return (ref($method) eq 'CODE')
? $method->( $self, $node )
: $node->can($method)->( $node );
}
1;
__END__
=pod
=head1 NAME
SOAP::WSDL::Generator::Iterator::WSDL11 - WSDL 1.1 Iterator
=head1 SYNOPSIS
my $iter = SOAP::WSDL::Generator::Iterator::WSDL11->new({
definitions => $wsdl
});
$iter->init();
while (my $node = $iter->get_next()) {
# do something with node - possibly call _accept with a visitor on it...
}
=head1 DESCRIPTION
Iterator for walking a WSDL 1.1 definition.
The iterator performs a depth-first search along the following path:
service
port
binding
operation
input/output/fault of operation in portType
message
part
type/element in XML schema
If you wonder about this path: This is how to look up which XML Schema element
is associated with a operation from a service/port.
=head2 Example
The nodes are returned in the order denoted in the following example:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 1 -->
<definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:s0="urn:HelloWorld"
targetNamespace="urn:HelloWorld"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema elementFormDefault="qualified" targetNamespace="urn:HelloWorld">
<!-- 9 -->
<s:element name="sayHello">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="name" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="givenName" type="s:string" nillable="1" />
</s:sequence>
<s:attribute name="testAttr" type="s:string" use="optional"></s:attribute>
</s:complexType>
</s:element>
<!-- 13 -->
<s:element name="sayHelloResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1"
name="sayHelloResult" type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</types>
<!-- 7 -->
<message name="sayHelloSoapIn">
<!-- 8 -->
<part name="parameters" element="s0:sayHello" />
</message>
<!-- 11 -->
<message name="sayHelloSoapOut">
<!-- 12 -->
<part name="parameters" element="s0:sayHelloResponse" />
</message>
<portType name="Service1Soap">
<operation name="sayHello">
<!-- 6 -->
<input message="s0:sayHelloSoapIn" />
<!-- 10 -->
<output message="s0:sayHelloSoapOut" />
</operation>
</portType>
<!-- 4 -->
<binding name="Service1Soap" type="s0:Service1Soap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<!-- 5 -->
<operation name="sayHello">
<soap:operation soapAction="urn:HelloWorld#sayHello"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<!-- 2 -->
<service name="Service1">
<!-- 3 -->
<port name="Service1Soap" binding="s0:Service1Soap">
<soap:address
location="http://localhost:81/soap-wsdl-test/helloworld.pl" />
</port>
</service>
</definitions>
You should not rely too much on this order - it may change. Even though the
current order will probably remain, the nodes currently skipped might
be returned somewhere along the path.
=head1 LICENSE AND COPYRIGHT
Copyright 2004-2008 Martin Kutter.
This file is part of SOAP-WSDL. You may distribute/modify it under
the same terms as perl itself
=head1 AUTHOR
Martin Kutter E<lt>martin.kutter fen-net.deE<gt>
=head1 REPOSITORY INFORMATION
$Rev: 239 $
$LastChangedBy: kutterma $
$Id: Client.pm 239 2007-09-11 09:45:42Z kutterma $
$HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Client.pm $
=cut