advertisement

Listen Print

Using XML Modules in Perl
Pages: 1, 2

Diving Right In

Enter XMLRPC::Lite. Paul Kulchenko's XMLRPC::Lite is a Perl implementation of the XML-RPC protocol. XML-RPC does lots of things that you can read about at www.xmlrpc.com, but the most desirable feature of XMLRPC::Lite, with regards to my application, is one's ability to use it to call a subroutine -- with arguments -- on the remote end of the connection (and really using any transport, including http).



By using a hash reference, I could easily pass %HoH over the network as an argument to a function that lives on my "report server", which would - in turn - expand the %HoH as XML. Bear in mind that your XML-RPC program doesn't have to be written in Perl at all, but for the sake of this exercise, it will be!

Using XMLRPC::Lite is a two-phase process. First, you'll need to write a program that lives on the remote (server) end of your connection. My suggestion is to store your function(s) in a module that gets "used" by your XMLRPC::Lite program. Let's say that you write a module called ExpandHoH that implements a function called hoh_to_xml. Here's what ExpandHoH.pm looks like:

package ExpandHoH;

sub hoh_to_xml {
    shift; # remove 'ExpandHoH'
    my $hoh = shift; # our ref to %HoH

    # Ordinarily, we'd use something like XML::Simple here
    # to expand $hoh as XML.  But for the sake of simplicity
    # we'll simply make sure that what we've got is a
    # hash and return a status message.
    if(ref($hoh) eq 'HASH') {
        return 'OK';
    } else {
        return 'NOT OK';
    }
}

1;
END questionable text-->

You won't be "using" the module directly from your client program, however. You'll write a program that uses 'ExpandHoH', and calls the appropriate function with a reference to %HoH as the argument. Let's call the program expand_hoh:

#!/usr/local/bin/perl -w

use XMLRPC::Transport::HTTP;

# we'll use http and dispatch to 'ExpandHoH'.
XMLRPC::Transport::HTTP::CGI
    -> dispatch_to('ExpandHoH')
    -> handle
    ;

And here's the program that you'll run on the "client" end of the connection. Basically, you'll populate %HoH with your system's configuration information, will create a reference to it, and pass this reference to ExpandHoH.hoh_to_xml. In the end, you'll get a status from the server by way of result():

#!/usr/local/bin/perl -w

use XMLRPC::Lite; # or XMLRPC::Lite ``+trace" if you'd like

my $proxy = 'http://my.server.here/cgi-bin/expand_hoh';
my %HoH = (
    # system configuration stuff here
    );
my $ref_hoh = { %HoH };

my $xlite= XMLRPC::Lite
    -> proxy($proxy)
    -> call('ExpandHoh.hoh_to_xml', $ref_hoh);

my $status = $xlite->result;
# do something with $status here.

If all goes well, your client will receive an 'OK' status from the server.

We bustled through that pretty quickly. But it wasn't due to lack of interest! Just when you thought that it was all about %HoH, the tables are turn, and you find yourself smack in the middle of XML.

There are many XML-related modules in Perl: XML::Parser, XML::DOM, XML::Twig, to name a few. If you're getting your feet wet with XML and Perl, or you're just looking for something quick 'n' dirty to read (and write) XML files, you might consider using XML::Simple. Let's say that you have XML like the following:

<hosts>
  <host name="atlas" osname="Solaris">
    <addr>192.168.0.100</addr>
    <addr>192.168.0.101</addr>
    <addr>192.168.0.150</addr>
  </host>
  <host name="dns" osname="Linux">
    <addr>192.168.0.2</addr>
    <addr>192.168.0.3</addr>
  </host>
</hosts>

You can easily generate a %HoH from the above XML with XML::Simple:

#!/usr/local/bin/perl -w

use XML::Simple;

my $infile = 'configs.xml';
my $xml    = XMLin(); # read configs.xml into $xml

print XMLout($xml), "\n"; # show us how the XML looks

You might've noticed that the above code generates XML that isn't identical to the markup in configs.xml. One of the things that you'll need to be careful of if you use XML::Simple is that you provide XMLin() and XMLout() with the appropriate arguments so that your XML formatting is preserved, and so you don't accidentally fold attributes into your XML (elements) that you hadn't intended. You can cure the above code as follows:

#!/usr/local/bin/perl -w

use XML::Simple;

my $infile = 'configs.xml';
my $xml    = XMLin($infile, keeproot => 1, forcearray => 1, keyattr => []);

print XMLout($xml, keeproot => 1, keyattr => []), "\n";

Now that you've been thrown into shark-infested waters, and you don't hear Spielberg yell "cut!", let's throw you a line so that we can tie everything together (or: insert your own quip or cliché here).

Let's close things out by reviewing 2 key parts that we'd glossed over earlier. We'll start with XMLout() first. XMLout($hash_ref) lives in XML::Simple, and allows you to write a XML file from the contents of $hash_ref. $hash_ref, eh? Sound familiar? Second, if you were thinking, "hey, I just saw something about a hashref in that XMLRPC::Lite program!", then you're correct. We'll pass $hash_ref to ExpandHoH::hoh_to_xml(), which will in turn call XMLout($hash_ref). XMLout($hash_ref) will then generate the XML and write it somewhere on the remote end of the connection. Here's the revised ExpandHoH:

package ExpandHoH;

use XML::Simple; # needed for XMLout()

sub hoh_to_xml {
    shift; # remove 'ExpandHoH'
    my $hoh = shift; # our ref to %HoH

    # Expand $hoh to XML with XMLout().
    if(ref($hoh) eq 'HASH') {
        my $outfile = "/tmp/temp_xml.$$"; # for now, be temp

        XMLout($hoh, rootname => 'config', outputfile => $outfile, keyattr => []);
        if($@) { # XMLout() found an error somewhere
            return 'NOT OK';
        } else {
            return 'OK';
        }
    } else {
        return 'NOT OK';
    }

So, there you have it: a little bit of XML, a little bit of XML-RPC, and a rasher of corniness. While this article could've done things in slightly different ways, I'm a firm believer in "TMTOWTDI". So, sure, it would've been possible to use XML::Parser or XML::Dumper instead of the modules I chose for this article. In fact, if you've been looking to implement something similar to what was covered here, I suggest that you try exploring any XML/XML-RPC Perl modules you can find.

And finally, if you're curious, I'll be releasing the system-reporting application at some point in the near future. I haven't decided on licensing terms yet; nor have I developed a suitable mechanism for you to install it on your systems. But, watch this space. It'll be soon!

O'Reilly & Associates recently released (June 2002) Perl in a Nutshell, 2nd Edition.

Nathan Patwardhan was a software developer and system administrator for Banta Integrated Media in Cambridge, MA.


Return to the O'Reilly Network.