Chapter 10. Using XSLJSP in Web Site Design

CONTENTS

Chapter 10. Using XSL/JSP in Web Site Design

IN THIS CHAPTER

  •  Handling XML Files Directly
  •  Building an XML Servlet Handler
  •  Summary

Up to this point, this book has been geared towards building your skill set and familiarizing you with using XML. The first two parts of the book covered the most important APIs required to craft and manage XML documents. Using APIs such as SAX, dom4j, and JDOM, you've learned to access and use XML within JSP. We've also discussed how to incorporate XML into the logic being accessed by a JSP page. However, over the next few chapters, we will switch focus slightly and examine JSP and XML usage from a site perspective rather than a JSP perspective.

JSP holds together many components. In this context, a good JSP page is one that minimizes the Java code in the JSP. This concept can be taken a step further. In a JSP application, not every page needs to be based on JSP. Many successful JSP applications merge several server-side technologies. This chapter will examine what is possible by going back to the roots of JSP that is, by using servlets. The goal of the chapter will be to examine generic XML handling. This means that the initial processing of an XML document can happen at the application level rather than at the page level. This chapter will show how to capture and route the processing of an XML page directly to a servlet.

Handling XML Files Directly

We have built quite a few XML files in earlier chapters. However, one issue not touched on so far is how to properly handle direct access to an XML file.

The question to ponder is this: How should the XML files within a Web application be handled when the user directly requests them?

The first problem encountered is the browser. Figure 10.1 takes a quick look at the House.xml file created in Chapter 5, "Using DOM."

Figure 10.1. Using Opera, Netscape, and Explorer to view XML.

graphics/10fig01.gif

The first thing to notice is that each browser will view the raw XML differently. The second fact to consider is that the browsers view the raw XML in a format not easily used by most people. We could improve the display of the XML by using an XSL stylesheet. However, while this might solve the raw XML formatting problem, it won't always solve the presentation problem. Each browser implements a different XML processor, which means that browsers' XSLT processing capabilities vary widely.

The second issue to consider is security. Simply exposing every XML file on a site doesn't make sense. An XML file may contain information that only a particular user should see, or perhaps only portions of the XML file should be accessible. Generally, it doesn't make sense for user to see an XML file directly.

A simple solution to these problems is to create a servlet mapping. This enables a JSP application to intercept all file requests and perform special processing for any file. Using a servlet mapping will solve both the security and presentation problems with direct XML file access. It will permit us to block all unwanted access to an XML file. It also lets the Web site process any XML file to an acceptable format on the server before the file is sent to the user.

How Servlet Mappings Work

A servlet mapping is controlled within the web.xml file. Within this file, we must do two things: define the servlet and define the mapping.

The first step is to define the servlet itself for the container. This step only requires an entry defining a handle to the servlet and the location of the servlet class itself. The declaration would look like this:

<servlet>     <servlet-name>      ProcessXML     </servlet-name>     <servlet-class>ProcessXML</servlet-class> </servlet>

Refer to Table 10.1 for the subelements that can be used to fully define a servlet.

Table 10.1. Servlet Definition
Element Description
servlet-name This element functions as the servlet's handle. Any references to the servlet within the web.xml file will be through this name.
display-name This is a short name intended for display by GUI tools.
description This element is a short description of the servlet.
servlet-class or jsp-file This is the actual class file, which drives the servlet. This entry can be either servlet-class or jsp-file. The servlet-class element contains the fully qualified class name of the servlet. The element jsp-file is the full path to a JSP file.
init-param init-param contains an initialization parameter to the servlet. This element uses subelements of param-name, param-value and description to define the overall parameter.
load-on-startup If this element exists, it means the servlet should be loaded when the container starts. No value or a negative value means the container is free to determine the timing of servlet loading during the startup of the container. A positive integer will indicate the order of loading. Lower numbers are loaded before higher numbers.
run-as

