Elaborate

In this elaborate example, the scripts from the preceding Moderate examples will be enhanced for better Web site management. Obviously, much more elaborate examples can be devised, but this will serve as a good jumping off point.


Enhancing the Simple Scripts

Let's modify the simple scripts from the Moderate examples so that the XML and XSL file names do not need to be "hardcoded" for every page on the Web site. One way to do this is by using a parameter passed by a query string in the URL. (A query string is the part of the URL that follows a "?" such as "www.thexmltoolkit.org?name=index.") By using the "name" variable in the Request.QueryString statement, an unlimited number of XML and XSL files can be processed. For example, the home page URL would be "www.thexmltoolkit.org?name=index;" the About Us page would be "www.thexmltoolkit.org?name=about;" the Contact Us page would be www.thexmltoolkit.org?name=contact" and so on. Example scripts are given below for ASP (using VB Script), ASP.NET (using C#), PHP, JSP, Java Filters, Cold Fusion, and Cocoon.

				
ASP (Using VBScript) Example

<%@ Language=VBScript %>
<%
  Dim oXML, oXSL,strName
  strName=Request.QueryString("name")
  Set oXML = CreateObject("MSXML2.DOMDocument")
  oXML.load(Server.MapPath(strName & ".xml"))
  Set oXSL = CreateObject("MSXML2.DOMDocument")
  oXSL.load(Server.MapPath(strName & ".xsl"))
  Response.write oXML.transformNode(oXSL)
%>

----------------------------------------------------------------------------------------------------------------------------------------------


