XSL basics
I’ve been playing arround with XML and XSL transformations recently. XSL transformations may be very useful for:
- transforming XML to XML with different structure.
- converting XML to another well-known formats, as CSV or SQL. Then, you can pipe the output to another tools like awk/sqlplus or perform some complex querys in a RDBM.
- simple ordering / extracting node-values from the XML. Do you want to extract only a numeric value from a SOAP-response, if there is no a “soap fault” element?
All the above possible usages make XSL a powerful tool to deal with XML specially when integrating applications.
So, lets see a sample XML file, storing some info about music CDs:
<?xml version="1.0" encoding="ISO-8859-1"?> <catalog> <cd> <title>Empire Burlesque</title> <artist>Bob Dylan</artist> <country>USA</country> <company>Columbia</company> <price>10.90</price> <year>1985</year> </cd> <cd> <title>Hide your heart</title> <artist>Bonnie Tyler</artist> <country>UK</country> <company>CBS Records</company> <price>9.90</price> <year>1988</year> </cd> .... </catalog>
And a Java class to perform XSL transformation:
public static void main(String[] args)
throws FileNotFoundException,
TransformerException {
File inXMLFile = new File("input.xml");
File inXSLFile = new File("transformation.xsl");
File outXMLFile = new File("output.xml");
javax.xml.transform.TransformerFactory tFactory =
javax.xml.transform.TransformerFactory.newInstance();
// Get the XML input document and the stylesheet
javax.xml.transform.Source xmlSource =
new javax.xml.transform.stream.StreamSource(inXMLFile);
javax.xml.transform.Source xslSource =
new javax.xml.transform.stream.StreamSource(inXSLFile);
// Generate the transformer.
javax.xml.transform.Transformer transformer =
tFactory.newTransformer(xslSource);
// Perform the transformation, sending the output to the response.
transformer.transform(xmlSource,
new javax.xml.transform.stream.StreamResult(outXMLFile));
}
In the code above, there are three files:
- input.xml: XML input file. We are using the CD catalog as input for our tests.
- transformation.xsl: XSL sheet. The cornerstone of this test.
- output.xml: The resulting XML from the XSL processing will be stored here. The output may no be an XML file (csv,txt,…)
At this point, we have a Java class that can process an XML input file, using a XSL sheet. Lets move to the interesting part:
- Generating (X)HTML from XML input
- Generate the same (X)HTML as above, but ordering by artist:
- Process a SOAP response and build an HTML file
- Process a SOAP response, but extracting only the interesting value
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <h2>My CD Collection</h2> <table border="1"> <tr bgcolor="#9acd32"> <th align="left">Title</th> <th align="left">Artist</th> </tr> <xsl:for-each select="catalog/cd"> <tr> <td><xsl:value-of select="title"/></td> <td><xsl:value-of select="artist"/></td> </tr> </xsl:for-each></table> </body> </html> </xsl:template> </xsl:stylesheet>
Note the use of the namespace “xsl”. Processing the input file with this XSL sheet would yield the followin output:
<html> <body> <h2>My CD Collection</h2> <table border="1"> <tr bgcolor="#9acd32"> <th align="left">Title</th> <th align="left">Artist</th> </tr> <tr> <td>Empire Burlesque</td> <td>Bob Dylan</td> </tr> <tr> <td>Hide your heart</td> <td>Bonnie Tyler</td> </tr> .... </html>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <table border="2" bgcolor="yellow"> <tr> <th>Title</th> <th>Artist</th> </tr> <xsl:for-each select="catalog/cd"> <xsl:sort select="artist"/> <tr> <td><xsl:value-of select="title"/></td> <td><xsl:value-of select="artist"/></td> </tr> </xsl:for-each></table> </body> </html> </xsl:template> </xsl:stylesheet>
The output will be:
<html> <body> <table bgcolor="yellow" border="2"> <tr> <th>Title</th> <th>Artist</th> </tr> <tr> <td>Romanza</td> <td>Andrea Bocelli</td> </tr> <tr> <td>One night only</td> <td>Bee Gees</td> </tr> ... </html>
<?xml version="1.0"?> <soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope" soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding"> <soap:Body xmlns:m="http://www.example.org/stock"> <m:GetStockPriceResponse> <m:Price>34.5</m:Price> </m:GetStockPriceResponse> </soap:Body> </soap:Envelope>
XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:m="http://www.example.org/stock"> <xsl:template match="/"> <html> <body> <table border="2" bgcolor="yellow"> <tr> <th>Price</th> </tr> <xsl:for-each select="//m:GetStockPriceResponse"> <tr> <td><xsl:value-of select="m:Price"/></td> </tr> </xsl:for-each></table> </body> </html> </xsl:template> </xsl:stylesheet>
Output:
<html xmlns:m="http://www.example.org/stock"> <body> <table bgcolor="yellow" border="2"> <tr> <th>Price</th> </tr> <tr> <td>34.5</td> </tr> </table> </body> </html>
With the same input as above, this XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:m="http://www.example.org/stock"> <xsl:output omit-xml-declaration="yes"/> <xsl:template match="/"> <xsl:for-each select="//m:GetStockPriceResponse"> <xsl:value-of select="m:Price"/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Would output:
34.5
Note the declaration in the XSL of the “m” namespace used in the input and the “omit-
- xml-declaration” to avoid that the resulting output starts with “<¿xml …” 5.-Get a CSV from the CDcatalog XSL:
- Get a lot of insert statements to import the XML directly into a database
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes"/> <xsl:template match="/"> <xsl:for-each select="catalog/cd"> <xsl:value-of select="title"/>|<xsl:value-of select="artist"/>|<xsl:value-of select="country"/>|<xsl:value-of select="price"/><xsl:text>
</xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
Outputs:
Empire Burlesque|Bob Dylan|USA|10.90
Hide your heart|Bonnie Tyler|UK|9.90
Greatest Hits|Dolly Parton|USA|9.90
Still got the blues|Gary Moore|UK|10.20
Eros|Eros Ramazzotti|EU|9.90
One night only|Bee Gees|UK|10.90
………
XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:for-each select="catalog/cd">insert into mycds (title,artist,country,price) values ("<xsl:value-of select="title"/>","<xsl:value-of select="artist"/>","<xsl:value-of select="country"/>",<xsl:value-of select="price"/>);
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Output:
insert into mycds (title,artist,country,price) values ("Empire Burlesque","Bob Dylan","USA",10.90);
insert into mycds (title,artist,country,price) values ("Hide your heart","Bonnie Tyler","UK",9.90);
insert into mycds (title,artist,country,price) values ("Greatest Hits","Dolly Parton","USA",9.90);
insert into mycds (title,artist,country,price) values ("Still got the blues","Gary Moore","UK",10.20);
insert into mycds (title,artist,country,price) values ("Eros","Eros Ramazzotti","EU",9.90);
insert into mycds (title,artist,country,price) values ("One night only","Bee Gees","UK",10.90);
....
These are very basic examples mostly taken from w3schools but I found them useful for processing HL7/XML messages, and saved me lots of hours coding
