• No results found

distributed to different servers The net result is that FastCGI eliminates the most vexing problems of CGI while making it

4.2 The Universal Design

4.2.3 XSLT Implementation

All of the approaches presented up to this point are, of course, building up to the XSLT approach. In many respects, the XSLT approach is simultaneously the most powerful and the easiest to understand. For a single web page, the XSLT approach is probably harder than a servlet or JSP to configure. Configuration of the XML parser and XSLT processor can be quite difficult, mostly due to CLASSPATH issues.[2] But as the complexity of a web application increases, the benefits

of using XSLT become obvious. Figuring out how to tackle these complex web applications is the real goal of this chapter.

[2]

This can be a frustrating experience when the servlet container comes with an older XML parser that uses DOM or SAX Version 1. Most XSLT processors require Version 2 parsers.

The XSLT approach maps fairly directly to the MVC pattern. The XML represents the model, the servlet represents the controller, and the XSLT produces HTML, which represents the view. The XSLT stylesheets may contain a minimal amount of logic, potentially blurring the line between view and controller. Figure 4-6 represents a conceptual view of how the XSLT approach maps to MVC.

Figure 4-6. XSLT conceptual model

One weakness common to every approach other than XSLT is the HTML-centric viewpoint. In every example presented thus far, it was assumed that we generated HTML. What happens when the requirement to support cellular phones arises? It is very likely that these devices will not use HTML. Instead, they will use WML, XHTML Basic, or some other technology that has not been invented yet. For now, consider that you would have to write brand new servlets or JSPs to support these devices when using traditional approaches. Any programming logic embedded into JSP pages would be duplicated or would have to be factored out into common helper classes. In a pure servlet approach, the hardcoded HTML generation logic would have to be completely rewritten.

XSLT offers an elegant solution -- simply create a second stylesheet. Instead of transforming XML into HTML, this new stylesheet transforms XML into WML. You can even support different web browsers with the XSLT approach. Again, just write different stylesheets for browser-specific functions. Since XSLT stylesheets can import and include functionality from other stylesheets, much of the code can be shared and reused across a project.

Regardless of what your XSLT will produce, start by producing the XML. For the schedule web application, the XML is dynamic and must be programmatically generated. JDOM code is shown in Example 4-4, which produces the XML necessary to create the schedule web page.

Example 4-4. ScheduleJDOM.java

import java.text.SimpleDateFormat; import org.jdom.*;

import org.jdom.output.*; /**

* Produces a JDOM Document for a tv schedule. */

public class ScheduleJDOM {

private SimpleDateFormat dateFmt = new SimpleDateFormat("hh:mm a"); /**

* Simple main( ) method for printing the XML document to System.out,

* useful for testing. */

public static void main(String[] args) throws Exception { Document doc = new ScheduleJDOM().getTodaysShows( );

new XMLOutputter(" ", true, "UTF -8").output(doc, System.out); }

/**

* @return a new JDOM Document for all TV show s scheduled for today. */

public Document getTodaysShows( ) {

Schedule sched = Schedule.getInstance( ); Show[] shows = sched.getTodaysShows( ); Element rootElem = new Element("schedule"); for (int i=0; i<shows.length; i++) {

rootElem.addContent(createShowElement(shows[i])); }

return new Document(rootElem); }

/**

* A helper method to convert a Show object into a JDOM Element. */

public Element createShowElement(S how show) { Element e = new Element("show");

e.addContent(new Element("channel").setText( Integer.toString(show.getChannel( )))); e.addContent(new Element("from").setText( this.dateFmt.format(show.ge tStartTime( )))); e.addContent(new Element("to").setText( this.dateFmt.format(show.getEndTime( )))); e.addContent(new Element("title").setText(show.getTitle( ))); return e; } }

You might be wondering why this JDOM code is that much better than the servlet code, which also used Java to programmatically produce output. The difference is fundamental and important. With this JDOM example, println( ) statements are not used. Instead, a data structure representing the television schedule is created. By virtue of the JDOM API, the data structure is

guaranteed to produce well-formed XML. We could very easily add a DTD, writing a unit test that validates the integrity of the generated data structure.

In addition to ensuring the integrity of the data, the JDOM code will typically be much smaller than the servlet or JSP code. In this basic web page, the servlet and JSP were quite small because the HTML did not contain any significant formatting or layout. In a real-world web page, however, the servlet and JSP will continue to grow in complexity as the HTML layout gets more

sophisticated, while the JDOM code remains exactly the same.

Although the XSLT stylesheet will get larger as the HTML gets more complex, this is arguably less of a problem because the presentation logic is completely separated from the underlying XML data. Once fully tested, the XSLT can be deployed to the web server without recompiling the Java code or restarting the servlet. The XML data produced by JDOM is shown in Example 4-5. Example 4-5. XML for schedule web page

<?xml version="1.0" encoding="UTF -8"?>

<?xml-stylesheet type="text/xsl" href="schedule.xslt"?> <schedule> <show> <channel>2</channel> <from>06:00 AM</from> <to>06:30 AM</to> <title>Baseball</title> </show> <show> <channel>3</channel> <from>06:00 AM</from> <to>08:00 AM</to> <title>Stand up Comedy</title> </show> ...remaining XML omitted </schedule>

The stylesheet that produces the exact same output as the JSP and servlet is listed in Example 4-6. Example 4-6. schedule.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"/>

<!-- ========== Produce the HTML Document ========== --> <xsl:template match="/">

<html>

<head><title>Today's Shows</title></head> <body>

<h1>Today's Shows</h1>

<table cellpadding="3" border="1" cellspacing="0"> <tr> <th>Channel</th> <th>From</th> <th>To</th> <th>Title</th> </tr>

<!-- ===== select the shows ===== --> <xsl:apply-templates select="schedule/show"/> </table> </body> </html> </xsl:template>

<!-- ======== Display each show as a row in the tabl e ======== --> <xsl:template match="show"> <tr> <td><xsl:value-of select="channel"/></td> <td><xsl:value-of select="from"/></td> <td><xsl:value-of select="to"/></td> <td><xsl:value-of select="title"/></td> </tr> </xsl:template> </xsl:stylesheet>

The remaining piece of the puzzle is to write a servlet that combines all of these pieces and delivers the result of the XSLT transformation to the client (see Chapter 6). In a nutshell, the servlet acts as a controller between the various components, doing very little of the actual work. The client request is intercepted by the servlet, which tells ScheduleJDOM to produce the XML data. This XML is then fed into an XSLT processor such as Xalan, along with schedule.xslt. Finally, the output is sent to the browser as HTML, XHTML, WML, or some other format.

Another interesting option made possible by this architecture