• No results found

from locating jaxp.properties JBuilder, for instance, installs its own version of Java 2 that it uses by default.

5.3 Input and Output

5.3.5 JAXP SAX I/O

5.3.5.4 Using the parser

To wrap things up, let's look at how you will actually use this CSV parser with an XSLT

stylesheet. The code shown in Example 5-8 is a standalone Java application that allows you to perform XSLT transformations on CSV files. As the comments indicate, it requires the name of a CSV file as its first parameter and can optionally take the name of an XSLT stylesheet as its second parameter. All output is sent to System.out.

Example 5-8. SimpleCSVProcessor.java package com.oreilly.javaxslt.util; import java.io.*; import javax.xml.transform.*; import javax.xml.transform.sax.*; import javax.xml.transform.stream.*; import org.xml.sax.*; /**

* Shows how to use the CSVXMLReader class. This is a command -line * utility that takes a CSV file and optionally an XSLT file as * command line parameters. A transformation is applied and the * output is sent to System.out.

*/

public class SimpleCSVProcessor {

public static void main(String[] args) throws Exception { if (args.length == 0) {

System.err.println("Usage: java "

+ SimpleCSVProc essor.class.getName( ) + " <csvFile> [xsltFile]");

System.err.println(" - csvFile is required"); System.err.println(" - xsltFile is optional"); System.exit(1);

}

String csvFileName = args[0];

String xsltFileName = (args.length > 1) ? args[1] : null;

TransformerFactory transFact = TransformerFactory.newInstance( );

if (transFact.getFeature(SAXTransformerFactory.FEATURE)) { SAXTransformerFactory sax TransFact =

(SAXTransformerFactory) transFact; TransformerHandler transHand = null;

if (xsltFileName == null) {

transHand = saxTransFact.newTransformerHandler( ); } else {

transHand = saxTransFact.newTransformerHandler( new StreamSource(new File(xsltFileName))); }

// set the destination for the XSLT transformation transHand.setResult(new StreamResult(System.ou t)); // hook the CSVXMLReader to the CSV file

CSVXMLReader csvReader = new CSVXMLReader( ); InputSource csvInputSrc = new InputSource( new FileReader(csvFileName));

// attach the XSLT processor to the CSVXMLReader csvReader.setContentHandler(transHand); csvReader.parse(csvInputSrc); } else { System.err.println("SAXTransformerFactory is not supported."); System.exit(1); } } }

As mentioned earlier in this chapter, the TransformerHandler is provided by JAXP and is an implementation of the org.xml.sax.ContentHandler interface. It is constructed by the

SAXTransformerFactory as follows:

TransformerHandler transHand = null; if (xsltFileName == null) {

transHand = saxTransFact.newTransformerHandler( ); } else {

transHand = saxTransFact.newTransformerHandler( new StreamSource(new File(xsltFileName))); }

When the XSLT stylesheet is not specified, the transformer performs an identity transformation. This is useful when you just want to see the raw XML output without applying a stylesheet. You

will probably want to do this first to see how your XSLT will need to be written. If a stylesheet is provided, however, it is used for the transformation.

The custom parser is then constructed as follows:

CSVXMLReader csvReader = new CSVXMLReader( );

The location of the CSV file is then converted into a SAX InputSource:

InputSource csvInputSrc = new InputSource( new FileReader(csvFileName));

And finally, the XSLT processor is attached to our custom parser. This is accomplished by

registering the TransformerHandler as the ContentHandler on csvReader. A single call to the parse method causes the parsing and transformation to occur:

// attach the XSLT processor to the CSVXMLReader csvReader.setContentHandler(transHand);

csvReader.parse(csvInputSrc);

For a simple test, assume that a list of presidents is available in CSV format:

Washington,George,, Adams,John,, Jefferson,Thomas,, Madison,James,, etc... Bush,George,Herbert,Walker Clinton,William,Jefferson, Bush,George,W,

To see what the XML looks like, invoke the program as follows:

java com.oreilly.javaxslt.util.SimpleCSVProcessor presidents.csv

This will parse the CSV file and apply the identity transformation stylesheet, sending the following output to the console:

<?xml version="1.0" encoding="UTF -8"?> <csvFile> <line> <value>Washington</value> <value>George</value> <value/> <value/> </line> <line> etc... </csvFile>

Actually, the output is crammed onto a single long line, but it is broken up here to make it more readable. Any good XML editor application should provide a feature to pretty-print the XML as shown. In order to transform this into something useful, a stylesheet is required. The XSLT stylesheet shown in Example 5-9 takes any output from this program and converts it into an HTML table. Example 5-9. csvToHTMLTable.xslt <?xml version="1.0" encoding="UTF -8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/>

<xsl:template match="/"> <table border="1"> <xsl:apply-templates select="csvFile/line"/> </table> </xsl:template> <xsl:template match="line"> <tr> <xsl:apply-templates select="value"/> </tr> </xsl:template> <xsl:template match="value"> <td>

<!-- If a value is empty, print a non -breaking space so the HTML table looks OK -->

<xsl:if test=".=''"> <xsl:text> disable-output-escaping="yes">&amp;nbsp;</xsl:text> </xsl:if> <xsl:value-of select="."/> </td> </xsl:template> </xsl:stylesheet>

In order to apply this stylesheet, type the following command:

java com.oreilly.javaxslt.util.SimpleCSVProcessor presidents.csv csvToHTMLTable.xslt

As before, the results are sent to System.out and contain code for an HTML table. This stylesheet will work with any CSV file parsed with SimpleCSVProcessor, not just

presidents.xml. Now that the concept has been proved, you can add fancy formatting and custom output to the resulting HTML without altering any Java code -- just edit the stylesheet or write a new one.