Finally, we come to the category of Perl and XML software that is so ridiculously abstracted from the book's topic that it's almost not worth covering, but it's definitely much more worth showing off. This category describes modules and extensions that are similar to the XML::RSS class helper modules; they help you work with a specific variety of XML documents, but set themselves apart by the level of aggression they employ to keep programmers separated from the raw, element-encrusted data flowing underneath it. They involve enough layers of abstraction to make you forget that you're even dealing with XML in the first place.
Of course, they're perfectly valid in doing so; for example, if we want to write a program that uses the SOAP or XML-RPC protocols to use remote code, nothing could be further from our thoughts than XML. It's all a magic carpet, as far as we're concerned -- we just want our program to work! (And when we do care, a good module lets us peek at the raw XML, if we insist.)
The Simple Object Access Protocol (SOAP) gives you the power of object-oriented web services by letting you construct and use objects whose class definitions exist at the other end of a URI. You don't even need to know what programming language they use because the protocol magically turns the object's methods into a common, XML-based API. As long as the class is documented somewhere, with more details of the available class and object methods, you can hack away as if the class was simply another file on your hard drive, despite the fact that it actually exists on a remote machine.
At this point it's entirely too easy to forget that we're working with XML. At least with RSS, the method names of the object API more or less match those of the resulting output document; in this case, We don't even want to see the horrible machine-readable-only document any more than we'd want to see the numeric codes representing keystrokes that are sent to our machine's CPU.
SOAP::Lite's name refers to the amount of work you have to apply when you wish to use it, and does not reflect its own weight. When you install it on your system, it makes a long list of Perl packages available to you, many of which provide a plethora of transportation styles, a mod_perl module to assist with SOAPy web serving, and a whole lot of documentation and examples. Then it does most of this all over again with a set of modules providing similar APIs for XML-RPC, SOAP's non-object-oriented cousin. SOAP::Lite is one of those seminal all-singing, all-dancing tools for Perl programmers, doing for web service programming what CGI.pm does for dynamic web site programming.
Let's get our hands dirty with SOAP.
9.4.1. First Example: A Temperature Converter
Every book about programming needs some temperature-conversion code in it somewhere, right? Well, we don't quite have that here. In this example, lovingly ripped off from the SYNOPSIS section of the documentation for SOAP::Lite, we write a program whose main function, f2c, lives on whatever machine answers to the URI http://services.soaplite.com/Temperatures.
use SOAP::Lite; print SOAP::Lite -> uri('http://www.soaplite.com/Temperatures') -> proxy('http://services.soaplite.com/temper.cgi') -> f2c(32) -> result;
Executing this program as a Perl script (on a machine with SOAP::Lite properly installed) gives the correct response: 0.
9.4.2. Second Example: An ISBN Lookup Engine
This example, which uses a little module residing on one of the author's personal web servers, is somewhat more object oriented. It takes an ISBN number and returns Dublin Core XML for almost any book that might match it:
my ($isbn_number) = @ARGV; use SOAP::Lite +autodispatch=> uri=>'http://www.jmac.org/ISBN', proxy=>'http://www.jmac.org/projects/bookdb/isbn/lookup.pl'; my $isbn_obj = ISBN->new; # The 'get_dc' method fetches Dublin Core information my $result = $isbn_obj->get_dc($isbn_number);
The magic here is that the module on the host machine, ISBN.pm, isn't unusual in any way; it's a pretty straightforward Perl module that you could use in the usual fashion, if you happened to have a local copy. In other words, we can get the same results by logging into the machine and hammering out a little program like this:
my ($isbn_number) = @ARGV; use ISBN; # This line replaces the long 'use SOAP::Lite' line my $isbn_obj = ISBN->new; # The 'get_dc' method fetches Dublin Core information my $result = $isbn_obj->get_dc($isbn_number);
But, by invoking SOAP::Lite and mumbling a few extra incantations to aim our sights at a remote machine that's listening for SOAP-ish requests, you don't need a copy of that Perl module on your end to enjoy the benefits of its API. And, if we eventually went insane and reimplemented the module in Java, you'd probably never know it, since we'd keep the interface the same. In the language-independent world of web services, that's all that matters.
Where is the XML? We can switch on a valve and peek at the raw stuff roaring beneath this pleasant veneer. Let's see what actually happens with that ISBN class constructor call after we activate SOAP::Lite's outputxml option:
my ($isbn_number) = @ARGV; use SOAP::Lite +autodispatch=> uri=>'http://www.jmac.org/ISBN', outputxml=>1, proxy=>'http://www.jmac.org/projects/bookdb/isbn/lookup.pl'; my $isbn_xml = ISBN->new; print "$isbn_xml\n";
What we get back is something like this:
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENC="http:// schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap. org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns: xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/ XMLSchema" xmlns:namesp1="http://www.jmac.org/ISBN"><SOAP-ENV:Body><namesp2: newResponse xmlns:namesp2="http://www.jmac.org/ISBN"><ISBN xsi:type="namesp1:ISBN"/> </namesp2:newResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
The second bit of example code had to stop short, of course, since it returned a scalar containing a pile of XML (which we then printed) instead of an object belonging to the SOAP::Lite class family. We can't well continue calling methods on it. We can fix this problem by passing the blob to the magic SOAP::Deserializer class, which turns SOAPy XML back into objects:
# Continuing from the previous snippet... my $deserial = SOAP::Deserializer->new; my $isbn_obj = $deserial->deserialize($isbn_xml); # Now we can continue as with the first example.
A little extra work, then, nets us the raw XML as well as the black boxes of the SOAP::Lite objects. As you may expect, this feature has uses far beyond interesting book examples, as getting the raw XML in hand opens up the door to all kinds of interesting mischief on our end.
While SOAP::Lite the Perl module is magic in diverse ways, SOAP the protocol is just, well, a protocol, and all the strange namespaces, elements, and attributes seen in the XML generated by this module are compliant to the world-readable SOAP specification. This compliance allows you to apply a cunning plan to your SOAP-using application, with which you let the SOAP::Lite module do its usual magic -- but then your program leaps in, captures the raw XML, does something strange and wonderful with it (it can be parsed with any method we've covered so far), and then perhaps return control back to SOAP::Lite.
Admittedly, most of SOAP::Lite doesn't require a fingernail's width of knowledge about XML processing in Perl, as most applications will probably be content with its prepackaged functionality. If you want to get really tricky with it, though, it welcomes your meddling. Knowledge is power, my friend.
Copyright © 2002 O'Reilly & Associates. All rights reserved.