A container needs a way to handle users that are not authenticated through the container. This element permits the assignment of a security identity to such users. This identity can then be passed to an EJB as the role defined within this element. This element isn't used very often.

This element uses subelements of description and role-name to further define the overall parameter.

security-role-ref

This element ties a servlet to a security role defined within a <security-role> element. This permits the container to apply basic access security to the servlet.

This element uses subelements of description, role-name, and role-link to further define the overall parameter.

The second step in creating a servlet mapping is to define an actual mapping. A servlet mapping can look like this:

<servlet-mapping>     <servlet-name>ProcessXML</servlet-name>     <url-pattern>*.xml</url-pattern> </servlet-mapping>

The servlet-mapping element only uses the servlet-name element to match the mapping to a servlet. The url-pattern element defines the actual mapping request, which will invoke the given servlet.

The rules defining a mapping are as follows:

  • The container will first select against an exact match of the full path- and filename.

  • The container will try to match a request to the longest path mapping that matches the file request.

  • The container will attempt to match a file to a mapping with the correct general file prefix.

The rules for building a string contained within the url-pattern element are as follows:

  • When defining the pattern, the path is case sensitive.

  • A pattern that begins with / and ends with /* is used to map paths (for example, /chapter10/*).

  • A pattern that begins with *. is used to map a file extension to a servlet (for example, *.shtml).

  • A pattern that only has / indicates the servlet to be executed when no file is requested by the user.

  • All other patterns must be an exact file match (for example, /chapter10/NoXSL.xml).

These rules cannot be mixed and matched. So, for instance, *.xml matches all .xml files, and /chapter10/* matches all files in the chapter10 directory. However, /chapter10/*.xml won't work at all in Tomcat. Different JSP containers might allow a bit more flexibility in the interpretation of the specifications. However, you should generally avoid experimenting if you plan to deploy on multiple JSP container implementations.

File matching is a powerful tool, as it will permit a site to handle XML files in many different fashions. For example, it is possible to build custom servlets to handle different directories. A reporting directory could have one servlet to process files and another servlet for generic XML handling.

Building an XML Servlet Handler

In this chapter, we will build a generic servlet to intercept all XML requests within the xmlbook Web application.

The servlet will use the following business rules:

  • It returns a file-not-found error when the requested XML file doesn't exist.

  • The XML file is parsed to determine whether it declares a stylesheet. If a stylesheet has been declared, it's to be applied against the XML file. The results are sent back to the user instead of the original XML file.

  • To speed access, the results of the parsing of the XML file will be cached to memory space. The cache will have one of three values: a filename when the stylesheet is found, false when no stylesheet has been found, or null if the parsing hasn't been performed. Memory caching will only be performed once during the application life cycle.

  • If a stylesheet is not found, the servlet will search for a JSP page that matches the same name as the XML file. If such a JSP page exists, it will be launched to process the XML file.

  • If neither stylesheet nor matching JSP is found, the system will return a file-not-found error. This step is to protect raw XML files from direct access.

It would be easy to modify this example to use other rules. For example, a more robust memory caching mechanism should be in place for a production system.

Constructing the actual example takes several steps:

  1. Build a SAX reader.

  2. Create a servlet to process the XML file.

  3. Register the servlet.

  4. Build the error page.

  5. Create the various test XML files to show everything working.

Building a SAX Reader

One of the most exciting aspects of this example is building a customized SAX handler. The example will show how to use SAX to read only a partial file. In addition, the example will demonstrate how to customize a DefaultHandler to work directly with another XML API, in this example dom4j.

This example has one major problem to deal with: ascertaining whether a stylesheet declaration is embedded within an XML file. There are two ways to determine whether a stylesheet has been declared within the XML file.

The first option is to create a JDOM or dom4j object representation. Once the XML document is in memory, it is simple to use the appropriate stylesheet and perform an XSLT transformation. This solution is only good if the majority of XML files have a stylesheet defined and the XML files are generally small. For our example, this solution would be a poor option, because it cannot be assumed that these conditions will always be true for you. As a result, the example will use a more flexible two-pass approach to the problem.

The second option is to perform a two-pass process. The first pass will perform a quick scan of the XML file. This scan will only verify and gather information if a stylesheet processing instruction (PI) exists. If a stylesheet PI does exist, the process will save the data and stop reading the XML file. Because the stylesheet is typically one of the first processing commands embedded within an XML file, usually only a small portion of the XML file needs to be examined. If no PI is found, the SAX process is geared to be as efficient as possible in reading the file and processing the XML file quickly. No extra steps are wasted creating a full-blown XML representation. If a stylesheet is found, a full-blown XSLT transformation will be performed on the XML file.

While this is a two-pass system, in practice it would be extremely rare to have the system perform two complete passes. Why? If no stylesheet PI exists, only the fast and efficient SAX pass happens. If a stylesheet does exist, the stylesheet PI is usually in the first few lines, resulting in only a few extra lines being parsed rather than the whole XML file.

The interesting part of this is the ability to stop the SAX process in the middle of reading an XML file. However, the method to stop SAX is not immediately apparent. Currently, the only way to stop a SAX process is to throw a SAXException. While this may seem strange, it turns out to be efficient. Since the code will be throwing an exception, it makes sense to create a customized SAXException to make the overall logic simple.

The extended SAXException class, shown in Listing 10.1, should be saved as webapps/xmlbook/WEB-INF/classes/xmlbook/chapter10/StopSaxParsing.java.

Listing 10.1 A Customized SAXException for Stopping SAX Processing
package xmlbook.chapter10; import org.xml.sax.SAXException; public class StopSaxParsing extends SAXException {     public StopSaxParsing(String text, boolean finished)     {  super(text);         dataretrieved = finished;} ;     private boolean dataretrieved = false; }

The StopSaxParsing.java class is simple and only adds one attribute. This attribute indicates whether an XSL stylesheet was found or not. The real advantage of the StopSaxParsing.java class is the actual class definition itself. When the SAX process throws a StopSaxParsing exception, the code knows that a stylesheet was found. So all the code needs to do is check for a StopSaxParsing exception to determine whether a stylesheet was obtained by SAX.

The next step is to build a SAX reader. The SAX reader, shown in Listing 10.2, will extend the SAX2 class DefaultHandler. The code should be saved as webapps/xmlbook/WEB-INF/classes/xmlbook/chapter10/DetermineStyleSheet.java.

Listing 10.2 A Customized SAX Handler for Quick Scanning of XML Files
package xmlbook.chapter10; import org.dom4j.Document; import org.dom4j.DocumentFactory; import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.SAXParseException; public class DetermineStyleSheet extends DefaultHandler {     private Document doc = DocumentFactory.getInstance().createDocument();     public  Document getDocument() {return doc; }     public DetermineStyleSheet(){}     public void processingInstruction(String target, String data)     throws SAXException     {  doc.addProcessingInstruction(target, data);         if(target.equals("xml-stylesheet"))         {throw new StopSaxParsing ("Finished getting stylesheet.",true);}     } }

The code for the DetermineStyleSheet class is minimal. It should be, since the example only needs to determine the existence of a stylesheet processing instruction.

We covered how to stop processing, but how does the SAX handler return data? A SAX reader doesn't pass variables directly back to the process calling it. However, the reader can store data within itself that can be accessed by the calling process. In this case, the code will create a dom4j Document to store processing instructions. The reason for using the Document object is that it's already built to read and parse the XML data into its structure. This means that when the code finds a PI, it only needs to invoke the addProcessingInstruction method to add the PI to the Document.

Now the code will process all processing instructions. However, when an xml-stylesheet instruction has been found, the StopSaxParsing exception is thrown to stop the reading process.

As a side note, this process can be made more efficient so that it only reads in the data up to the point of the root element. We can do this because the stylesheet PI appears before the root element. If no stylesheet is found before the root element, it is easy to exit from the parsing.

Creating a Servlet to Process XML Files

The central part of this example is the actual servlet. The code shown in Listing 10.3 should be saved as webapps/xmlbook/WEB-INF/classes/ProcessXML.java.

Listing 10.3 A Customized Servlet for Generically Processing XML Files
import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.stream.*; import org.dom4j.Document; import org.dom4j.ProcessingInstruction; import org.xml.sax.helpers.*; import org.xml.sax.*; import xmlbook.chapter10.*; public class ProcessXML extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)      throws IOException, ServletException {   // Step 1) Get a handle to system objects   ServletContext application = this.getServletConfig().getServletContext();   PrintWriter            out = response.getWriter();   // Step 2) Determine file names and paths   String spath    = request.getServletPath();   String file     = spath.substring(spath.lastIndexOf("/") + 1,spath.length());   String xmlpath  = application.getRealPath(spath);   String path     = xmlpath.substring(0,xmlpath.indexOf(file));   // See if we have the data stashed already in app space.   String xslpath  = (String)application.getAttribute(xmlpath);   String errorpage= "/chapter10/XMLError.jsp";    /* The data stored in xslpath is null, equals "false" or equals a file      name. If it equals a file name, then assign it to xslpath. If null, then      the check never has happened yet. So check to see if a XSL file exists*/     if (xslpath == null)     { try        {String saxparser = "org.apache.xerces.parsers.SAXParser";         XMLReader reader = XMLReaderFactory.createXMLReader(saxparser);         reader.setFeature("http://xml.org/sax/features/validation", false);         //create instance of special handler class for this process         DetermineStyleSheet dss = new DetermineStyleSheet();         //register handler class         reader.setContentHandler(dss);         //set application variable to false as default value.         application.setAttribute(xmlpath,"false");         //parse the XML document         try {reader.parse(xmlpath);}         catch(StopSaxParsing ssp)         {/*The XSL stylesheet is only found when we throw StopSaxParsing.            When this is the case, get the filename and stash it to memory */         Document doc = dss.getDocument();         ProcessingInstruction pi = doc.processingInstruction("xml-stylesheet");         xslpath = path + pi.getValue("href");         application.setAttribute(xmlpath,xslpath);         }         }         catch(Exception e)         {application.log("Error Determining XSL file" + xmlpath,e); }     }   //Step 3) Determine which files exist   File xmlfile = new File(xmlpath);   File xslfile = null;   if (xslpath != null && xslpath.equals("false") == false)   {xslfile = new File(xslpath);}   if (xmlfile.exists() == false)   {// Requested XML file doesn't exist, so let user know.     request.setAttribute("XMLPage",file);     application.getRequestDispatcher(errorpage).forward(request, response);     return;   }   if (xslfile == null || xslfile.exists() == false)   {String jsppage  = spath.substring(0,spath.lastIndexOf(".xml")) + ".jsp";     File jspfile    = new File(application.getRealPath(jsppage));       if (jspfile.exists() == true)       {application.getRequestDispatcher(jsppage).forward(request, response);        return;       }       else       {request.setAttribute("XMLPage",file);        application.getRequestDispatcher(errorpage).forward(request, response);        return;       }   }   else   {  // Apply stylesheet if one exists       response.setContentType("text/html");       try       {   StreamSource xml    = new StreamSource(xmlfile);            StreamSource xsl    = new StreamSource(xslfile);            StreamResult result = new StreamResult(out);            TransformerFactory tFactory = TransformerFactory.newInstance();            Transformer transformer     = tFactory.newTransformer(xsl);            transformer.transform(xml, result);       }       catch(Exception e)       {  application.log("Error Transforming XML file:" + xmlpath,e);           out.print(" XML resource is unavailible ");       }       out.close();   } } }

It's time to step through the servlet in Listing 10.3. The first thing to note is that the code is dealing with a servlet. Even if you are new to servlets, this example should be relatively easy to follow. However, if you have questions regarding servlets, please visit the Sun servlet tutorial at http://java.sun.com/docs/books/tutorial/servlets/.

The servlet class built here will extend the HttpServlet class. The HttpServlet class is geared towards building a servlet based on HTTP requests. The code for this example will be placed within the doGet method. This method is invoked upon receiving a get request for the XML file.

A servlet doesn't have direct access to an application implicit object. However, the servlet does have access to a configuration object. The configuration object makes it possible to get a handle to the application implicit object:

ServletContext application = this.getServletConfig().getServletContext();

The second part to consider is

String xslpath  = (String)application.getAttribute(xmlpath);

One of the business rules for this servlet states that it is to store information regarding the existence of a stylesheet for an XML file. This caching of information is important in that it reduces the need for parsing every XML file each time it's requested. Re-parsing a large XML file every time would be slow and an inefficient use of resources. This servlet will store the results found after parsing an XML file under an application attribute. This attribute's name will match the full pathname of the XML file, as shown here:

application.setAttribute(xmlpath,xslpath);

The caching here is simple and only happens once per file request. Once the results are cached, this servlet will not check again. A slightly more robust caching mechanism should be built for systems where the stylesheet declaration within the XML files changes frequently, something that usually isn't the case.

The next item to consider is the SAX reader. The steps here are similar to the previous SAX examples up to the point of the handler class:

DetermineStyleSheet dss = new DetermineStyleSheet(); reader.setContentHandler(dss);

This example creates and sets the DetermineStyleSheet class as the ContentHandler to use for the SAX reader. Next, the code uses SAX to parse the file. Because the DetermineStyleSheet class will throw an exception when it's done, the code needs to be placed in a try-catch block:

try {reader.parse(xmlpath);} catch(StopSaxParsing ssp)

We know upon catching the StopSaxParsing exception that the stylesheet has been found. This is the only way this exception can be thrown. Therefore, once this exception is thrown, the code queries the ContentHandler to get the Document object created within the DetermineStyleSheet class:

Document doc = dss.getDocument();

Once this Document object is in hand, it's an easy step to query and get the stylesheet within the Document:

ProcessingInstruction pi = doc.processingInstruction("xml-stylesheet"); xslpath = path + pi.getValue("href");

Overall, this method of using SAX is very powerful and it's possible to modify or add more to this basic example depending on what the project needs to accomplish.

Once the data is in hand, the code stores the results to the application attribute:

application.setAttribute(xmlpath,xslpath);

This code is also using the RequestDispatcher object. This object is used within a servlet to access another resource, such as the page shown in Listing 10.5:

application.getRequestDispatcher(errorpage).forward(request, response);

In order to use a RequestDispatcher, the code used a String containing the URL of the resource to be accessed within the code. Once this is obtained, it's possible to forward the request and response to the destination page.

The rest of the logic within this page is similar to logic we've used in earlier chapters. For example, the servlet uses JAXP, as shown in Chapter 4, "A Quick Start to JSP and XML Together," to perform the XSLT transformation of the XML file. Also, if something goes wrong, the code logs the error to the log file in a way similar to that of the logic shown in previous chapters. It is easy to reuse code from process to process when handling XML files.

Register the Servlet

Once the servlet is finished, it's a quick task to modify the web.xml file stored in webapps/xmlbook/WEB-INF/web.xml, as shown in Listing 10.4. (Add the following code after any listener declarations.)

Listing 10.4 Updating web.xml
<servlet>     <servlet-name>      ProcessXML     </servlet-name>     <servlet-class>ProcessXML</servlet-class> </servlet> <servlet-mapping>     <servlet-name>ProcessXML</servlet-name>     <url-pattern>*.xml</url-pattern> </servlet-mapping>

For now, the example will intercept all XML file requests.

Building the Error Page

The servlet in Listing 10.3 refers to an error page. The error page is just a collector spot in case something goes wrong. The actual JSP page, shown in Listing 10.5, should be saved as webapps/xmlbook/chapter10/XMLError.jsp.

Listing 10.5 JSP Error Display
<%@page contentType="text/html" %> <% String xmlpage = (String) request.getAttribute("XMLPage");    if (xmlpage == null) xmlpage = ""; %> <html> <head><title>No XML File Page</title></head> <body>     A simple error page to alert the user. <br/><br/>     The XML File: <%= xmlpage %> cannot be accessed.<br/> </body> </html>

The page currently only takes the data stored in the request attribute called XMLPage. In practice, this page could do a little more depending on your project needs.

Creating Some Test Files

Now everything is ready. Let's create a few test XML files for the ProcessXML servlet. The first test file is a copy of buzz_10_09_2001.xml from Chapter 7, "Successfully Using JSP and XML in an Application," with one slight modification the addition of the xml-stylesheet processing instruction (see the line in boldface type in Listing 10.6). The new file should be saved as webapps/xmlbook/chapter10/buzz_10_09_2001.xml.

Listing 10.6 buzz_10_09_2001.xml
<?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="Buzz.xsl"?> <jspbuzz volumn="II" issue="19">

The new XML file references the Buzz.xsl file, which is created in Listing 10.7. This stylesheet is based on the production JSPBuzz stylesheet. The file should be saved as webapps/xmlbook/chapter10/Buzz.xsl.

Listing 10.7 Buzz.xsl
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xsl:stylesheet [<!ENTITY nbsp "&#xA0;">]> <xsl:stylesheet version="1.0"                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                 xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="html"/> <xsl:template match="/"> <html>       <head><title>JSP Insider - XML to HTML - Test Page</title>       <style>       .10ptBold {font-size:10pt; font-weight:bold; font-family:arial;}       .12ptBold {font-size:12pt; font-weight:bold; font-family:arial;}        td {font-family: verdana, Arial; font-size: 10pt; border-style: groove;            border-width:2px; border-color:#ffffff; padding:2px;}       .Clear {background: #ffffff; border-width:0px; padding-left:0px;                                                      padding-right:0px;}       .LightGreyBox {background: #eeeeee;}       .LightGrey {background: #eeeeee; border-width:0px;}       .OffWhite {background: #f5f5f5; border-width:0px;}       .OffWhiteBox {background: #f5f5f5;}       .GreenBox {background: #aabbbb;}       </style></head>       <body>         <table cellspacing="0" width="100%">             <tr><td class="OffWhite">                 <p class="12ptBold" align="center">                 JSP Buzz: Issue #<xsl:value-of select="jspbuzz/@issue"/>                 </p>                 <p align="center" class="12ptBold">                         <xsl:value-of select="jspbuzz/title"/>                 </p>                 <p align="center"><xsl:value-of select="jspbuzz/buzzdate"/>                 </p>             </td></tr>             <tr><td class="GreenBox">                 <div class="12ptBold">Table of Contents</div>             </td></tr>             <tr><td class="OffWhiteBox">                 <div class="10ptBold"><a href="#links">Links of Interest</a>                 </div>                 <ol>                 <xsl:apply-templates select="jspbuzz/buzzlink[@type='link']"                                      mode="contents">                         <xsl:sort data-type="number" select="@position"/>                 </xsl:apply-templates>                 </ol>             </td></tr>             <tr><td class="GreenBox">                 <div class="12ptBold"><a name="links"/>Links</div>             </td></tr>             <tr><td class="WhiteBox">                 <table border="0" width="90%">                 <xsl:apply-templates select="jspbuzz/buzzlink[@type='link']">                         <xsl:sort data-type="number" select="@position"/>                 </xsl:apply-templates>                 </table>             </td></tr>         </table>         </body> </html> </xsl:template> <xsl:template match="jspbuzz/buzzlink" mode="contents">      <li><a href="#{@type} {@position}"><xsl:value-of select="title"/></a></li> </xsl:template> <xsl:template match="jspbuzz/buzzlink">         <tr><td class="LightGreyBox"  width="100%">         <a href="{link} "          name="{@type} {@position} " target="_window" style="font-weight:bold;">                 <xsl:value-of select="title"/>         </a>         </td></tr>         <xsl:if test="string-length(author)>0 or string-length(date)>0">         <tr><td  class="LightGreyBox">                 <table><tr>                 <td class="LightGrey" nowrap="nowrap" width="400px">                         <xsl:value-of select="author"/>&nbsp;</td>                 <td class="LightGrey">                         <xsl:value-of select="date"/>&#xA0;</td>                 </tr></table>         </td></tr>         </xsl:if>         <xsl:apply-templates select="body" /> </xsl:template> <xsl:template match="body" >       <tr><td class="Clear" valign="top" ><xsl:value-of select="."/></td></tr> </xsl:template> </xsl:stylesheet>

The stylesheet is unremarkable. However, one thing to note is the use of CSS style commands. Using CSS is recommended as a method to keep the XSLT code cleaner and make maintenance easier. Using CSS has many advantages, with one of the main strengths being the increased formatting capabilities it brings to HTML and XML. However, the real reason to use CSS within XSL is that CSS gives you the ability to create predefined formats. This in turn makes it simple to change and update styles within the page. CSS will also make the XSLT easier to maintain when using a readable naming convention. CSS styles aren't written as XML. This makes it easy to create class and style attributes within an XML/XSL file without interfering with the XML. Since HTML uses tag elements, using HTML within an XML data file can at times interfere with the XML file. However, it's simple to store CSS style attributes within the same XML file without markup conflicts.

You should also note the use of the mode attribute in Listing 10.7. At times, you will want to create multiple templates using the same XPath selection statement. This is done using the mode attribute:

<xsl:template match="jspbuzz/buzzlink" mode="contents">    <li><a href="#{@type} {@position}"><xsl:value-of select="title"/></a></li> </xsl:template> <xsl:template match="jspbuzz/buzzlink">         <tr><td class="LightGreyBox"  width="100%"> etc.

Using the mode attribute lets the XSLT define which template to call for a given selection. The apply-templates command

<xsl:apply-templates select="jspbuzz/buzzlink[@type='link']" mode="contents">

would call the following template:

<xsl:template match="jspbuzz/buzzlink" mode="contents">

Let's run Listing 10.6 to see what happens. As always, don't forget to compile everything, then stop and restart the Tomcat container. Figure 10.2 shows the result.

Figure 10.2. Results of running buzz_10_09_2001.xml.

graphics/10fig02.gif

Notice that even though this example requests the XML file, the server returns the HTML created by the XSL transformation against the XML file. Viewing the source code of this file would show the HTML from the transformation, not the XML file. This is due to the transformation occurring on the server rather than within the browser.

Now let's build another example. First, we'll create a test XML file. The example will again copy buzz_10_09_2001.xml from the chapter7 directory to the chapter10 directory of the xmlbook Web site. This time, create an exact copy of the buzz_10_09_2001.xml file from Chapter 7. The new file should be saved as webapps/xmlbook/chapter10/NoXSL.xml.

The goal of NoXSL.xml is to show how to build a JSP handler page that will be executed by the ProcessXML servlet (see Listing 10.8). Keep in mind that if ProcessXML doesn't find a stylesheet, it searches for a JSP with the same name as the XML file. Save the following file as webapps/xmlbook/chapter10/NoXSL.jsp.

Listing 10.8 A Customized JSP to Handle an XML File
<%@page contentType="text/html"         import="xmlbook.chapter7.*"%> <html><head><title>Dedicated JSP Page To Process XML File</title> <style>     td {font-family: verdana, Arial, ; font-size: 10pt; border-style: groove;          border-width:2px; border-color:#ffffff; padding:2px;} .Clear{background:#ffffff;border-width:0px;padding-left:0px;padding-right:0px;} .OffWhiteBox {background: #f5f5f5;} .GreenBox {background: #aabbbb;} </style> </head> <body> <% ProduceListing listing = new ProduceListing();    String spath  = request.getServletPath();    String file   = spath.substring(spath.lastIndexOf("/") + 1,spath.length());    String xmlpath= application.getRealPath(spath);    String path   = xmlpath.substring(0,xmlpath.indexOf(file));    listing.listContent("","NoXSL.xml", path, out); %> </body> </html>

The code here is unremarkable. In fact, the code reuses ProduceListing.java from Chapter 7 in order to reduce the amount of coding needed. The purpose of this page is simply to show how to tie the XML file to a JSP file through the servlet.

When NoXSL.xml is accessed, the results shown in Figure 10.3 appear in the browser.

Figure 10.3. Accessing NoXSL.xml.

graphics/10fig03.gif

Finally, to show that everything is working, let's view an XML page that has no stylesheet or JSP page to process it. When http://localhost:8080/xmlbook/chapter6/Books.xml runs, the results shown in Figure 10.4 should appear.

Figure 10.4. Accessing Books.xml.

graphics/10fig04.gif

The example receives the error page, as expected for an XML file not tied to a stylesheet or JSP.

Accessing XML Directly

This chapter shows how easy it is to build a servlet to intercept all XML file requests. Generally, this is a valid approach, and it will be a common practice across many JSP applications. Does this mean that you should take this approach every time? The answer is no.

While JSP sites generally offer data to users in a visual format, it isn't uncommon to provide direct data feeds to users. At these times, it's fine to access XML files directly. After all, XML is best used for data transfer.

Another point to keep in mind is that the various browsers are getting better at offering XSL support. At some point in the future, general XSL support will be solid enough that it will be an acceptable solution to use client-side processing of the XML files. In fact, browser considerations will be closely examined in Chapter 13, "Browser Considerations with XML." Before working on the examples in Chapter 13, you will need to turn off the generic XML processing this chapter performs. To do so, just remove the <servlet-mapping> entry created in Listing 10.4 and restart Tomcat.

This shows the other drawback of the system created in this chapter. Using pattern matching is great when all the files need to be processed through a single servlet controller. However, in practice, the pattern strings allowed to create the actual mappings are not as flexible as they could be. It isn't possible to create a /chapter10/*.xml pattern to only affect XML files in the chapter10 directory. Instead, some finesse is required in creating the required pattern matching. For example, one could possibly match to /chapter10/* or selectively match to individual files such as /chapter10/NoXSL.xml. This entails building a more complicated version of the example to implement a selective solution. Hopefully, future versions of Tomcat and the servlet specification will expand the pattern matching capabilities of the <servlet-mapping> entry. Ironically, a simple workaround exists. The pattern matching is case sensitive. This means that the *.xml pattern only matches lowercase .xml. Any XML file with the .XML (uppercase) extension would be ignored by this example's servlet mapping. Thus, an application could use .xml for secure XML files and .XML for XML files that the client will access directly. That's not the best solution, but it's easy to implement.

Summary

JSP is a wonderful tool that simplifies using servlets. However, at times, using specialized servlets can greatly enhance a JSP site. In the case of XML, building generic handlers for XML pages can be a great boon to a JSP application. It's possible to provide extra security by preventing unwanted access to XML pages. Using servlets can reduce the amount of work within the JSP site by creating reusable templates to process an XML file in different directories.

CONTENTS


JSP and XML[c] Integrating XML and Web Services in Your JSP Application
JSP and XML[c] Integrating XML and Web Services in Your JSP Application
ISBN: 672323540
EAN: N/A
Year: 2005
Pages: 26

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net