ASP.NET (Using C#) Example

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Xml.Xsl" %>
<%@ Import Namespace="System.Xml.XPath" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Text" %>

<script language="C#" runat="server">

/*This function is called every time when aspx page load */ 
public void Page_Load(Object sender, EventArgs E) 
{ 

string xmlPath;
string xslPath; 
string name = Request.QueryString["name"];

xmlPath = Server.MapPath(name + ".xml");
xslPath = Server.MapPath(name + ".xsl");

/* Read the XML file */
FileStream fs = new FileStream(xmlPath,FileMode.Open,FileAccess.Read);
StreamReader reader = new StreamReader(fs,Encoding.UTF8);
XmlTextReader xmlReader = new XmlTextReader(reader);

/* Instantiate the XPathDocument Class */
XPathDocument doc = new XPathDocument(xmlReader);

/* Instantiate the XslTransform Class */
XslTransform xslDoc = new XslTransform();
xslDoc.Load(xslPath);
xslDoc.Transform(doc,null,Response.Output);

/* Close Readers */
fs.Close();
reader.Close();
xmlReader.Close();
}

</script>

----------------------------------------------------------------------------------------------------------------------------------------------

PHP Example

<?php

/* Get the name parameter from the URL Query String */
$name = $_GET["name"];

/* load the xml file and stylesheet as dom documents */
$inputdom = new DomDocument();
$inputdom->load($name.".xml");
$xsl = new DomDocument();
$xsl->load($name.".xsl");

/* create the processor and import the stylesheet and set the parameters */
$proc = new XsltProcessor();
$xsl = $proc->importStylesheet($xsl);

/* transform and output the xml document */
$newdom = $proc->transformToDoc($inputdom);
print $newdom->saveXML();

?> 

----------------------------------------------------------------------------------------------------------------------------------------------

JSP Example

<%-- Must specify the jsp tag library -- xtags and make sure it has been installed correctly   --%>
<%@ taglib uri="http://jakarta.apache.org/taglibs/xtags-1.0" prefix="xtags" %>
<% String name = request.getParameter("name") ;%>
 <xtags:style  xml="<%= name + ".xml"  %>" xsl="<%= name + ".xsl"  %>"></xtags:style>
 
----------------------------------------------------------------------------------------------------------------------------------------------

Java Filter Example

import java.io.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public  class ManageXMLXSL implements Filter 
{

   private FilterConfig filterConfig = null;

   public void init(FilterConfig filterConfig) throws ServletException 
   {
      this.filterConfig = filterConfig;
   }

   public void destroy() 
   {
      this.filterConfig = null;
   }

   /*******************************************************************************************
     This doFilter method is the key function which do all the required work
   *******************************************************************************************/
   public void doFilter(ServletRequest request, 
          ServletResponse response, FilterChain chain)
           throws IOException, ServletException 
   {

     String contentType;
     contentType = "text/html";

	  /* Get the name parameter from the URL query string and attach it to the XML and XSL file strings */
     String styleSheet;
     String xmlData;
     String name = request.getParameter("name");
     xmlData = name + ".xml";
     stylesheet = name + ".xsl";
	       
     response.setContentType(contentType);

      /* set XSL style sheet */
     String stylePath =filterConfig.getServletContext().getRealPath(styleSheet);
     Source styleSource = new StreamSource(stylePath);

      /* set xml data source */
     String xmlPath =filterConfig.getServletContext().getRealPath(xmlData);
     Source xmlSource = new StreamSource(xmlPath);

     PrintWriter out = response.getWriter();

     chain.doFilter(request, response);

     /* Do the translation */
     try 
     {
      TransformerFactory transformerFactory =TransformerFactory.newInstance();
      Transformer transformer = transformerFactory.newTransformer(styleSource); 
      CharArrayWriter caw = new CharArrayWriter();
      StreamResult result  = new StreamResult(caw);
      transformer.transform(xmlSource, result);
      response.setContentLength(caw.toString().length());
      out.write(caw.toString());
     } 
     catch(Exception ex) 
     {
      out.println(ex.toString());
     }

  }  //End of doFilter

}  //End of class
 
  
----------------------------------------------------------------------------------------------------------------------------------------------

ColdFusion Example

 <!--- 
 ******************************************************************************************
* Declares the name parameter from the URL Query String and inserts it into path.filenmame
* for xml and xsl files then runs the XMLTransform function to load the XML and XSL files,
* and produce the HTML output					
* ******************************************************************************************
--->
<cfparam name="name" default="missing">
<cfset concatXML = "C:\CFusionMX7\wwwroot\" & name & ".xml">
<cffile action="read" file="#concatXML#" variable="mydoc">

<cfset concatXSL = "C:\CFusionMX7\wwwroot\" & name & ".xsl">
<cffile action="read" file="#concatXSL#" variable="xslDoc">

<cfset transformedXML = XmlTransform(mydoc, xslDoc)>
<cfoutput> #transformedXML# </cfoutput>
 
----------------------------------------------------------------------------------------------------------------------------------------------

Cocoon Example

 <!--- 
 ******************************************************************************************
* Retrieves the name parameter from the URL Query String and inserts it 
*  to load the XML and XSL files,
* and produce the HTML output					
* ******************************************************************************************
--->
<map:act type="request">
 <map:parameter name="parameters" value="true" />
 <map:generate src="{name}.xml" />
 <map:transform src="{name}.xsl" />
 <map:serialize /> 
</map:act>
 

			

While this is an improvement, it still has some drawbacks. It does not allow for the passing of parameters from the script to the XSL file, and it requires every XML file to have a unique XSL file to process it. (One of the great advantages of XML is that it can process many XML source files with one XSL file which streamlines Web site maintenace and enhances consistency.) One final improvement can address those issues.


Refining the Scripts Again

The revised examples below are similar to the previous scripts with some significant additions. First, they allow for more than one parameter to be included in the URL query string. Secondly, based on how many parameters are present in the query string (0, 1, or 2), they decide which of three XSL files will be used and pass parameters from the query string to the XSL file. The scripts check for a "name" parameter in the URL query string. If there is no name parameter, it assumes that the home page is wanted, so it loads the index.xml and index.xsl files as in the previous scripts. If there is a name parameter, then the script also checks for a sub parameter in the query string. It uses the name parameter to retrieve the appropriate XML file (similar to what was done in the previous script with the index, about, and contact pages) and it checks for the presence of the sub parameter to determine if it should use the "level1.xsl" or the "level2.xsl" file. So, rather than duplicating XSL files, this scripts can process all the HTML pages of the site with 3 XSL files, based on whether it's a home page, a level 1 page, or a level 2 page. The scripts also pass the query string parameters to the XSL file where they will be used to transform the XML in creating the HTML pages sent back to the browser. Again, scripts examples are provided for ASP (using VB Script), ASP.NET (using C#), PHP, JSP, Java Filters, Cold Fusion, and Cocoon.

				
				ASP (Using VBScript) Example

<%@ Language=VBScript %>
<% Response.Buffer=True %>
<%
 Dim oXML, oXSL,strName,xml,xsl,template,processor
 
  If Request.QueryString("name")="" Then
	 strName="index"
	Set oXML = CreateObject("MSXML2.DOMDocument")
	oXML.load(Server.MapPath(strName & ".xml"))
  	Set oXSL = CreateObject("MSXML2.DOMDocument")
	oXSL.load(Server.MapPath(strName & ".xsl"))
	Response.write oXML.transformNode(oXSL)
		
 Else
   param1 = Request.QueryString("name")
   param2 = Request.QueryString("sub")
   Set xml = Server.CreateObject("MSXML2.FreeThreadedDOMDocument.3.0")
   xml.async = false
   xml.load (Server.MapPath(param1 & ".xml"))
   
   Set xsl = Server.CreateObject("MSXML2.FreeThreadedDOMDocument.3.0")
   xsl.async = false
     
	If param2 = "" Then
   		xsl.load (Server.MapPath("level1.xsl"))
   	Else
   		xsl.load (Server.MapPath("level2.xsl"))
   	End If
   
  Set template = Server.CreateObject("MSXML2.XSLTemplate")
   template.stylesheet = xsl 
   set processor = template.createProcessor()
   processor.input = xml
      if param1 <> "" then
     processor.addParameter "name", param1
   end if
   if param2 <> "" then
     processor.addParameter "sub", param2 
   end if
 
   processor.transform()
   Response.write (processor.output)  
   
 End If
%>

----------------------------------------------------------------------------------------------------------------------------------------------


ASP.NET (Using C#) Example

<%@ Page Language="C#" %>

<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Xml.Xsl" %>
<%@ Import Namespace="System.Xml.XPath" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Text" %>

<script language="C#" runat="server">

/* This function is called every time when aspx page load */
public void Page_Load(Object sender, EventArgs E) 
{ 

string xmlPath;
string xslPath;
string param1 = Request.QueryString["name"];
string param2 = Request.QueryString["sub"];

XsltArgumentList args = new XsltArgumentList();

if(param1 == null)
{
  xmlPath = Server.MapPath("index.xml");
 xslPath = Server.MapPath("index.xsl");
 }
 else
 {
  if(param2 == null)
 {
 xmlPath = Server.MapPath(param1 + ".xml");
 xslPath = Server.MapPath("level1.xsl");
 args.AddParam("name","",param1);
 }
 else
 {
 xmlPath = Server.MapPath(param1 + ".xml");
 xslPath = Server.MapPath("level2.xsl");
 args.AddParam("name","",param1);
 args.AddParam("sub","",param2);
 }
}

/* Read the XML file */
FileStream fs = new FileStream(xmlPath,FileMode.Open,FileAccess.Read);
StreamReader reader = new StreamReader(fs,Encoding.UTF8);
XmlTextReader xmlReader = new XmlTextReader(reader);

/* Instantiate the XPathDocument Class */
XPathDocument doc = new XPathDocument(xmlReader);

/* Instantiate the XslTransform Class */
XslTransform xslDoc = new XslTransform();
xslDoc.Load(xslPath);
xslDoc.Transform(doc,args,Response.Output);

/* Close Readers */
fs.Close();
reader.Close();
xmlReader.Close();
}

</script>

----------------------------------------------------------------------------------------------------------------------------------------------

PHP Example

<?php

/******************************************************************************************
* Defines 2 parameters to pass to XSL files from the URL Query String.
* If there is no name parameter, it defines param1 as index
* it uses param1 to load  the appropriate xml file
* If there is no name parameter in the Query String it, it loads index.xsl 
* if there is a name parameter, but no sub parameters, it loads level1.xsl
* If there is a sub parameter, it loads level2.xsl  
******************************************************************************************/

$param1 = $_GET["name"];
$param2 = $_GET["sub"];

if ($param1=="")
{
 $param1="index";
}

/* load the xml file and stylesheet as dom documents */
$inputdom = new DomDocument();
$inputdom->load($param1.".xml");

$xsl = new DomDocument();
if ($param1=="index")
{
  $xsl->load("index.xsl");
}
else
{
 if ($param2!="")
 {
   $xsl->load("level2.xsl");
 }
 else 
 {
   $xsl->load("level1.xsl");
 }
}

/* create the processor and import the stylesheet and set the parameters */
$proc = new XsltProcessor();
$xsl = $proc->importStylesheet($xsl);

if($param1 !="")
{
  $proc->setParameter(null, "name", $param1);
}

if($param2 != "")
{
  $proc->setParameter(null, "sub", $param2); 
}

/* transform and output the xml document */
$newdom = $proc->transformToDoc($inputdom);
print $newdom->saveXML();

?> 

----------------------------------------------------------------------------------------------------------------------------------------------

JSP Example

<%-- Must specify the jsp tag library -- xtags and make sure it has been installed correctly   --%>
<%@ taglib uri="http://jakarta.apache.org/taglibs/xtags-1.0" prefix="xtags" %>
<%@ page import=" java.io.File" %>

<% String param1 = request.getParameter("name") ;%>
<% String param2 = request.getParameter("sub") ;%>

<%
   if ( param1 == null )
   {
%>
     <xtags:style  xml="index.xml" xsl="index.xsl">
     </xtags:style>
<%
   }
   else
   {
       if(param2 == null)
        {
 %>
         <xtags:style  xml="<%= param1 + ".xml"  %>" xsl="level1.xsl">
         <xtags:param name="param1" value="<%=param1 %>"/>
          </xtags:style>
<%
        }
       else
        {
 %>
         <xtags:style  xml="<%= param1 + ".xml"  %>" xsl="level2.xsl">
         <xtags:param name="param1" value="<%= param1 %>"/>
         <xtags:param name="param2" value="<%= param2 %>"/>
          </xtags:style>

<%
        }
   }
%>

----------------------------------------------------------------------------------------------------------------------------------------------

Java Filter Example

import java.io.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public  class ManageXMLXSL implements Filter
{

   private FilterConfig filterConfig = null;

   public void init(FilterConfig filterConfig) throws ServletException
   {
      this.filterConfig = filterConfig;
   }


   public void destroy()
   {
      this.filterConfig = null;
   }

   /*******************************************************************************************
     This doFilter method is the key function which do all the required work
   *******************************************************************************************/
   public void doFilter(ServletRequest request,
          ServletResponse response, FilterChain chain)
           throws IOException, ServletException
   {

     String contentType;
     contentType = "text/html";

     String styleSheet;
     String xmlData;

     name = request.getParameter("name") ;
     sub = request.getParameter("sub") ;

     /* According to requested link, and retrieve related xml data and xsl stysheet */
    if(name == null)
     {
       xmlData = "index.xml";
       styleSheet = "index.xsl";
     }
     else 
     { 
		   if(sub == null)
			 {
			  xmlData = name + ".xml";
			   styleSheet = "level1.xsl";
			 }
			 else
			 {
			  xmlData= name + ".xml";
			  styleSheet = "level2.xsl";
			 }
     }

     response.setContentType(contentType);

     /* set xml data source */
     String stylePath =filterConfig.getServletContext().getRealPath(styleSheet);
     Source styleSource = new StreamSource(stylePath);

     /* set XSL style sheet */
     String xmlPath =filterConfig.getServletContext().getRealPath(xmlData);
     Source xmlSource = new StreamSource(xmlPath);

     PrintWriter out = response.getWriter();

     chain.doFilter(request, response);

     /* Do the translation, using parameter and data path info */
     try 
     {
      TransformerFactory transformerFactory =TransformerFactory.newInstance();
      Transformer transformer = transformerFactory.newTransformer(styleSource);
      transformer.setParameter("name", name) ;
      transformer.setParameter("sub", sub ;
      CharArrayWriter caw = new CharArrayWriter();
      StreamResult result  = new StreamResult(caw);
      transformer.transform(xmlSource, result);
      response.setContentLength(caw.toString().length());
      out.write(caw.toString());
     } 
     catch(Exception ex)
     {
      out.println(ex.toString());
     }

  }  //End of doFilter

}  //End of class


----------------------------------------------------------------------------------------------------------------------------------------------

ColdFusion Example

<!---
*******************************************************************************************
* Declares the name and sub parameters which may be passed in the
* URL Query String and are used to control processing of XSL sheets
* ******************************************************************************************
--->
<CFPARAM NAME="name" DEFAULT="missing">
<CFPARAM NAME="sub" DEFAULT="missing">

<!---
*******************************************************************************************
* Determines if there is no name parameter in the user's URL;
* if so, it reads the index.xsml and index.xsl pages
*******************************************************************************************
--->
<cfif name is "missing">
	<cffile action="read" file="C:\CFusionMX7\wwwroot\index.xml" variable="mydoc">
	<cffile action="read" file="C:\CFusionMX7\wwwroot\index.xsl" variable="xslDoc">
<cfelse>
<!---
*******************************************************************************************
* If name is not missing, then it reads an xml file identified by the name parameter.
* If there is a sub parameter, it uses the level2.xsl file; if not, it uses level1.xsl
*******************************************************************************************
--->
<cfif sub is not "missing" and sub is not "">
	<cfset concatXML = "C:\CFusionMX7\wwwroot" & name & ".xml">
	<cffile action="read" file="#concatXML#" variable="mydoc">
	<cffile action="read" file="C:\CFusionMX7\wwwroot\level2.xsl" variable="xslDoc">
<cfelse>
	<cfset concatXML = "C:\CFusionMX7\wwwroot" & name & ".xml">
	<cffile action="read" file="#concatXML#" variable="mydoc">
	<cffile action="read" file="C:\CFusionMX7\wwwroot\level1.xsl" variable="xslDoc">
</cfif>

</cfif>

<!---
*******************************************************************************************
* Puts the parameters that will be used by the XSL files into a ColdFusion
* structure that can then be passed to the XSL files via the XmlTransform
* function
*******************************************************************************************
--->
<cfscript>
xslParams = StructNew();
StructInsert(xslParams, "sub", #sub#);
StructInsert(xslParams, "name", #sub#);
</cfscript>

<!---
*******************************************************************************************
* Runs the XMLTransform function to load the XML and XSL files, pass the
* appropriate parameters to the XSL, and produce the HTML output
*******************************************************************************************
--->
<cfset transformedXML = XmlTransform(mydoc, xslDoc, xslParams)>
<cfoutput> #transformedXML# </cfoutput>

----------------------------------------------------------------------------------------------------------------------------------------------

Cocoon Example

<!---
*******************************************************************************************
* Declares the name and sub parameters which may be passed in the
* URL Query String and are used to control processing of XSL sheets
* ******************************************************************************************
--->
<map:act type="request">
 <map:parameter name="parameters" value="true" />
 <map:generate src="{name}.xml" />
 <map:select type="request">
  <map:parameter name="parameter-name" value="sub"/>
   <map:when test="{sub}">
    <map:transform src="level2.xsl">
     <map:parameter name="use-request-parameters" value="true"/>
    </map:transform>
    <map:serialize type="html" />
   </map:when> 
   <map:otherwise>
    <map:transform src="level1.xsl">
     <map:parameter name="use-request-parameters" value="true"/>
    </map:transform>
    <map:serialize type="html" />
   </map:otherwise>
  </map:select>
</map:act>

		
			

The scripts above are very similar to the one used to power this Web site. However, this site's ASP script is enhanced even further to allow for simpler URL's that mirror the directory and file structure of the Web server more closely. It also minimizes the duplication of files even further and centralizes the Web site structure, navigation, and maintenance. Go to Inside this Site for an explanation and demonstration of this script.