SOAP::...Parser(3pm)

πŸ’– SOAP::...Parser(3pm) πŸ’–

okay bestie, so this is the SOAP::...Parser(3pm) page, and it's literally the lore drop on how SOAP::WSDL parses XML. no cap. let's get into it πŸ¦‹


🌸 NAME 🌸

SOAP::WSDL::Manual::Parser β€” how SOAP::WSDL parses XML messages ✨


πŸ¦‹ Which XML message does SOAP::WSDL parse ? πŸ¦‹

so like, naturally there are two kinds of XML documents (or messages, same thing) that SOAP::WSDL has to parse, and there's no getting around it:

  • WSDL definitions
  • SOAP messages

and the thing is, there are different parser implementations available for SOAP messages vs. WSDL definitions. so don't go thinking one parser does it all πŸ‘‘


πŸŽ€ WSDL definitions parser πŸŽ€

πŸ’… SOAP::WSDL::Expat::WSDLParser

this one is a parser for WSDL definitions, and it's built on top of XML::Parser::Expat. iconic.

 my $parser = SOAP::WSDL::Expat::WSDLParser->new();
 my $wsdl = $parser->parse_file( $filename );

the WSDL parser creates a tree of perl objects, whose root is a SOAP::WSDL::Definitions element. like, she builds a whole lil family tree and SOAP::WSDL::Definitions is the parent 🫢


🌈 SOAP messages parser 🌈

πŸ“ SOAP::WSDL::Expat::MessageParser

SOAP::WSDL::Expat::MessageParser converts SOAP messages to SOAP::WSDL::XSD object trees.

it uses a class resolver to figure out which class a particular XML element should be of, plus type libs holding those classes. dynamic duo fr fr.

πŸŽ€ Creating a class resolver

the easiest way to make a class resolver is to just run SOAP::WSDL's generator. let the machine do it.

see wsdl2perl.

the class resolver must implement a class method "get_class", which gets 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, bestie:

 package ClassResolver;

 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 {}, 'ClassResolver' };

 sub get_class {
    my $name = join('/', @{ $_[1] });
    return ($class_list{ $name }) ? $class_list{ $name }
        : warn "no class found for $name";
 };
 1;

✨ Skipping unwanted items

sometimes there's just... unnecessary information being transported in SOAP messages. we've all been there. πŸ™ˆ

to skip XML nodes (including all child nodes), just edit the type map for the message and set the type map entry to '__SKIP__'.

in the example above, EnqueueMessage/StuffIDontNeed and all child elements are skipped.

 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',
    'EnqueueMessage/StuffIDontNeed' => '__SKIP__',
    'EnqueueMessage/StuffIDontNeed/Foo' => 'SOAP::WSDL::XSD::Builtin::string',
    'EnqueueMessage/StuffIDontNeed/Bar' => 'SOAP::WSDL::XSD::Builtin::string',
 );
⚠️ note that only SOAP::WSDL::Expat::MessageParser implements skipping elements at the time of writing. so don't come for the others, they're not doing it yet πŸ’€

🧚 Creating type lib classes

every element must have a correspondent one in the type library. no element left behind πŸ’œ

builtin types should be resolved as SOAP::WSDL::XSD::Builtin::* classes

creating a type lib is easy: just run SOAP::WSDL's generator β€” it will create both a typemap and the type lib classes for a WSDL file. two-for-one, we love that.

sometimes it is necessary to create type lib classes by hand β€” because not all WSDL definitions are complete. (rude of them, honestly.)

for writing your own lib classes, see SOAP::WSDL::XSD::Typelib::Element, SOAP::WSDL::XSD::Typelib::ComplexType and SOAP::WSDL::XSD::Typelib::SimpleType.

🌟 SOAP::WSDL::Expat::Message2Hash

transforms a SOAP message into a perl hash refs. using this parser is usually triggered by calling the "outputhash" method of SOAP::WSDL, or by using SOAP::WSDL::Deserializer::Hash.

acts somewhat like XML::Simple, but faster. ⚑

the following restrictions apply, and bestie these are non-negotiable:

  • Ignores all namespaces
  • Ignores all attributes
  • Does not handle mixed content
  • The SOAP header is ignored

πŸ’€ OLD SAX HANDLER πŸ’€

historically (iykyk), SOAP::WSDL used SAX for parsing XML. the SAX handlers were implemented as XML::LibXML handlers, which also worked with XML::SAX::ParserFactory.

support for SAX and XML::LibXML in SOAP::WSDL is discontinued, for the following reasons:

  • Speed

XML::Parser::Expat is faster than XML::LibXML β€” at least when optimized for speed.

high parsing speed is one of the key requirements for a SOAP toolkit β€” if XML serializing and (more important) deserializing are not fast enough, the whole toolkit is unusable. not a vibe.

  • Availability

XML::Parser is more popular than XML::LibXML. periodt.

  • Stability

XML::LibXML is based on the libxml2 library. several versions of libxml2 are known to have specific bugs. as a workaround, there are often several versions of libxml2 installed on one system. this may lead to problems on operating systems which cannot load more than one version of a shared library simultaneously.

XML::LibXML is also still under development, while XML::Parser has had time to stabilize. she's grown. 🌱

  • SOAP::Lite uses XML::Parser

SOAP::Lite uses XML::Parser if available. SOAP::WSDL should not require users to install both XML::Parser and XML::LibXML. that's just mean.

the old SAX handler historically used in SOAP::WSDL are not included in the SOAP::WSDL package any more.

however, they may be obtained from the "attic" directory in SOAP::WSDL's SVN repository at

https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/attic

  • 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();
  • 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. flexible queen πŸ’…


Copyright 2007 Martin Kutter.

This file is part of SOAP-WSDL. You may distribute/modify it under the same terms as perl itself.


πŸ‘‘ AUTHOR πŸ‘‘

Martin Kutter <martin.kutter fen-net.de>


πŸ“¦ REPOSITORY INFORMATION πŸ“¦

 $Rev: 391 $
 $LastChangedBy: kutterma $
 $Id: Parser.pod 391 2007-11-17 21:56:13Z kutterma $
 $HeadURL: https://soap-wsdl.svn.sourceforge.net/svnroot/soap-wsdl/SOAP-WSDL/trunk/lib/SOAP/WSDL/Manual/Parser.pod $

and that's the whole page bestie, we ate and left no crumbs πŸŽ€ this was perl v5.36.0, dated 2022-10-14, stay slay, go parse something πŸ’–

πŸ“¦ where this page comes from