XSL Transformations with Perl, Revisited - Different strokes
(Page 3 of 4 )
This next example demonstrates the capabilities of the XML::XSLT processor more than its functionality. Consider the XML file that I've used in the examples thus far:
<?xml version="1.0"?>
<portfolio name="The Bull Pit">
<stocks>
<stock symbol="KO" companyname="Coca-Cola">
<quantity>500</quantity>
<currenttradedprice>14.00</currenttradedprice>
<previoustradedprice>14.00</previoustradedprice>
</stock>
<stock symbol="GE" companyname="General Electric">
<quantity>2400</quantity>
<currenttradedprice>25.00</currenttradedprice>
<previoustradedprice>24.25</previoustradedprice>
</stock>
<stock symbol="APPLE" companyname="Apple">
<quantity>3500</quantity>
<currenttradedprice>35.00</currenttradedprice>
<previoustradedprice>38.00</previoustradedprice>
</stock>
</stocks>
</portfolio>
Let's assume that, for some quirky reason, I want to prepare a list of stocks in my portfolio. The output XML should look like this:
<stocks>
<stock>
<symbol>KO</symbol>
<companyname>CocaCola</companyname>
</stock>
<stock>
<symbol>GE</symbol>
<companyname>General Electric</companyname>
</stock>
<stock>
<symbol>APPLE</symbol>
<companyname>Apple</companyname>
</stock>
</stocks>
While I can load the XML file in a DOM object and retrieve specific nodes (and/or attributes) of interest, the exercise -- take my word for it -- will soon spiral into a complex and unmanageable piece of code.
Instead, I'll show you how to use XSLT to create a new XML structure from an existing one without much sweat. Fortunately, the XML::XSLT processor has support for the XSLT elements (to create XML elements and attributes) to get the job done.
First, here is the XSL style sheet that brings about the transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/portfolio/stocks">
<xsl:element name="stocks">
<xsl:for-each select="stock">
<xsl:element name="stock">
<xsl:element name="symbol"><xsl:value-of select="@symbol" /></xsl:element> <xsl:element name="companyname"><xsl:value-of select="@companyname" /> </xsl:element> </xsl:element> </xsl:for-each> </xsl:element>
</xsl:template>
</xsl:stylesheet>
A quick word about the XSLT style sheet listed above: note the use of the <xslt:element> XSLT element to define a custom <stocks> element. Next, I've used the <xsl:for-each> construct to iterate over the <stock> elements (in the original XML file) and created the <symbol> and <companyname> elements for each stock in my portfolio.
# /usr/bin/perl
# import required modules
use XML::XSLT;
use XML::DOM;
# define local variables
my $xslfile = "portfolio.xsl";
my $xmlfile = "portfolio.xml";
my $outputfile = "stocks.xml";
# create an instance of XSL::XSLT processor
my $xslt = eval { XML::XSLT->new ($xslfile, warnings => 1, debug
=> 0) };
# some more error handling here ...
if ($@) {
die("Sorry, Could not create an instance of the XSL
Processor using $xslfile.\n");
}
# transform the XML DOM object using the XSL style sheet
my $xml_dom = eval { $xslt->transform($xmlfile) };
# ... here ...
if ($@) {
die("Sorry, Could not transform XML file,
$xmlfile.\n"); }
# output new XML to file
eval { $xml_dom->printToFile("stocks.xml") };
# ... and finally, here.
if ($@) {
die("Sorry, Could not create new XML file,
$outputfile.\n"); }
# free up memory
$xml_dom->dispose();
$xslt->dispose();
Above, I've listed the Perl script that carries out the required transformation. You should notice one minor difference between this example and all other examples that I've demonstrated, thus far. Can you spot it? If you drilled straight down to the following code snippet, then pat yourself on the back!
// snip
# transform the XML DOM object using the XSL style sheet
my $xml_dom = eval { $xslt->transform($xmlfile) };
# ... here ...
if ($@) {
die("Sorry, Could not transform XML file, $xmlfile.\n"); }
# output new XML to file
eval { $xml_dom->printToFile("stocks.xml") };
// snip
Here, you'll see that I've stored the output of the transformation in a DOM object instead of sending it to the output screen. Of course, I'll need to store the XML data to file eventually. This is where the printToFile() method of the XML::DOM module comes in handy. I pass the name of the output file to this printToFile()method and XML::DOM module will create a file with the required XML output.
Next: Transforming the Transformed >>
More Perl Articles
More By Harish Kamath