The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

SOAP::WSDL::SAX::MessageHandler - Convert SOAP messages to custom object trees

SYNOPSIS

 # this is the direct variant, recommended for performance
 use SOAP::WSDL::SAX::MessageHandler;
 use XML::LibXML;

 my $filter = SOAP::WSDL::SAX::MessageHandler->new( {
    class_resolver => FakeResolver->new()
 ), "Object creation");
 my $parser = XML::LibXML->new();
 $parser->set_handler( $filter );

 $parser->parse_string( $soap_message );

 my $object_tree = $filter->get_data();


 # This is the XML::ParserFactory variant - for those who want other
 # parsers than XML::Simple....
 use SOAP::WSDL::SAX::MessageHandler;
 use XML::SAX::ParserFactory;

 my $filter = SOAP::WSDL::SAX::MessageHandler->new( {
    class_resolver => FakeResolver->new(),
    base => 'XML::SAX::Base',
 ), "Object creation");
 my $parser = XML::LibXML->new();
 $parser->set_handler( $filter );

 $parser->parse_string( $soap_message );

 my $object_tree = $filter->get_data();

DESCRIPTION

Parses a SOAP message into an object tree.

For every element in the SOAP message, an object is created. The class of the object is determined via a Resolver object which has to be passed to new via the class_resolver parameter.

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;

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

  • new

    Constructor

  • 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.

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.

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...

Bugs and Limitations

  • Ignores all namespaces

  • Does not handle mixed content

  • The SOAP header is ignored

AUTHOR

Replace the whitespace by @ for E-Mail Address.

 Martin Kutter E<lt>martin.kutter fen-net.deE<gt>

COPYING

This module may be used under the same terms as perl itself.

Repository information

 $ID: $

 $LastChangedDate: $
 $LastChangedRevision: $
 $LastChangedBy: $

 $HeadURL: $