You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by dl...@locus.apache.org on 2000/08/03 17:18:13 UTC

cvs commit: xml-xalan/java/samples/servlet ApplyXSLT.java ApplyXSLTException.java ApplyXSLTListener.java ApplyXSLTProperties.java default.xsl default2.xsl DefaultApplyXSLTProperties.java media.properties readme.html

dleslie     00/08/03 08:18:13

  Added:       java/samples/servlet ApplyXSLT.java ApplyXSLTException.java
                        ApplyXSLTListener.java ApplyXSLTProperties.java
                        default.xsl default2.xsl
                        DefaultApplyXSLTProperties.java media.properties
                        readme.html
  Log:
  1. Repackaged sample servlet as "servlet": makes build process
  a lot more sensible.
  2. samples/Servlet seems to have disappeared from repository,
  so whatever has happened, have put into a new directory
  named samples/servlet (lowercase) to match package name.
  
  Revision  Changes    Path
  1.1                  xml-xalan/java/samples/servlet/ApplyXSLT.java
  
  Index: ApplyXSLT.java
  ===================================================================
  /*****************************************************************************************************
   * $Id: ApplyXSLT.java,v 1.1 2000/08/03 15:18:10 dleslie Exp $
   *
   * Copyright (c) 1998-1999 Lotus Corporation, Inc. All Rights Reserved.
   *				This software is provided without a warranty of any kind.
   *
   * $State: Exp $
   *****************************************************************************************************/
  package servlet;
  
  import java.io.*;
  import java.util.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  import java.net.URL;
  import java.net.MalformedURLException;
  import java.net.URLConnection;
  
  import org.apache.xalan.templates.Constants;
  import org.apache.xalan.templates.StylesheetRoot;
  import org.apache.xalan.templates.OutputFormatExtended;
  // SAX2 Imports
  import org.xml.sax.ContentHandler;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  import org.xml.sax.XMLReader;
  import org.xml.sax.Locator;
  import org.xml.sax.helpers.XMLReaderFactory;
  import org.xml.sax.ext.DeclHandler;
  import org.xml.sax.ext.LexicalHandler;
  import org.xml.sax.SAXNotRecognizedException;
  import org.xml.sax.SAXNotSupportedException;
  
  import org.w3c.dom.*;
  import trax.*;
  import org.apache.xalan.transformer.TransformerImpl;
  import org.apache.xalan.stree.SourceTreeHandler;
  import org.apache.xpath.objects.XObject;
  import org.apache.xpath.objects.XString;
  
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  
  import org.xml.sax.XMLReader;
  import org.xml.sax.helpers.XMLReaderFactory;
  import org.xml.sax.helpers.XMLFilterImpl;
  
  
  // Imported Serializer classes
  import org.apache.xml.serialize.OutputFormat;
  import org.apache.xml.serialize.Serializer;
  import org.apache.xml.serialize.SerializerFactory;
  
  // Imported JAVA API for XML Parsing 1.0 classes
  import javax.xml.parsers.ParserConfigurationException; 
  
  
  
  /*****************************************************************************************************
   *
   * ApplyXSLT supplies the basic
   * functions for transforming XML data using XSL stylesheets.
   *
   * @author Spencer Shepard (sshepard@us.ibm.com)
   * @author R. Adam King (rak@us.ibm.com)
   * @author Tom Rowe (trowe@us.ibm.com)
   * @author Don Leslie (donald_leslie@lotus.com)
   *
   *****************************************************************************************************/
  
  public class ApplyXSLT extends HttpServlet
  {
  
    /**
     * Operational parameters for this class.
     * <p>Request-time values override init-time values which override class defaults.</p>
     * @see #init
     * @serial
     */
    protected ApplyXSLTProperties ourDefaultParameters = null;
  
    /**
     * String representing the end of line characters for the System.
     */
    public final static String EOL = System.getProperty("line.separator");
  
    /**
     * String representing the file separator characters for the System.
     */
    public final static String FS = System.getProperty("file.separator");
  
     /**
     * String representing the current directory for properties files. See init().
     */
    public final static String ROOT = System.getProperty("server.root");
    public static String CURRENTDIR;
  
    /**
     * Initialize operational parameters from the configuration.
     * @param config Configuration
     * @exception ServletException Never thrown
     */
    public void init(ServletConfig config)
      throws ServletException
    {
      super.init(config);
      // If the server.root property --see above-- is null, use current working directory
      // as default location for media.properties.
      if (ROOT != null)
        CURRENTDIR= ROOT + FS + "servlets" + FS;
      else
        CURRENTDIR = System.getProperty("user.dir")+ FS;
      
  	setDefaultParameters(config);
  	
      setMediaProps(config.getInitParameter("mediaURL"));	
    }
    
   /**
     * Sets the default parameters for the servlet from the configuration.
     * Also sets required system properties until we figure out why servlet 
     * sometimess fails to read properties from properties files.
     * @param config Configuration
     */
    protected void setDefaultParameters(ServletConfig config)
    {
      ourDefaultParameters = new DefaultApplyXSLTProperties(config);
    }
    
      /**
     *	Loads the media properties file specified by the given string.
     * @param mediaURLstring Location of the media properties file.  Can be either a full URL or a path relative
     * to the System's server.root /servlets directory.  If this parameter is null,
     * server.root/servlets/media.properties will be used.
     * @see ApplyXSL#CURRENTDIR
     */
    protected void setMediaProps(String mediaURLstring)
    {
      if (mediaURLstring != null)
      {
        URL url = null;
        try
        {
          url = new URL(mediaURLstring);
        }
        catch (MalformedURLException mue1)
        {
          try
          {
            url = new URL("file", "", CURRENTDIR + mediaURLstring);
          }
          catch (MalformedURLException mue2)
          {
            writeLog("Unable to find the media properties file based on parameter 'mediaURL' = "
                     + mediaURLstring, HttpServletResponse.SC_ACCEPTED, mue2);
            url = null;
          }
        }
        if (url != null)
        {
          try
          {
            ourMediaProps = new OrderedProps(url.openStream());
          }
          catch (IOException ioe1)
          {
            writeLog("Exception occurred while opening media properties file: " + mediaURLstring +
                     ".  Media table may be invalid.", HttpServletResponse.SC_ACCEPTED, ioe1);
          }
        }
      }
      else
      {
        String defaultProp = CURRENTDIR + "media.properties";
        try
        {
          ourMediaProps = new OrderedProps(new FileInputStream(defaultProp));
        }
        catch (IOException ioe2)
        {
          writeLog("Default media properties file " + defaultProp + " not found.",
                   HttpServletResponse.SC_ACCEPTED, ioe2);
        }
      }
    }
  
    public String getMedia(HttpServletRequest request)
    {
      return ourMediaProps.getValue(request.getHeader(HEADER_NAME));
    }
    
    // doPost removed for security reasons due to the possibility of sending
    // unsecure XML and XSL XSLTInputSources through the request input stream
  
    /**
     * HTTP Get method passed on to process().
     * @param request The request
     * @param response The response
     * @see #process
     * @exception ServletException Never thrown
     * @exception IOException Never thrown
     */
    public void doGet (HttpServletRequest request,
                       HttpServletResponse response)
      throws ServletException, IOException
    {
      try
      {	
        Processor processor = Processor.newInstance("xslt");	  
        process(processor, request, response); 
      }
      catch (Exception e)
      {
      }
    }
    
    /**
     * Coordinates applying an XSL stylesheet to XML data using operational parameters.
     * <p>If successfully applied, the result tree will be streamed to the response object
     * and the content type set according to the XSL stylesheet's &lt;xsl:output> element(s).</p>
     * <p>If there is a problem in parsing the XML/XSL or if there is a problem in applying
     * the XSL to the XML, an exception will be streamed to the response object.  The detail
     * of the information returned in the response object will depend on whether we're
     * running in debug mode or not.</p>
     * @param processor implementation of TRaX processor
     * @param request  May contain information relevant to creating XML and XSL XSLTInputSource's
     * @param response Where to write the transformation result
     * @see #getDocument
     * @see #getStylesheet
     * @see #getContentType
     * @see #displayException
     * @see #setStylesheetParams
     * @exception ServletException Never thrown
     * @exception IOException Never thrown
     */
    
    public void process(Processor processor, 
  					  HttpServletRequest request,
                        HttpServletResponse response)
      throws ServletException, IOException, SAXException
    {
      boolean debug = ourDefaultParameters.isDebug(request);
  
      long time = 0;
      if (debug)
        time = System.currentTimeMillis();
  
      // Listener to be used for all reporting
      ApplyXSLTListener listener = new ApplyXSLTListener();
  	listener.out.println("debug is " + debug);
  
      InputSource xmlSource = null;
  	InputSource xslSource = null;
      try
      {
        if ((xmlSource = getDocument(request, listener)) == null)
          throw new ApplyXSLTException("getDocument() returned null",
                                       new NullPointerException(),
                                       response.SC_NOT_FOUND);
      }
      catch (ApplyXSLTException axe)
      {
        axe.appendMessage(EOL + "getDocument() resulted in ApplyXSLTException" + EOL
                          + listener.getMessage());
        if (debug) writeLog(axe);
        displayException(response, axe, debug);
        xmlSource = null;
      }
      // creating XSL Stylesheet
      if (xmlSource != null)
  	{
        try
        {
  	    if ((xslSource = getStylesheet(processor, request, xmlSource, listener)) == null)
  		{
            throw new ApplyXSLTException("getStylesheet() returned null",
                                         new NullPointerException(),
                                         response.SC_NOT_FOUND);
          }
          // For time being, must "reset" xmlSource after extracting stylesheet PI
  		xmlSource = getDocument(request, listener); 
        }
        catch (ApplyXSLTException axe)
        {
          axe.appendMessage(EOL + "getStylesheet() resulted in ApplyXSLTException" + EOL
                            + listener.getMessage());
          if (debug) writeLog(axe);
          displayException(response, axe, debug);
          xslSource = null;
        }
      // perform Transformation
  	  
      if ((xmlSource != null) && (xslSource != null))
      {
  	  try
  	  {
          listener.out.println("Performing transformation...");
  		
          Templates templates = processor.process(xslSource);
          Transformer transformer = templates.newTransformer();
  	  	  
  	    DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
          DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
          Document outNode = docBuilder.newDocument();
  		
          {
            try
            {
              String contentType = null;
  			contentType = getContentType(templates);
              if (contentType != null);
                response.setContentType(contentType);
  
  			if (transformer instanceof TransformerImpl)
  			{
  			  TransformerImpl transformerImpl = (TransformerImpl)transformer;
                transformerImpl.setQuietConflictWarnings(ourDefaultParameters.isNoCW(request));
  			}
  
  			setStylesheetParams(transformer, request);
  			
      	    Node doc = docBuilder.parse(xmlSource);
              transformer.transformNode(doc, new Result(outNode));
  	  
   	        ByteArrayOutputStream baos = new ByteArrayOutputStream();
              Result outBuffer = new Result(baos);
  
  
  	        SerializerFactory sf = SerializerFactory.getSerializerFactory("xml");
              Serializer serializer = sf.makeSerializer(baos, new OutputFormat());
              serializer.asDOMSerializer().serialize(outNode);
      	    baos.writeTo(response.getOutputStream());
  			if (debug)              
                writeLog(listener.getMessage(), response.SC_OK);
            }
            catch (Exception exc)
            {
              ApplyXSLTException axe = new ApplyXSLTException
  				                     ("Exception occurred during Transformation:"
                                            + EOL + listener.getMessage() + EOL
                                            + exc.getMessage(), 
  									  exc,
                                        response.SC_INTERNAL_SERVER_ERROR);
              if (debug) writeLog(axe);
              displayException(response, axe, debug);
            }
            finally
            {
  //            transformer.reset();
            } // end of try ... catch ... finally
  		}
  	  }
        catch (/*org.xml.sax.SAX*/Exception saxExc)
        {
          ApplyXSLTException axe = new ApplyXSLTException
  			                     ("Exception occurred during ctor/Transformation:"
                                               + EOL + listener.getMessage() + EOL
                                               + saxExc.getMessage(), 
  								  saxExc,
                                    response.SC_INTERNAL_SERVER_ERROR);
          if (debug) writeLog(axe);
          displayException(response, axe, debug);
        } // end of new try ... catch
      } // end of if((stylesheetRoot != null) ...
      if (debug)
      {
        time = System.currentTimeMillis() - time;
        writeLog("  No Conflict Warnings = " + ourDefaultParameters.isNoCW(request) +
                 "  Transformation time: " + time + " ms", response.SC_OK);
      }
    }
    }  
  
    /**
     * Returns an XML XSLTInputSource DOM.  Attempts will be make to create the DOM from the following
     * sources:
     * <ol>
     * <li>A relative URL specified in the HTTP request's path information. This capability is intended
     * for use by <b>servlet engines that map</b> some or all XML data to be processed at the server.</li>
     * <li>A URL specified in the HTTP request's <code>URL=</code> parameter.  This capability
     * is intended for <b>clients wishing to selectively process</b> XML data at the server.  For
     * security reasons, this URL will be forced to the local IP host.</li>
     * <li>The HTTP request's XML input stream. This capability is intended for use by chained servlets.</li>
     * </ol>
     * @param request May contain or point to the XML XSLTInputSource
     * @param listener To record detailed parsing messages for possible return to requestor
     * @return XML XSLTInputSource DOM, or null if the XSLTInputSource could not be parsed
     * @exception ApplyXSLTException Thrown if exception occurs while handling request
     */
    protected InputSource getDocument(HttpServletRequest request,
                                      ApplyXSLTListener listener)
      throws ApplyXSLTException
    {
      try
      {
        String xmlURL = null;
        // document from PathInfo
        if ((xmlURL = request.getPathInfo()) != null)
        {
          listener.out.println("Parsing XML Document from PathInfo: " + xmlURL);
          return new InputSource(new URL("http", ((DefaultApplyXSLTProperties)
                                               ourDefaultParameters).getLocalHost(),
                                               xmlURL.replace('\\', '/')).openStream());		
        }
        // document from Request parameter
        if ((xmlURL = ourDefaultParameters.getXMLurl(request)) != null)
        {
          listener.out.println("Parsing XML Document from request parameter: " + xmlURL);
          return new InputSource(new URL(xmlURL).openStream());
        }
        // document from chain
        String contentType = request.getContentType();
        if ((contentType != null) && contentType.startsWith("text/xml"))
        {
          listener.out.println("Parsing XML Document from request chain");
          return new InputSource(request.getInputStream());
        }
      }
      catch (IOException ioe)
      {
        throw new ApplyXSLTException(ioe, HttpServletResponse.SC_NOT_FOUND);
      }
      catch (Exception e)
      {
        throw new ApplyXSLTException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      }
      return null;
    }
  
    /**
     * Returns a Templates (StylesheetRoot) object.  Attempts will be make to create the Stylesheet 
     * from the followingsources:
     * <ol>
     * <li>A URL specified in the HTTP request's <code>xslURL=</code> parameter.  This capability
     * is intended for clients wishing to selectively override the server algorithm for applying XSL
     * stylesheets.  For security reasons, this URL will be forced to the local IP host.</li>
     * <li>XML association.  XML documents may contain references to one or more stylesheets using
     * <a HREF="http://www.w3.org/TR/1999/PR-xml-stylesheet-19990114">this</a> W3C proposed recommendation.
     * If the XML document does contain such references, a best match will be chosen based on the browser
     * type making the request and the default association.  This capability enables relationships to be
     * defined between client capabilities and stylesheets capable of acting on these capabilities.</li>
     * <li>A configured default stylesheet URL</li>
     * </ol>
     * @param request May contain or point to the XSL XSLTInputSource
     * @param xmlSource  May point to the XSL XSLTInputSource
     * @param listener To record detailed parsing messages for possible return to requestor
     * @return XSL XSLTInputSource, or null if the request could not be parsed
     * @see #makeDocument
     * @see #getMedia
     * @see #STYLESHEET_ATTRIBUTE
     * @see #getXSLURLfromDoc
     * @see #toAcceptLanguageConnection
     * @exception ApplyXSLTException Thrown if exception occurs while handling request
     */
    protected InputSource getStylesheet(Processor processor,
  									  HttpServletRequest request,
                                        InputSource xmlSource,
                                        ApplyXSLTListener listener)
      throws ApplyXSLTException
    {
      try
      {
        //stylesheet URL from request
        String xslURL = ((DefaultApplyXSLTProperties) ourDefaultParameters).getXSLRequestURL(request);
  
        if (xslURL != null)
          listener.out.println("Parsing XSL Stylesheet Document from request parameter: "
                               + xslURL);
        else
        {
          // find stylesheet from XML Document, Media tag preference
          if (xmlSource != null){
            listener.out.println("calling getXSLURLfromDoc and getMedia " + getMedia(request) );
            xslURL = getXSLURLfromDoc(xmlSource, STYLESHEET_ATTRIBUTE, getMedia(request), processor);
          }
          if (xslURL != null)
            listener.out.println("Parsing XSL Stylesheet Document from XML Document tag: " + xslURL);
          else
            // Configuration Default
            if ((xslURL = ourDefaultParameters.getXSLurl(null)) != null)
              listener.out.println("Parsing XSL Stylesheet Document from configuration: " + xslURL);
        }
        return new InputSource(xslURL);
      }
      catch (IOException ioe)
      {
        throw new ApplyXSLTException(ioe, HttpServletResponse.SC_NOT_FOUND);
      }
      catch (Exception e)
      {
        throw new ApplyXSLTException(e, HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      }
    }
  
    /**
     * Returns the response content type specified by the media-type and encoding attributes of
     * the &lt;xsl:output> element(s) of the stylesheet.
     * @param xslSourceRoot XSL Stylesheet to be examined for &lt;xsl:output> elements.
     * @return The response content type (MIME type and charset) of the stylesheet output
     * @see #process
     */
    public String getContentType(Templates templates)
    {
  	StylesheetRoot xslSourceRoot = (StylesheetRoot)templates;
  	OutputFormatExtended of = xslSourceRoot.getOutput();
  	String encoding = of.getEncoding();
  	String media = of.getMediaType();
      if (encoding != null)
        return media + "; charset=" + encoding;
      return media;
    }
  
    /**
     * Defines and sets select top-level XSL stylesheet variables from the HTTP request, which
     * can be evaluated using &lt;xsl:param-variable&gt;.  The following variables will be
     * automatically set:
     * <dl>
     * <dt><i>ParameterName</i></dt>
     * <dd>Each non-reserved request parameter returned from request.getParameterNames().  If a
     *     parameter contains more than a single value, only the first value is available.</dd>
     * <dt>servlet-RemoteAddr</dt>
     * <dd>Contains String output from request.getRemoteAddr(), which is the IP address
     *     of the client machine.</dd>
     * <dt>servlet-RemoteHost</dt>
     * <dd>Contains String output from request.getRemoteHost(), which is the host name
     *     of the client machine.</dd>
     * <dt>servlet-RemoteUser</dt>
     * <dd>Contains String output from request.getRemoteUser(), which was the user name
     *     accepted by the server to grant access to this servlet.</dd>
     * <dt>servlet-Request</dt>
     * <dd>Contains the request object.</dd>
     * </dl>
     * @param xslprocessor Where to register parameters to be set
     * @param request Provides access to all meaningful parameters to set
     * @see #process
     */
    public void setStylesheetParams(Transformer transformer, HttpServletRequest request)
    {
      Enumeration paramNames = request.getParameterNames();
      while (paramNames.hasMoreElements())
      {
        String paramName = (String) paramNames.nextElement();
        try
        {
          String[] paramVals = request.getParameterValues(paramName);
          if (paramVals != null)
              transformer.setParameter(paramName, null,
                                              new XString(paramVals[0]));
        }
        catch (Exception e)
        {
        }
      }
      try
      {
        transformer.setParameter("servlet-RemoteAddr", null,
                                        new XString(request.getRemoteAddr()));
      }
      catch (Exception e)
      {
      }
      try
      {
        transformer.setParameter("servlet-RemoteHost", null,
                                        new XString(request.getRemoteHost()));
      }
      catch (Exception e)
      {
      }
      try
      {
        transformer.setParameter("servlet-RemoteUser", null,
                                        new XString(request.getRemoteUser()));
      }
      catch (Exception e)
      {
      }
    }
  
  
    /**
     * Writes the following information to the servlet log:
     * <ol>
     * <li>HTTP status code</li>
     * <li>Message</li>
     * <li>Stack trace</li>
     * </ol>
     * @param axe Contains valid HTTP status code, message, and stack trace (optional)
     */
    protected void writeLog(ApplyXSLTException axe)
    {
      writeLog(axe.getMessage(), axe.getStatusCode(), axe.getException());
    }
  
    /**
     * Writes the following information to the servlet log:
     * <ol>
     * <li>HTTP status code</li>
     * <li>Message</li>
     * <li>Stack trace</li>
     * </ol>
     * @param msg Message to be logged
     * @param statusCode Valid status code from javax.servlet.http.HttpServletResponse
     * @param t Used to generate stack trace (may be =null to suppress stack trace)
     */
    protected void writeLog(String msg, int statusCode, Throwable t)
    {
      if (t == null)
        writeLog(msg, statusCode);
      else
      {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        PrintWriter writer = new PrintWriter(bytes, true);
        System.out.println("Exception is " + t.getClass().getName());
        t.printStackTrace(writer);
        log("HTTP Status Code: " + statusCode + " - " + msg + EOL + bytes.toString());
      }
    }
  
    /**
     * Writes the following information to the servlet log:
     * <ol>
     * <li>HTTP status code</li>
     * <li>Message</li>
     * </ol>
     * @param msg Message to be logged
     * @param statusCode Valid status code from javax.servlet.http.HttpServletResponse
     */
    protected void writeLog(String msg, int statusCode)
    {
      log("HTTP Status Code: " + statusCode + " - " + msg);
    }
  
    /**
     * Invokes response.sendError setting an HTTP status code and optionally an error message
     * as an HTML page.
     * <p>If running in debug mode, also try to return a stack trace of the exception and
     * and xml/xsl processor messages.</p>
     * @param response Where to stream the exception to
     * @param xse The wrapper which contains the exception and its HTTP status code
     * @param debug Indicates whether to include stack trace, etc.
     */
    protected void displayException(HttpServletResponse response, ApplyXSLTException xse, boolean debug)
    {
      String mesg = xse.getMessage();
      if (mesg == null)
        mesg = "";
      else mesg = "<B>" + mesg + "</B>";
      StringTokenizer tokens = new StringTokenizer(mesg, EOL);
      StringBuffer strBuf = new StringBuffer();
      while (tokens.hasMoreTokens())
        strBuf.append(tokens.nextToken() + EOL + "<BR>");
      mesg = strBuf.toString();
      if (debug)
      {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        PrintWriter writer = new PrintWriter(bytes, true);
        xse.getException().printStackTrace(writer);
        mesg += " <PRE> " + bytes.toString() + " </PRE> ";
      }
      response.setContentType("text/html");
      try
      {
        response.sendError(xse.getStatusCode(), mesg);
      }
      catch (IOException ioe)
      {
        System.err.println("IOException is occurring when sendError is called");
      }
    }
  
    /**
     * Mapping of HTTP request's user-Agent values to stylesheet media= values.
     * <p>This mapping is defined by a file pointed to by the operational parameter "mediaURL" which can
     *  either contain a full URL or a path relative to the System's server.root /servlets directory.</p>
     * @see #setMediaProps
     * @see #getMedia
     * @serial
     */
    protected OrderedProps ourMediaProps = null;
  
    /**
     * Returns a connection which respects the Accept-Language header of the HTTP request.  This
     * is useful when XSL files are internationalized for use with Web servers which respect this
     * header.
     * <p>For example, Apache 1.3.6 may be configured for multiviews.  Under this configuration,
     * requests for http://myhost/index.html would return http://myhost/index.html.fr to French browsers
     * and http://myhost/index.html.en to English browsers.</p>
     * @param url Location to connect to
     * @param request Could contain an Accept-Language header
     * @return An Accept-Language-enabled URL connection
     * @see #getStylesheet
     */
    protected URLConnection toAcceptLanguageConnection(URL url, HttpServletRequest request)
      throws Exception
    {
      URLConnection tempConnection = url.openConnection();
      tempConnection.setRequestProperty("Accept-Language", request.getHeader("Accept-Language"));
      return tempConnection;
    }
  
  
    /**
     * Returns the XSL stylesheet URL associated with the specified XML document.  If multiple XSL
     * stylesheets are associated with the XML document, preference will be given to the stylesheet
     * which contains an attribute name/value pair that corresponds to the specified attributeName
     * and attributeValue.
     * @param xmlSource XML XSLTInputSource to be searched for associated XSL stylesheets
     * @param attributeName  Attribute name to provide preferential matching
     * @param attributeValue Attribute value to provide preferential matching
     * @return The preferred XSL stylesheet URL, or null if no XSL stylesheet association is found
     * @see #getStylesheet
     */
    public static String getXSLURLfromDoc(InputSource xmlSource,
                                          String attributeName,
                                          String attributeValue,
                                          Processor processor)
    {
      String tempURL = null, returnURL = null;
      try
      {
  	  DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = dfactory.newDocumentBuilder();
        Node sourceTree = docBuilder.parse(xmlSource);
        for(Node child=sourceTree.getFirstChild(); null != child; child=child.getNextSibling())
        {
          if(Node.PROCESSING_INSTRUCTION_NODE == child.getNodeType())
          {
            ProcessingInstruction pi = (ProcessingInstruction)child;
            if(pi.getNodeName().equals("xml-stylesheet"))
            {
              PIA pia = new PIA(pi);
              if("text/xsl".equals(pia.getAttribute("type")))
              {
                tempURL = pia.getAttribute("href");
                String attribute = pia.getAttribute(attributeName);
                if ((attribute != null) && (attribute.indexOf(attributeValue) > -1))
                  return tempURL;
                if (!"yes".equals(pia.getAttribute("alternate")))
                  returnURL = tempURL;
              }
            }
          }
        }
      }
      catch(Exception saxExc)
      {
      }
      return returnURL;
    }  
  
   /**
     * The attribute name in the <?xml-stylesheet> tag used in stylesheet selection.
     */
    protected static final String STYLESHEET_ATTRIBUTE = "media";
  
    /**
     *	The HTTP Header used for matching the Stylesheet attribute via the
     * media properties file selected.
     */
    protected static final String HEADER_NAME = "user-Agent";
  }
  
  /**
   *  Stores the keys and values from a file (similar to a properties file) and
   *  can return the first value which has a key contained in its string.
   *  File can have comment lines starting with '#" and for each line the entries are
   *  separated by tabs and '=' char.
   */
  class OrderedProps
  {
  
    /**
     * Stores the Key and Values as an array of Strings
     */
    private Vector attVec = new Vector(15);
  
    /**
     * Constructor.
     * @param inputStream Stream containing the properties file.
     * @exception IOException Thrown if unable to read from stream
     */
    OrderedProps(InputStream inputStream)
      throws IOException
    {
      BufferedReader input  = new BufferedReader(new InputStreamReader(inputStream));
      String currentLine, Key = null;
      StringTokenizer currentTokens;
      while ((currentLine = input.readLine()) != null)
      {
        currentTokens = new StringTokenizer(currentLine, "=\t\r\n");
        if (currentTokens.hasMoreTokens()) Key = currentTokens.nextToken().trim();
        if ((Key != null) && !Key.startsWith("#") && currentTokens.hasMoreTokens())
        {
          String temp[] = new String[2];
          temp[0] = Key; temp[1] = currentTokens.nextToken().trim();
          attVec.addElement(temp);
        }
      }
    }
  
    /**
     * Iterates through the Key list and returns the first value for whose
     * key the given string contains.  Returns "unknown" if no key is contained
     * in the string.
     * @param s String being searched for a key.
     * @return Value for key found in string, otherwise "unknown"
     */
    String getValue(String s)
    {
      int i, j = attVec.size();
      for (i = 0; i < j; i++)
      {
        String temp[] = (String[]) attVec.elementAt(i);
        if (s.indexOf(temp[0]) > -1)
          return temp[1];
      }
      return "unknown";
    }
  }
  
  /**
   * Parses a processing instruction's (PI) attributes for easy retrieval.
   */
  class PIA
  {
  
    private Hashtable piAttributes = null;
  
    /**
     * Constructor.
     * @param pi The processing instruction whose attributes are to be parsed
     */
    PIA(ProcessingInstruction pi)
    {
      piAttributes = new Hashtable();
      StringTokenizer tokenizer = new StringTokenizer(pi.getNodeValue(), "=\"");
      while(tokenizer.hasMoreTokens())
      {
        piAttributes.put(tokenizer.nextToken().trim(), tokenizer.nextToken().trim());
      }
    }
  
    /**
     * Returns value of specified attribute.
     *  @param name Attribute name
     *  @return Attribute value, or null if the attribute name does not exist
     */
    String getAttribute(String name)
    {
      return (String) piAttributes.get(name);
    }  
  }
  
  
  1.1                  xml-xalan/java/samples/servlet/ApplyXSLTException.java
  
  Index: ApplyXSLTException.java
  ===================================================================
  /*****************************************************************************************************
   * $Id: ApplyXSLTException.java,v 1.1 2000/08/03 15:18:11 dleslie Exp $
   * 
   * Copyright (c) 1998-1999 Lotus Corporation, Inc. All Rights Reserved.
   *				This software is provided without a warranty of any kind.
   * 
   * $State: Exp $
   *****************************************************************************************************/
   
  /*****************************************************************************************************
   *
   * Wrapper for exceptions occurring during apply XSL processing.  
   * Allows for exceptions to be returned with an associated HTTP Status Code.
   *
   * @author Spencer Shepard (sshepard@us.ibm.com)
   * @author R. Adam King (rak@us.ibm.com)
   * @author Tom Rowe (trowe@us.ibm.com)
   *
   *****************************************************************************************************/
  package servlet;
  
  public class ApplyXSLTException extends Exception {
  
      /**
        * Exception Message.
        * @serial
        */ 
      private String myMessage = "";
  
      /**
        * HTTP Status Code. Default= internal server error.
        * @serial
        */
      private int  myHttpStatusCode = javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; 
  
      /**
        * Wrapped exception
        * @serial
        */
      private Exception myException = null;
  
      /**
        * Constructor for exception with no additional detail.
        */
      public ApplyXSLTException() 
      { 
          super(); 
      }
  
      /**
        * Constructor for exception with message.
        * @param s Exception message
        */
      public ApplyXSLTException(String s) 
      { 
          super(); 
  	myMessage = s;
      }
  
      /**
        * Constructor for exception with HTTP status code.
        * @param hsc Valid status code from javax.servlet.http.HttpServletResponse
        */
      public ApplyXSLTException(int hsc) 
      {
  	super();
  	myHttpStatusCode = hsc;
      }
  
      /**
        * Constructor for exception with message and HTTP status code.
        * @param s Exception message
        * @param hsc Valid status code from javax.servlet.http.HttpServletResponse
        */
      public ApplyXSLTException(String s, int hsc)
      {
  	super();
  	myHttpStatusCode = hsc;
      }
  
      /**
        * Constructor for exception.
        * @param e Exception to be wrapped.
        */
      public ApplyXSLTException(Exception e)
      {
  	super();
  	myMessage = e.getMessage();
  	myException = e;
      }
  
      /**
        * Constructor for passed exception with message.
        * @param s Exception message
        * @param e Exception to be wrapped.
        */
      public ApplyXSLTException (String s, Exception e)
      {
  	super();
  	myMessage = s;
  	myException = e;
      }
  
      /**
        * Constructor for passed exception with HTTP status code.
        * @param e Exception to be wrapped.
        * @param hsc Valid status code from javax.servlet.http.HttpServletResponse
        */
      public ApplyXSLTException(Exception e, int hsc)
      {
  	super();
  	myMessage = e.getMessage();
  	myException = e;
  	myHttpStatusCode = hsc;
      }
  
      /**
        * Constructor for passed exception with HTTP status code and message.
        * @param s Exception message
        * @param e Exception to be wrapped.
        * @param hsc Valid status code from javax.servlet.http.HttpServletResponse
        */
      public ApplyXSLTException(String s, Exception e, int hsc)
      {
  	super();
  	myMessage = s;
  	myException = e;
  	myHttpStatusCode = hsc;
      }
  
      /**
        * Returns exception message.
        * @return exception message
        */
      public String getMessage()
      {
  	return myMessage;
      }
  
      /**
        * Appends string to exception message.
        * @param s String to be added to message
        */
      public void appendMessage(String s)
      {
  	myMessage += s;
      }
  
      /**
        * Returns the wrapped exception.
        * @return Wrapped exception
        */
      public Exception getException()
      {
  	return myException;
      }
  
      /**
        * Returns the HTTP status code associated with the exception.
        * @return Valid status code from javax.servlet.http.HttpServletResponse
        */
      public int getStatusCode()
      {
  	return myHttpStatusCode;
      }
  }
  
  
  
  
  1.1                  xml-xalan/java/samples/servlet/ApplyXSLTListener.java
  
  Index: ApplyXSLTListener.java
  ===================================================================
  /*****************************************************************************************************
   * $Id: ApplyXSLTListener.java,v 1.1 2000/08/03 15:18:11 dleslie Exp $
   *
   * Copyright (c) 1998-1999 Lotus Corporation, Inc. All Rights Reserved.
   *				This software is provided without a warranty of any kind.
   *
   * $State: Exp $
   *****************************************************************************************************/
  package servlet;
  
  import java.io.*;
  import org.xml.sax.*;
  import org.apache.xalan.xpath.xml.ProblemListenerDefault.*;
  
  /*****************************************************************************************************
   * ApplyXSLTListener provides a buffered listener essential for capturing, and then subsequently
   * reporting, XML and XSL processor messages which may be of use in debugging XML+XSL processed at
   * the server.
   *
   * @author Spencer Shepard (sshepard@us.ibm.com)
   * @author R. Adam King (rak@us.ibm.com)
   * @author Tom Rowe (trowe@us.ibm.com)
   *
   *****************************************************************************************************/
  
  public class ApplyXSLTListener extends org.apache.xalan.xpath.xml.ProblemListenerDefault implements ErrorHandler
  {
  
      /**
        * Output stream
        */
      private ByteArrayOutputStream outStream = new ByteArrayOutputStream();
  
      /**
        * Buffered output stream
        */
      public PrintWriter out = null;
  
      /**
        * Constructor.
        */
      public ApplyXSLTListener()
      {
  	out = new PrintWriter(new BufferedOutputStream(outStream), true);
      }
  
      /**
        * Receive notification of a warning.
        *
        * @param spe The warning information encapsulated in a SAX parse exception.
        */
      public void warning(SAXParseException spe)
      {
  	out.println("Parser Warning: " + spe.getMessage());
      }
  
      /**
        * Receive notification of a recoverable error.
        *
        * @param spe The error information encapsulated in a SAX parse exception.
        */
      public void error(SAXParseException spe)
      {
  	out.println("Parser Error: " + spe.getMessage());
      }
  
      /**
        * Receive notification of a non-recoverable error.
        *
        * @param spe The error information encapsulated in a SAX parse exception.
        * @exception SAXException Always thrown
        */
      public void fatalError(SAXParseException spe)
      throws SAXException
      {
  	out.println("Parser Fatal Error: " + spe.getMessage());
  	throw spe;
      }
  
      /**
        * Returns the buffered processing message(s).
        * @return Buffered processing message(s)
        */
      public String getMessage()
      {
  	return outStream.toString();
      }
  }
  
  
  
  
  1.1                  xml-xalan/java/samples/servlet/ApplyXSLTProperties.java
  
  Index: ApplyXSLTProperties.java
  ===================================================================
  /*****************************************************************************************************
   * $Id: ApplyXSLTProperties.java,v 1.1 2000/08/03 15:18:11 dleslie Exp $
   * 
   * Copyright (c) 1998-1999 Lotus Corporation, Inc. All Rights Reserved.
   *				This software is provided without a warranty of any kind.
   * 
   * $State: Exp $
   *****************************************************************************************************/
  package servlet;
  
  import java.net.MalformedURLException;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  /*****************************************************************************************************
   * 
   * ApplyXSLTProperties contains operational parameters for ApplyXSLT based 
   * on program defaults and configuration.  
   * <p>This class is also used to return values for request-time parameters.</p>
   *
   * @author Spencer Shepard (sshepard@us.ibm.com)
   * @author R. Adam King (rak@us.ibm.com)
   * @author Tom Rowe (trowe@us.ibm.com)
   *
   *****************************************************************************************************/
  
  public class ApplyXSLTProperties {
  
      /**
        * Program default for parameter "URL"
        */
      private final String DEFAULT_URL;
  
      /**
        * Program default for parameter "xslURL"
        */
      private final String DEFAULT_xslURL;
      
      /**
        * Program default for parameter "debug"
        */
      private final boolean DEFAULT_debug;
  
      /**
        * Program default for parameter "noConflictWarnings"
        */
      private final boolean DEFAULT_noCW;
      
      /**
        * Constructor to use program defaults.
        */
      public ApplyXSLTProperties() 
      {
  	DEFAULT_URL = null;
  	DEFAULT_xslURL = null;
  	DEFAULT_debug = false;
  	DEFAULT_noCW = false;
      }
  
      /**
        * Constructor to use to override program defaults.
        * @param config Servlet configuration
        */
      public ApplyXSLTProperties(ServletConfig config)
      {
  	String xm = config.getInitParameter("URL"),
  	       xu = config.getInitParameter("xslURL"),
  	       db = config.getInitParameter("debug"),
  	       cw = config.getInitParameter("noConflictWarnings");
  	       
  	if (xm != null) DEFAULT_URL = xm;
  	else DEFAULT_URL = null;
  	if (xu != null) DEFAULT_xslURL = xu;
  	else DEFAULT_xslURL = null;
  	if (db != null) DEFAULT_debug = new Boolean(db).booleanValue();
  	else DEFAULT_debug = false;
  	if (cw != null) DEFAULT_noCW = new Boolean(cw).booleanValue();
  	else DEFAULT_noCW = false;
      }
     
      /**
        * Given a parameter name, returns the HTTP request's String value; 
        * if not present in request, returns default String value.
        * @param request Request to check for default override
        * @param param Name of the parameter
        * @return String value of named parameter
        */
      public String getRequestParmString(HttpServletRequest request, String param)
      {
  	if (request != null) { 
  	    String[] paramVals = request.getParameterValues(param); 
  	    if (paramVals != null) 
  		return paramVals[0];
  	}
  	return null;
      }
  
      /**
        * Returns the current setting for "URL".
        * @param request Request to check for parameter value
        * @return String value for "URL"
        * @exception MalformedURLException Will not be thrown
        */
      public String getXMLurl(HttpServletRequest request)
      throws MalformedURLException
      {
  	String temp = getRequestParmString(request, "URL");
  	if (temp != null)
  	    return temp;
  	return DEFAULT_URL;
      }     
      
      /**
        * Returns the current setting for "xslURL".
        * @param request Request to check for parameter value
        * @return String value for "xslURL"
        * @exception MalformedURLException Will not be thrown
        */
      public String getXSLurl(HttpServletRequest request)
      throws MalformedURLException
      {  
  	String temp = getRequestParmString(request, "xslURL");
  	if (temp != null)
  	    return temp;
  	return DEFAULT_xslURL;
      }
      
      /**
        * Returns the current setting for "debug".
        * @param request Request to check for parameter value
        * @return Boolean value for "debug"
        */
      public boolean isDebug(HttpServletRequest request)
      {
  	String temp = getRequestParmString(request, "debug");
  	if (temp != null)
  	    return new Boolean(temp).booleanValue();
  	return DEFAULT_debug;
      }
  
      /**
        * Returns the current setting for "noConflictWarnings".
        * @param request Request to check for parameter value
        * @return Boolean value for "noConflictWarnings"
        */
      boolean isNoCW(HttpServletRequest request)
      {
  	String temp = getRequestParmString(request, "noConflictWarnings");
  	if (temp != null)
  	    return new Boolean(temp).booleanValue();
  	return DEFAULT_noCW;
      }    
  }
  
  
  1.1                  xml-xalan/java/samples/servlet/default.xsl
  
  Index: default.xsl
  ===================================================================
  <?xml version="1.0"?>
  
  <!--                                                                                -->
  <!--  Default XSL stylesheet for use by com.lotus.xsl.server#DefaultApplyXSL.       -->
  <!--                                                                                -->
  <!--  This stylesheet mimics the default behavior of IE when XML data is displayed  -->
  <!--  without a corresponding XSL stylesheet.  This stylesheet uses JavaScript      -->
  <!--  to accommodate node expansion and contraction.                                -->
  <!--                                                                                -->
  
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                  xmlns="http://www.w3.org/TR/REC-html40">
                  
  <xsl:output method="html" indent="no"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="/">
    <HTML>
      <HEAD>
        <STYLE type="text/css">
          BODY {font:x-small 'Verdana'; margin-right:1.5em}
        <!-- container for expanding/collapsing content -->
          .c  {cursor:hand}
        <!-- button - contains +/-/nbsp -->
          .b  {color:red; font-family:'Courier New'; font-weight:bold; text-decoration:none}
        <!-- element container -->
          .e  {margin-left:1em; text-indent:-1em; margin-right:1em}
        <!-- comment or cdata -->
          .k  {margin-left:1em; text-indent:-1em; margin-right:1em}
        <!-- tag -->
          .t  {color:#990000}
        <!-- tag in xsl namespace -->
          .xt {color:#990099}
        <!-- attribute in xml or xmlns namespace -->
          .ns {color:red}
        <!-- markup characters -->
          .m  {color:blue}
        <!-- text node -->
          .tx {font-weight:bold}
        <!-- multi-line (block) cdata -->
          .db {text-indent:0px; margin-left:1em; margin-top:0px; margin-bottom:0px;
               padding-left:.3em; border-left:1px solid #CCCCCC; font:small Courier}
        <!-- single-line (inline) cdata -->
          .di {font:small Courier}
        <!-- DOCTYPE declaration -->
          .d  {color:blue}
        <!-- pi -->
          .pi {color:blue}
        <!-- multi-line (block) comment -->
          .cb {text-indent:0px; margin-left:1em; margin-top:0px; margin-bottom:0px;
               padding-left:.3em; font:small Courier; color:#888888}
        <!-- single-line (inline) comment -->
          .ci {font:small Courier; color:#888888}
          PRE {margin:0px; display:inline}
        </STYLE>
  
        <SCRIPT type="text/javascript"><xsl:comment><![CDATA[
          // Detect and switch the display of CDATA and comments from an inline view
          //  to a block view if the comment or CDATA is multi-line.
          function f(e)
          {
            // if this element is an inline comment, and contains more than a single
            //  line, turn it into a block comment.
            if (e.className == "ci") {
              if (e.children(0).innerText.indexOf("\n") > 0)
                fix(e, "cb");
            }
            
            // if this element is an inline cdata, and contains more than a single
            //  line, turn it into a block cdata.
            if (e.className == "di") {
              if (e.children(0).innerText.indexOf("\n") > 0)
                fix(e, "db");
            }
            
            // remove the id since we only used it for cleanup
            e.id = "";
          }
          
          // Fix up the element as a "block" display and enable expand/collapse on it
          function fix(e, cl)
          {
            // change the class name and display value
            e.className = cl;
            e.style.display = "block";
            
            // mark the comment or cdata display as a expandable container
            j = e.parentElement.children(0);
            j.className = "c";
  
            // find the +/- symbol and make it visible - the dummy link enables tabbing
            k = j.children(0);
            k.style.visibility = "visible";
            k.href = "#";
          }
  
          // Change the +/- symbol and hide the children.  This function works on "element"
          //  displays
          function ch(e)
          {
            // find the +/- symbol
            mark = e.children(0).children(0);
            
            // if it is already collapsed, expand it by showing the children
            if (mark.innerText == "+")
            {
              mark.innerText = "-";
              for (var i = 1; i < e.children.length; i++)
                e.children(i).style.display = "block";
            }
            
            // if it is expanded, collapse it by hiding the children
            else if (mark.innerText == "-")
            {
              mark.innerText = "+";
              for (var i = 1; i < e.children.length; i++)
                e.children(i).style.display="none";
            }
          }
          
          // Change the +/- symbol and hide the children.  This function work on "comment"
          //  and "cdata" displays
          function ch2(e)
          {
            // find the +/- symbol, and the "PRE" element that contains the content
            mark = e.children(0).children(0);
            contents = e.children(1);
            
            // if it is already collapsed, expand it by showing the children
            if (mark.innerText == "+")
            {
              mark.innerText = "-";
              // restore the correct "block"/"inline" display type to the PRE
              if (contents.className == "db" || contents.className == "cb")
                contents.style.display = "block";
              else contents.style.display = "inline";
            }
            
            // if it is expanded, collapse it by hiding the children
            else if (mark.innerText == "-")
            {
              mark.innerText = "+";
              contents.style.display = "none";
            }
          }
          
          // Handle a mouse click
          function cl()
          {
            e = window.event.srcElement;
            
            // make sure we are handling clicks upon expandable container elements
            if (e.className != "c")
            {
              e = e.parentElement;
              if (e.className != "c")
              {
                return;
              }
            }
            e = e.parentElement;
            
            // call the correct funtion to change the collapse/expand state and display
            if (e.className == "e")
              ch(e);
            if (e.className == "k")
              ch2(e);
          }
          
          // Erase bogus link info from the status window
          function h()
          {
            window.status=" ";
          }
  
          // Set the onclick handler
          document.onclick = cl;
          
        ]]>//</xsl:comment></SCRIPT>
      </HEAD>
  
      <BODY class="st"><xsl:apply-templates/></BODY>
  
    </HTML>
  </xsl:template>
  
  <!-- Templates for each node type follows.  The output of each template has a similar structure
    to enable script to walk the result tree easily for handling user interaction. -->
    
  <!-- Template for pis not handled elsewhere -->
  <xsl:template match="processing-instruction()">
    <DIV class="e">
    <SPAN class="b">&#160;</SPAN>
    <SPAN class="m">&lt;?</SPAN><SPAN class="pi"><xsl:value-of select="name(.)"/> <xsl:value-of select="."/></SPAN><SPAN class="m">?&gt;</SPAN>
    </DIV>
  </xsl:template>
  
  <!-- Template for the XML declaration.  Need a separate template because the pseudo-attributes
      are actually exposed as attributes instead of just element content, as in other pis 
  <xsl:template match="processing-instruction('xml')">
    <DIV class="e">
    <SPAN class="b">&#160;</SPAN>
    <SPAN class="m">&lt;?</SPAN><SPAN class="pi">xml <xsl:for-each select="@*"><xsl:value-of select="name(.)"/>="<xsl:value-of select="."/>" </xsl:for-each></SPAN><SPAN class="m">?&gt;</SPAN>
    </DIV>
  </xsl:template>
  -->
  
  <!-- Template for attributes not handled elsewhere -->
  <xsl:template match="@*"><SPAN class="t"><xsl:text> </xsl:text><xsl:value-of select="name(.)"/></SPAN><SPAN class="m">="</SPAN><B><xsl:value-of select="."/></B><SPAN class="m">"</SPAN></xsl:template>
  
  <!-- Template for attributes in the xmlns or xml namespace
  <xsl:template match="@xmlns:*|@xmlns|@xml:*"><SPAN class="ns"> <xsl:value-of select="name(.)"/></SPAN><SPAN class="m">="</SPAN><B class="ns"><xsl:value-of select="."/></B><SPAN class="m">"</SPAN></xsl:template>
  -->
  
  <!-- Template for text nodes -->
  <xsl:template match="text()">
    <xsl:choose><xsl:when test="name(.) = '#cdata-section'"><xsl:call-template name="cdata"/></xsl:when>
    <xsl:otherwise><DIV class="e">
    <SPAN class="b">&#160;</SPAN>
    <SPAN class="tx"><xsl:value-of select="."/></SPAN>
    </DIV></xsl:otherwise></xsl:choose>
  </xsl:template>
    
  <!-- Template for comment nodes -->
  <xsl:template match="comment()">
    <DIV class="k">
    <SPAN><A class="b" onclick="return false" onfocus="h()" STYLE="visibility:hidden">-</A> <SPAN class="m">&lt;!--</SPAN></SPAN>
    <SPAN id="clean" class="ci"><PRE><xsl:value-of select="."/></PRE></SPAN>
    <SPAN class="b">&#160;</SPAN> <SPAN class="m">--&gt;</SPAN>
    <SCRIPT>f(clean);</SCRIPT></DIV>
  </xsl:template>
  
  <!-- Template for cdata nodes -->
  <xsl:template name="cdata">
    <DIV class="k">
    <SPAN><A class="b" onclick="return false" onfocus="h()" STYLE="visibility:hidden">-</A> <SPAN class="m">&lt;![CDATA[</SPAN></SPAN>
    <SPAN id="clean" class="di"><PRE><xsl:value-of select="."/></PRE></SPAN>
    <SPAN class="b">&#160;</SPAN> <SPAN class="m">]]&gt;</SPAN>
    <SCRIPT>f(clean);</SCRIPT></DIV>
  </xsl:template>
  
  <!-- Template for elements not handled elsewhere (leaf nodes) -->
  <xsl:template match="*">
    <DIV class="e"><DIV STYLE="margin-left:1em;text-indent:-2em">
    <SPAN class="b">&#160;</SPAN>
    <SPAN class="m">&lt;</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN> <xsl:apply-templates select="@*"/><SPAN class="m"> /&gt;</SPAN>
    </DIV></DIV>
  </xsl:template>
    
  <!-- Template for elements with comment, pi and/or cdata children
  <xsl:template match="*[comment() or processing-instruction() or cdata()]">
    <DIV class="e">
    <DIV class="c"><A href="#" onclick="return false" onfocus="h()" class="b">-</A> <SPAN class="m">&lt;</SPAN><SPAN><xsl:attribute name="class"><xsl:if test="xsl:*">x</xsl:if>t</xsl:attribute><xsl:value-of select="name(.)"/></SPAN><xsl:apply-templates select="@*"/> <SPAN class="m">&gt;</SPAN></DIV>
    <DIV><xsl:apply-templates/>
    <DIV><SPAN class="b">&#160;</SPAN> <SPAN class="m">&lt;/</SPAN><SPAN><xsl:attribute name="class"><xsl:if test="xsl:*">x</xsl:if>t</xsl:attribute><xsl:value-of select="name(.)"/></SPAN><SPAN class="m">&gt;</SPAN></DIV>
    </DIV></DIV>
  </xsl:template> -->
  
  <!-- Template for elements with only text children -->
  <xsl:template match="*[text() and not(comment() or processing-instruction() or *)]">
    <DIV class="e"><DIV STYLE="margin-left:1em;text-indent:-2em">
    <SPAN class="b">&#160;</SPAN> <SPAN class="m">&lt;</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN><xsl:apply-templates select="@*"/>
    <SPAN class="m">&gt;</SPAN><SPAN class="tx"><xsl:value-of select="."/></SPAN><SPAN class="m">&lt;/</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN><SPAN class="m">&gt;</SPAN>
    </DIV></DIV>
  </xsl:template>
  
  <!-- Template for elements with element children -->
  <xsl:template match="*[*]">
    <DIV class="e">
    <DIV class="c" STYLE="margin-left:1em;text-indent:-2em"><A href="#" onclick="return false" onfocus="h()" class="b">-</A> <SPAN class="m">&lt;</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN><xsl:apply-templates select="@*"/><SPAN class="m">&gt;</SPAN></DIV>
    <DIV><xsl:apply-templates/>
    <DIV><SPAN class="b">&#160;</SPAN><SPAN class="m">&lt;/</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN><SPAN class="m">&gt;</SPAN></DIV>
    </DIV></DIV>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.1                  xml-xalan/java/samples/servlet/default2.xsl
  
  Index: default2.xsl
  ===================================================================
  <?xml version="1.0"?>
  
  <!--                                                                                -->
  <!--  Default XSL stylesheet for use by com.lotus.xsl.server#DefaultApplyXSL.       -->
  <!--                                                                                -->
  <!--  This stylesheet mimics the default behavior of IE when XML data is displayed  -->
  <!--  without a corresponding XSL stylesheet.  This stylesheet uses no JavaScript   -->
  <!--  and displays all nodes as fully expanded.                                     -->
  <!--                                                                                -->
  
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                  xmlns="http://www.w3.org/TR/REC-html40">
                  
  <xsl:output method="html" indent="no"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="/">
    <HTML>
      <HEAD>
        <STYLE type="text/css">
          BODY {font:x-small 'Verdana'; margin-right:1.5em}
        <!-- container for expanding/collapsing content -->
          .c  {cursor:hand}
        <!-- button - contains +/-/nbsp -->
          .b  {color:red; font-family:'Courier New'; font-weight:bold; text-decoration:none}
        <!-- element container -->
          .e  {margin-left:1em; text-indent:-1em; margin-right:1em}
        <!-- comment or cdata -->
          .k  {margin-left:1em; text-indent:-1em; margin-right:1em}
        <!-- tag -->
          .t  {color:#990000}
        <!-- tag in xsl namespace -->
          .xt {color:#990099}
        <!-- attribute in xml or xmlns namespace -->
          .ns {color:red}
        <!-- markup characters -->
          .m  {color:blue}
        <!-- text node -->
          .tx {font-weight:bold}
        <!-- multi-line (block) cdata -->
          .db {text-indent:0px; margin-left:1em; margin-top:0px; margin-bottom:0px;
               padding-left:.3em; border-left:1px solid #CCCCCC; font:small Courier}
        <!-- single-line (inline) cdata -->
          .di {font:small Courier}
        <!-- DOCTYPE declaration -->
          .d  {color:blue}
        <!-- pi -->
          .pi {color:blue}
        <!-- multi-line (block) comment -->
          .cb {text-indent:0px; margin-left:1em; margin-top:0px; margin-bottom:0px;
               padding-left:.3em; font:small Courier; color:#888888}
        <!-- single-line (inline) comment -->
          .ci {font:small Courier; color:#888888}
          PRE {margin:0px; display:inline}
        </STYLE>
      </HEAD>
  
      <BODY class="st"><xsl:apply-templates/></BODY>
  
    </HTML>
  </xsl:template>
  
  <!-- Templates for each node type follows.  The output of each template has a similar structure
    to enable script to walk the result tree easily for handling user interaction. -->
    
  <!-- Template for pis not handled elsewhere -->
  <xsl:template match="processing-instruction()">
    <DIV class="e">
    <SPAN class="b">&#160;</SPAN>
    <SPAN class="m">&lt;?</SPAN><SPAN class="pi"><xsl:value-of select="name(.)"/> <xsl:value-of select="."/></SPAN><SPAN class="m">?&gt;</SPAN>
    </DIV>
  </xsl:template>
  
  <!-- Template for the XML declaration.  Need a separate template because the pseudo-attributes
      are actually exposed as attributes instead of just element content, as in other pis 
  <xsl:template match="processing-instruction('xml')">
    <DIV class="e">
    <SPAN class="b">&#160;</SPAN>
    <SPAN class="m">&lt;?</SPAN><SPAN class="pi">xml <xsl:for-each select="@*"><xsl:value-of select="name(.)"/>="<xsl:value-of select="."/>" </xsl:for-each></SPAN><SPAN class="m">?&gt;</SPAN>
    </DIV>
  </xsl:template>
  -->
  
  <!-- Template for attributes not handled elsewhere -->
  <xsl:template match="@*"><SPAN class="t"><xsl:text> </xsl:text><xsl:value-of select="name(.)"/></SPAN><SPAN class="m">="</SPAN><B><xsl:value-of select="."/></B><SPAN class="m">"</SPAN></xsl:template>
  
  <!-- Template for attributes in the xmlns or xml namespace
  <xsl:template match="@xmlns:*|@xmlns|@xml:*"><SPAN class="ns"> <xsl:value-of select="name(.)"/></SPAN><SPAN class="m">="</SPAN><B class="ns"><xsl:value-of select="."/></B><SPAN class="m">"</SPAN></xsl:template>
  -->
  
  <!-- Template for text nodes -->
  <xsl:template match="text()">
    <xsl:choose><xsl:when test="name(.) = '#cdata-section'"><xsl:call-template name="cdata"/></xsl:when>
    <xsl:otherwise><DIV class="e">
    <SPAN class="b">&#160;</SPAN>
    <SPAN class="tx"><xsl:value-of select="."/></SPAN>
    </DIV></xsl:otherwise></xsl:choose>
  </xsl:template>
    
  <!-- Template for comment nodes -->
  <xsl:template match="comment()">
    <DIV class="k">
    <SPAN><SPAN class="b" STYLE="visibility:hidden">-</SPAN> <SPAN class="m">&lt;!--</SPAN></SPAN>
    <SPAN class="cb"><PRE><xsl:value-of select="."/></PRE></SPAN>
    <SPAN class="b">&#160;</SPAN> <SPAN class="m">--&gt;</SPAN>
    </DIV>
  </xsl:template>
  
  <!-- Template for cdata nodes -->
  <xsl:template name="cdata">
    <DIV class="k">
    <SPAN><SPAN class="b" STYLE="visibility:hidden">-</SPAN> <SPAN class="m">&lt;![CDATA[</SPAN></SPAN>
    <SPAN class="db"><PRE><xsl:value-of select="."/></PRE></SPAN>
    <SPAN class="b">&#160;</SPAN> <SPAN class="m">]]&gt;</SPAN>
    </DIV>
  </xsl:template>
  
  <!-- Template for elements not handled elsewhere (leaf nodes) -->
  <xsl:template match="*">
    <DIV class="e"><DIV STYLE="margin-left:1em;text-indent:-2em">
    <SPAN class="b">&#160;</SPAN>
    <SPAN class="m">&lt;</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN> <xsl:apply-templates select="@*"/><SPAN class="m"> /&gt;</SPAN>
    </DIV></DIV>
  </xsl:template>
    
  <!-- Template for elements with comment, pi and/or cdata children
  <xsl:template match="*[comment() or processing-instruction() or cdata()]">
    <DIV class="e">
    <DIV class="c"><A href="#" onclick="return false" onfocus="h()" class="b">-</A> <SPAN class="m">&lt;</SPAN><SPAN><xsl:attribute name="class"><xsl:if test="xsl:*">x</xsl:if>t</xsl:attribute><xsl:value-of select="name(.)"/></SPAN><xsl:apply-templates select="@*"/> <SPAN class="m">&gt;</SPAN></DIV>
    <DIV><xsl:apply-templates/>
    <DIV><SPAN class="b">&#160;</SPAN> <SPAN class="m">&lt;/</SPAN><SPAN><xsl:attribute name="class"><xsl:if test="xsl:*">x</xsl:if>t</xsl:attribute><xsl:value-of select="name(.)"/></SPAN><SPAN class="m">&gt;</SPAN></DIV>
    </DIV></DIV>
  </xsl:template> -->
  
  <!-- Template for elements with only text children -->
  <xsl:template match="*[text() and not(comment() or processing-instruction() or *)]">
    <DIV class="e"><DIV STYLE="margin-left:1em;text-indent:-2em">
    <SPAN class="b">&#160;</SPAN> <SPAN class="m">&lt;</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN><xsl:apply-templates select="@*"/>
    <SPAN class="m">&gt;</SPAN><SPAN class="tx"><xsl:value-of select="."/></SPAN><SPAN class="m">&lt;/</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN><SPAN class="m">&gt;</SPAN>
    </DIV></DIV>
  </xsl:template>
  
  <!-- Template for elements with element children -->
  <xsl:template match="*[*]">
    <DIV class="e">
    <DIV class="c" STYLE="margin-left:1em;text-indent:-2em"><SPAN class="b">-</SPAN><SPAN class="m">&lt;</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN><xsl:apply-templates select="@*"/> <SPAN class="m">&gt;</SPAN></DIV>
    <DIV><xsl:apply-templates/>
    <DIV><SPAN class="b">&#160;</SPAN> <SPAN class="m">&lt;/</SPAN><SPAN class="t"><xsl:value-of select="name(.)"/></SPAN><SPAN class="m">&gt;</SPAN></DIV>
    </DIV></DIV>
  </xsl:template>
  
  </xsl:stylesheet>
  
  
  1.1                  xml-xalan/java/samples/servlet/DefaultApplyXSLTProperties.java
  
  Index: DefaultApplyXSLTProperties.java
  ===================================================================
  /*****************************************************************************************************
   * $Id: DefaultApplyXSLTProperties.java,v 1.1 2000/08/03 15:18:11 dleslie Exp $
   * 
   * Copyright (c) 1998-1999 Lotus Corporation, Inc. All Rights Reserved.
   *				This software is provided without a warranty of any kind.
   * 
   * $State: Exp $
   *****************************************************************************************************/
  package servlet;
  
  import java.net.*;
  import javax.servlet.*;
  import javax.servlet.http.*;
  
  /*****************************************************************************************************
   * 
   * DefaultApplyXSLTProperties contains operational parameters for DefaultApplyXSLT based 
   * on program defaults and configuration.  
   * <p>This class is also used to return values for request-time parameters.</p>
   *
   * @author Spencer Shepard (sshepard@us.ibm.com)
   * @author R. Adam King (rak@us.ibm.com)
   * @author Tom Rowe (trowe@us.ibm.com)
   *
   *****************************************************************************************************/
  
  public class DefaultApplyXSLTProperties extends ApplyXSLTProperties {
      
      /**
        * Program default for parameter "catalog".
        * @see #getCatalog
        */
      private final String DEFAULT_catalog;
  
      /**
        * Host used for local context comparisons.
        * @see #getLocalHost
        * @see #setLocalHost
        */
      protected transient String localHost = null;
  
      /**
        * Constructor to use program defaults.
        */
      public DefaultApplyXSLTProperties()
      {
  	super();
  	DEFAULT_catalog = null;
  	setLocalHost();
  	setSystemProperties();
      }
  
      /**
        * Constructor to use to override program defaults.
        * @param config Servlet configuration
        * @see #setLocalHost
        */
      public DefaultApplyXSLTProperties(ServletConfig config)
      {
  	super(config);
  	String cat = config.getInitParameter("catalog");
  	if (cat != null) DEFAULT_catalog = cat;
  	else DEFAULT_catalog = null;
  	setLocalHost();
  	setSystemProperties();
      }
  
      /**
        * Sets the name of the local IP host name; this value will be used to constrain untrusted 
        * XML document and XSL stylesheet URLs to this trusted host.
        * @see #getLocalHost
        */
      protected void setLocalHost()
      {
  	try { 
  	    localHost = InetAddress.getLocalHost().getHostName();
  	} catch (Exception uhe) {
  	    localHost = null;
  	}
      }
  
      /**
        * Returns the name of trusted IP host.
        * @return Name of trusted host
        * @see #setLocalHost
        */
      public String getLocalHost()
      {
  	return localHost;
      }
  
      /**
        * Returns a URL which is constrained to a trusted IP host.
        * @param xURL URL or file path to be made safe 
        * @return Safe URL
        * @exception MalformedURLException Thrown when xURL is not a valid URL
        * @see #setLocalHost
        * @see #getLocalHost
        */
      public URL toSafeURL(String xURL)
      throws MalformedURLException
      {
  	if (xURL == null)
  	    return null;
  
  	if (xURL.startsWith("/")) {
  	    try {
  		return new URL("http", localHost, xURL);
  	    } catch (MalformedURLException mue) {
  	    throw new MalformedURLException("toSafeURL(): " + xURL + 
  					    " did not map to local");
  	    }
  	}
  	URL tempURL = null;
  	try { 
  	    tempURL = new URL(xURL);
  	} catch (MalformedURLException mue) {
  	    throw new MalformedURLException("toSafeURL(): " + xURL + 
  					    " not a valid URL");
  	}
  	try { 
  	    return new URL(tempURL.getProtocol(), localHost, 
  			   tempURL.getPort(), tempURL.getFile());
  	} catch (MalformedURLException mue) {
  	    throw new MalformedURLException("toSafeURL(): " + xURL + 
  					    " could not be converted to local host");
  	}
      }
  
      /**
        *	Returns a string representing the constrained URL for the XML document.
        * If there is no request parameter for the XML document, return the configured default.
        * @param request May contain an XML document URL parameter
        * @return String form of XML URL
        * @exception MalformedURLException Thrown when request URL is not a valid URL or path
        * @see #toSafeURL
        */
      public String getXMLurl(HttpServletRequest request)
      throws MalformedURLException
      {
  	URL url = toSafeURL(getRequestParmString(request, "URL"));
  	if (url == null)
  	    return super.getXMLurl(null);
  	return url.toExternalForm();
      }
  
      /**
        * Returns a string representing the constrained URL for the XSL stylesheet 
        * from the request.
        * @param request May contain an XSL stylesheet URL parameter
        * @return String form of request XSL URL, or null if request contains no xslURL parameter
        * @exception MalformedURLException Thrown when request URL is not a valid URL or path
        * @see #toSafeURL
        */
      public String getXSLRequestURL(HttpServletRequest request)
      throws MalformedURLException
      {
  	URL url = toSafeURL(getRequestParmString(request, "xslURL"));
  	if (url == null)
  	    return null;
  	return url.toExternalForm();
      }
  
      /**
        * Returns a string representing the constrained request URL for the XSL stylesheet.
        * If there is no request parameter for the XSL stylesheet, return the configured default.
        * @param request May contain an XSL stylesheet URL parameter
        * @return String form of XSL URL
        * @exception MalformedURLException Thrown when request URL is not a valid URL or path
        * @see #toSafeURL
        */
      public String getXSLurl(HttpServletRequest request)
      throws MalformedURLException
      {
  	String reqURL = getXSLRequestURL(request);
  	if (reqURL != null)
  	    return reqURL;
  	return super.getXSLurl(null);
      }
  
      /**
        * Returns URLs for all <a href="http://www.ccil.org/~cowan/XML/XCatalog.html">XCatalogs</a> 
        * that are to be used to process the request.  Catalogs are used to resolve XML public identifiers
        * into system identifiers.
        * <p>A single XCatalog can be configured as a default,
        * but multiple XCatalogs can be specified at request time to augment the configured default.
        * @param request May contain one or more XCatalog parameters
        * @return Array of strings for all catalog URLs
        */
      public String[] getCatalog(HttpServletRequest request)
      {
  	String temp[] = request.getParameterValues("catalog");
  	if (DEFAULT_catalog == null)
  	    return temp;
  	if (temp == null) {
  	    String defaultArray[] = new String [1];
  	    defaultArray[0] = DEFAULT_catalog;
  	    return defaultArray;
  	}
  	int i, len = temp.length + 1;
  	String newCatalogs[] = new String[len];
  	newCatalogs[0] = DEFAULT_catalog;
  	for (i=1; i < len; i++) {
  	    newCatalogs[i] = temp[i-1];
  	}
  	return newCatalogs;
      }
  	
  	 /**
     * Sets required system properties until we figure out why servlet 
     * sometimes fails to read properties from properties files.
     */	
    protected void setSystemProperties()
    {
  	 System.setProperty("trax.processor.xslt", "org.apache.xalan.processor.StylesheetProcessor");
  	 System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser");
  	 System.setProperty("serialize.methods", "xml,html,Text");
  	 System.setProperty("serialize.xml", "org.apache.xml.serialize.XMLSerializer");	 
  	 System.setProperty("serialize.html", "org.apache.xml.serialize.HTMLSerializer");	 
  	 System.setProperty("serialize.text", "org.apache.xml.serialize.TextSerializer");	 
  	 System.setProperty("serialize.xhtml", "org.apache.xml.serialize.XHTMLSerializer");	 
  	 System.setProperty("serialize.wml", "org.apache.xml.serialize.WMLSerializer");	
  	 System.setProperty("serialize.format.xml", "serialize.format.XMLOutputFormat");	 
  	 System.setProperty("serialize.format.html", "serialize.format.XMLOutputFormat");	 
  	 System.setProperty("serialize.format.text", "serialize.format.XMLOutputFormat");	 
  	 System.setProperty("serialize.format.xhtml", "serialize.format.XHTMLOutputFormat");	 
  	 System.setProperty("serialize.format.text", "serialize.format.TextOutputFormat");	 
    }
  }
  
  
  
  1.1                  xml-xalan/java/samples/servlet/media.properties
  
  Index: media.properties
  ===================================================================
  # This property file is used by com.lotus.xsl.server.DefaultApplyXSL.
  #
  # Each line below specifies a mapping rule between a value contained in the HTTP request's user-Agent 
  # field and a value to be scanned for in XSL stylesheet(s) associated with the XML data. This mapping 
  # enables relationships to be defined between client capabilities and stylesheets capable of acting 
  # on these capabilities.
  #
  # The rules defined below are order-significant.  In other words, if the first rule is unsuccessful,
  # the second rule will be tried, etc.  The media value "unknown" will be used when no rules are
  # satisfied.
  #
  # Example: 
  #
  # Mapping rules of...
  #
  #   MSIE=explorer
  #   MSPIE=pocketexplorer
  #
  # ...and XML data that contains XSL stylesheet associations of...
  #
  # <?xml-stylesheet                 media="explorer"       href="alldata.xsl"  type="text/xsl"?>
  # <?xml-stylesheet alternate="yes" media="pocketexplorer" href="somedata.xsl" type="text/xsl"?>
  #
  # ...and an HTTP request that contains a user-Agent value of...
  #    
  #   foo MSPIE bar
  #
  # ...will apply the XSL stylesheet somedata.xsl.
  #
  MSIE=explorer
  MSPIE=pocketexplorer
  HandHTTP=handweb
  Mozilla=netscape
  Lynx=lynx
  Opera=opera
  Java=java
  AvantGo=avantgo
  Nokia=nokia
  UP.Browser=up
  DoCoMo=imode
  
  
  
  1.1                  xml-xalan/java/samples/servlet/readme.html
  
  Index: readme.html
  ===================================================================
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  
  <html>
  <head>
  	<title>Xalan Samples</title>
  </head>
  <body>
  <h2>Xalan Samples</h2>
  <p>For information about the samples (what they illustrate and how to run them), see <a href="../../docs/samples.html">Samples</a>.</p>
  
  
  </body>
  </html>