Nov 22, 2011

Generating proper XML with Perl

Once upon a time I was asked by one of our javadevelopers if i can send a csv in proper xml to one of his webservices. Of course I can. As usual i decided to use perl and Text::CSV to read in the CSV as well as LWP::UserAgent to send the xml to the (soap-)webservice.

After having a second look on the code, where I put in several nodes at the fourth level of the xml-tree, managing all the intents just via print, I found myself doing something like this:
foreach my $key(keys %hasharr) {
my ($foo,$bar,$value1,$value2,$value3,$value4) = @{$hasharr{$key}};
print XML "\t\t\t\t<base>\n\t\t\t\t\t<key>\n\t\t\t\t\t\t".
$key."\n\t\t\t\t\t</key>\n\t\t\t\t\t<foo>\n\t\t\t\t\t\t".
$foo."\n\t\t\t\t\t</foo>\n\t\t\t\t\t<timestamp>\n\t\t\t\t\t\t".
$value1."\n\t\t\t\t\t</timestamp>\n\t\t\t\t\t<originator>\n\t\t\t\t\t\t".
$value2."\n\t\t\t\t\t</originator>\n\t\t\t\t\t<remote-server>\n\t\t\t\t\t\t".
$value3."\n\t\t\t\t\t</remote-server>\n\t\t\t\t\t<category>\n\t\t\t\t\t\t".
$value4."\n\t\t\t\t\t</category>\n\t\t\t\t\t<diagnostic-string>\n\t\t\t\t\t\t<![CDATA[".$bar."]]>\n\t\t\t\t\t</diagnostic-string>\n\t\t\t\t</base>\n";
}

So not only this looks very ugly it is also very hard to edit afterwards. I was playing around a bit with "XML::Smart" which was a hint by one of my friends. Unfortunately I again found why I always hated products which call themselves "Smart" like "S.M.A.R.T" or "Smarty", it is because they all label their Product as smart, while in some cases it maybe is, in this it wasn't. I don't like tools to be smart. I like people beeing smart or solutions beeing smart. Tools should just work.
So I found "XML::LibXML" which is a perl-Interface to the most commonly used library in C. It was not only much faster than XML::Smart, it also worked in my rather curious circumstances. But as well as for many other XML-Modules, while there were plenty of examples for parsing, dumping data and validating xml, I can't find a simple example on how to generate xml.
So here's mine:
#!/usr/bin/perl
use XML::LibXML;
#the XML doc itself:
my $xml = XML::LibXML::Document->new( '1.0', 'UTF-8');
#the root node:
my $root=$xml->createElement( 'foo' );
#append a node with textcontent:
$root->appendTextChild('bar','fubafubafubalalalala');
#append a node with CDATA Content, kind of tricky:
my $content = ' fuubaaa cdata ';
my $newnode = XML::LibXML::Element->new('fubacdata');
my $cdata = XML::LibXML::CDATASection->new($content);
$newnode->appendChild($cdata);
$root->appendChild( $newnode );
#put all back in the document:
$xml->setDocumentElement($root);
#print it pretty:
print $xml->toString(2);
This is the output you will get from that:
If you have any questions, rants, suggestions for me, just leave them in the comments below.

1 comment:

  1. clear, concise, short comment with enough code to illustrate.

    thanks for the post :)

    ReplyDelete