Recipe14.10.Integrating Struts and XSLT


Recipe 14.10. Integrating Struts and XSLT

Problem

You want to use XSL transformations for HTML page generation instead of JSP pages in your Struts application.

Solution

Use the STXX framework with Struts.

Discussion

The Struts for Transforming XML with XSL (STXX) framework was developed by Don Brown. (The STXX project site can be found at http://stxx.sourceforge.net.) STXX fits into Struts in a manner similar to Velocity. Instead of forwarding requests to JSP pages, your action forwards to a special URL that is processed by the StxxRequestProcessor. Based on request data, this custom request processor reads a configuration file to determine the corresponding XSLT stylesheet. The request processor then uses an XSLT transformation engine to transform the received XML data, using the XSLT stylesheet, into XHTML.

XHTML is HTML that is well-formed, valid XML. XHTML is specified by the World Wide Web Consortium (W3C); details can be found at http://www.w3.org/MarkUp/.


To get started, download STXX from the project web site (http://stxx.sourceforge.net). This recipe was built using the full download of STXX Version 1.3. Extract the download to your system.

Copy the following JAR files to your application's WEB-INF/lib directory:

  • dist/stxx-1.3.jar

  • libs/core/jdom.jar

  • libs/xform/commons-jxpath-1.1.jar

  • libs/xform/xmlform.jar

The configuration of STXX is specified in the stxx.properties file. For this recipe, you can use this file without modification. From the STXX directory, copy source/web/WEB-INF/classes/stxx.properties to your application's WEB-INF/classes directory. STXX uses the concept of pipelines to chain transformations together. The stxx-pipelines.xml controls how the pipelines work. For this recipe, copy the source/web/WEB-INF/stxx-pipelines.xml file to your application's /WEB-INF directory.

As shown in Example 14-30, add an initialization parameter specifying the location of the stxx.properties file to the Struts ActionServlet declaration in your web.xml file.

Example 14-30. Adding STXX to your application's web.xml
<!DOCTYPE web-app   PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"   "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app>     <display-name>Struts Cookbook - Chapter 14 : STXX</display-name>        <!-- Standard Action Servlet Configuration (with debugging) -->     <servlet>         <servlet-name>action</servlet-name>         <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>         <init-param>             <param-name>config</param-name>             <param-value>/WEB-INF/struts-config.xml</param-value>         </init-param>         <init-param>             <param-name>stxxInit</param-name>             <param-value>/stxx.properties</param-value>         </init-param>         <load-on-startup>2</load-on-startup>     </servlet>     <!-- Standard Action Servlet Mapping -->     <servlet-mapping>         <servlet-name>action</servlet-name>         <url-pattern>*.do</url-pattern>     </servlet-mapping>     <!-- The Usual Welcome File List -->     <welcome-file-list>         <welcome-file>index.jsp</welcome-file>     </welcome-file-list> </web-app>

You configure the integration between Struts and STXX in your Struts configuration file. Example 14-31 shows the struts-config.xml used for this sample application.

Example 14-31. Integrating Struts and STXX in a Struts configuration file
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE struts-config PUBLIC           "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN"           "http://jakarta.apache.org/struts/dtds/struts-config_1_2.dtd"> <struts-config>     <form-beans>         <form-bean name="userForm" type="com.oroad.stxx.xform.JDOMForm"/>     </form-beans>     <global-exceptions>     </global-exceptions>     <global-forwards>     </global-forwards>     <action-mappings>         <action    path="/viewUserList"                   type="com.oreilly.strutsckbk.ch14.UserListAction">             <forward name="success" path="simple/viewUserList.dox"/>         </action>         <action    path="/addUser"                    name="userForm"                   scope="request"                 forward="simple/addUser.dox"         />         <action    path="/saveUser"                    type="com.oreilly.strutsckbk.ch14.SaveUserAction"                    name="userForm"                   scope="request">             <forward name="success" path="/viewUserList.do"/>         </action>     </action-mappings>     <message-resources parameter="ApplicationResources"      factory="com.oroad.stxx.util.PropertyMessageResourcesFactory"/>     <plug-in className="com.oreilly.strutsckbk.ch14.DataLoadPlugIn"/>                               <plug-in className="com.oroad.stxx.plugin.StxxPlugin" >         <set-property property="pipeline-config"                          value="/WEB-INF/stxx-pipelines.xml" />         <set-property property="xmlform-models"                          value="/WEB-INF/xmlform-models.xml" />         <set-property property="xmlform-schema"                          value="" />     </plug-in> </struts-config>

In a STXX application, your action form holds XML data. STXX provides two specialized classes that wrap XML data in an ActionForm. The contained XML can be represented as a traditional DOM object using the DOMForm or as a JDOM object using JDOMForm. JDOM provides a more natural API than DOM, so the JDOMForm was used in this recipe.

<form-bean name="userForm" type="com.oroad.stxx.xform.JDOMForm"/>

This form-bean element references an XML model that describes the XML structure of the form data. The XML models for your application are defined in the WEB-INF/xmlform-models.xml file. Example 14-32 shows the model, representing user information, used in this recipe.

Example 14-32. XML models used by STXX
<document>   <model name="userForm">     <user>       <name>           <firstname />           <lastname />       </name>       <email />     </user>       </model> </document>

A custom action in STXX performs the same functions as in a conventional Struts application: you retrieve data from the form, access the model, and forward to a destination. For STXX, the pattern can be specifically laid out as follows:

  1. Retrieve the ActionForm and extract the form data as a DOM or JDOM object.

  2. Access the business model to retrieve data.

  3. Format the data into an XML in-memory representation.

  4. Forward the request to a STXX transformation pipeline.

The actions defined in Example 14-31 represent a typical flow common to most web applications. The first action, /viewUserList, displays data on a page. The second action, /addUser, presents a form where a user can input data. The third action, /saveUser, saves the data in the model and forwards back to the first action.

Here's the first action mapping:

<action    path="/viewUserList"            type="com.oreilly.strutsckbk.ch14.UserListAction">     <forward name="success" path="simple/viewUserList.dox"/> </action>

The UserListAction, shown in Example 14-33, retrieves data stored in application-scope and builds a JDOM document from it. The action saves the document in the request and forwards to "success."

Example 14-33. Action that prepares an XML document
package com.oreilly.strutsckbk.ch14; import java.util.Iterator; import java.util.List; import com.oroad.stxx.action.Action; import javax.servlet.http.*; import org.jdom.*; import org.apache.struts.action.*; public class UserListAction extends Action {      public ActionForward execute(ActionMapping mapping,                                   ActionForm form,                                   HttpServletRequest request,                                   HttpServletResponse response)              throws Exception {            List usersList = (List) getServlet( ).getServletContext( ).                          getAttribute("users");                  //create a new XML document for this Action with the root          //element of "userList"          Document document =          new Document(new Element("userList"));            //add some data to the XML document so that the Action          //will produce XML in the form          Element users = new Element("users");                   for (Iterator k=usersList.iterator( ); k.hasNext( ); ) {             Element user = new Element("user");              Element name = new Element("name");             User u = (User) k.next( );             name.addContent(new Element("firstname").             setText(u.getFirstName( )));              name.addContent(new Element("lastname").             setText(u.getLastName( )));              user.addContent(name);             user.addContent(new Element("email").             setText(u.getEmail( )));              // add the user             users.addContent(user);                      }            // add to the root element and save the document         document.getRootElement( ).addContent(users);          saveDocument(request, document);            return mapping.findForward("success");      }  }

The success forward specifies a path of simple/viewUserList.dox. The forward is processed by STXX and matched against patterns in the stxx-pipelines.xml file. In this example, the matching pattern defines a simple XML to XHTML transformation using an XSL stylesheet:

<pipeline match="simple/*.dox">     <display-name>Simple XSLT</display-name>     <description>Performs simple XSLT transformations</description>     <transform type="html">         <param name="path" value="/xsl/{1}.xsl" />         <param name="render" value="server" />     </transform> </pipeline>

The first param element specifies the context-relative path to the XSL stylesheet. The value contains a substitution value retrieved from the wildcard-matched path.

If the {1} notation looks familiar, that's because it's the same wildcard-matching approach shown in Recipe 7.8. Wildcard mappings, as well as the STXX pipeline approach, originated in the Apache Cocoon project.


In this case, the transformation uses the xsl/viewUserList.xsl stylesheet shown in Example 14-34.

Example 14-34. XSL stylesheet that renders the user list
<xsl:stylesheet version="1.0"     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">          <xsl:output method="html" />     <xsl:template match="/">         <xsl:apply-templates select="stxx/userList"/>     </xsl:template>     <xsl:template match="userList">         <html>             <body>                 <table width="75%" border="1" align="center">                     <tr>                         <td bgcolor="lightblue" align="center">                             <a href="./xsl/viewUserList.xsl">View XSL</a>                            </td>                         <td bgcolor="lightblue" align="center">                             <a href="./index.jsp">                                 <xsl:value-of      select="/stxx/applicationResources/key[@name='link.index']"/>                             </a>                            </td>                         <td bgcolor="lightblue" align="center">                             <a href="./addUser.do">                                 <xsl:value-of      select="/stxx/applicationResources/key[@name='link.add.user']"/>                             </a>                            </td>                     </tr>                     <xsl:apply-templates select="users"/>                 </table>             </body>         </html>     </xsl:template>     <xsl:template match="users">         <tr bgcolor="lightgrey">             <td><b>First Name</b></td>             <td><b>Last Name</b></td>             <td><b>Email</b></td>         </tr>         <xsl:apply-templates select="user"/>     </xsl:template>          <xsl:template match="user">         <tr>             <td><xsl:value-of select="./name/firstname"/></td>             <td><xsl:value-of select="./name/lastname"/></td>             <td><xsl:value-of select="./email"/></td>         </tr>     </xsl:template> </xsl:stylesheet>

Figure 14-9 shows the page that gets displayed when you access the /viewUserList action.

Figure 14-9. STXX-generated HTML page


Clicking the "Add User" link sends a request to the /addUser action:

<action    path="/addUser"            name="userForm"           scope="request"         forward="simple/addUser.dox" />

STXX processes this request through the xsl/addUser.xsl stylesheet shown in Example 14-35.

Example 14-35. XSL stylesheet that generates an HTML form
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">     <xsl:output method="html" />     <xsl:template match="/">         <html>         <body>              <form action="saveUser.do">                 <table width="75%" border="1" align="center">                     <tr bgcolor="lightgrey">                         <td colspan="2"><b>Add User</b>                             <a href="./xsl/addUser.xsl"> (View XSL) </a>                         </td>                     </tr>                     <tr>                         <td><font color="red">*</font>First name:</td>                         <td>                             <input type="text" name="user/name/firstname"                                    value="{stxx/form/userForm/user/                                           name/firstname}"/>                         </td>                     </tr>                     <tr>                         <td><font color="red">*</font>Last name:</td>                         <td>                             <input type="text" name="user/name/lastname"                                    value="{stxx/form/userForm/user/                                           name/lastname}"/>                         </td>                     </tr>                     <tr>                         <td><font color="red">*</font>Email:</td>                         <td>                             <input type="text" name="user/email"                                    value="{stxx/form/userForm/user/email}"/>                         </td>                     </tr>                     <tr align="center">                         <td colspan="2">                             <input type="submit" value="Submit"/>                         </td>                     </tr>                 </table>             </form>         </body>         </html>     </xsl:template> </xsl:stylesheet>

Unlike a conventional Struts application, STXX doesn't use the Commons BeanUtils classes to populate the ActionForm. Instead, it treats the name attribute as an XPath expression into the XML form model specified for the action form.

Figure 14-10 shows the rendered form for adding a user.

Figure 14-10. STXX-generated HTML form


The /saveUser action receives and processes this form:

<action    path="/saveUser"            type="com.oreilly.strutsckbk.ch14.SaveUserAction"            name="userForm"           scope="request">     <forward name="success" path="/viewUserList.do"/> </action>

The SaveUserAction, shown in Example 14-36, extracts the data from the JDOM-backed form and updates the model stored in the servlet context.

Example 14-36. Action that retrieves XML data from an action form
package com.oreilly.strutsckbk.ch14; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import com.oroad.stxx.action.Action; import com.oroad.stxx.xform.JDOMForm; public class SaveUserAction extends Action {      public ActionForward execute(ActionMapping mapping,                                   ActionForm form,                                   HttpServletRequest request,                                   HttpServletResponse response)              throws Exception {          List usersList = (List) getServlet( ).getServletContext( ).                           getAttribute("users");         JDOMForm jdomForm = (JDOMForm) form;         String firstName = jdomForm.getValue("/user/name/firstname");         String lastName  = jdomForm.getValue("/user/name/lastname");         String email     = jdomForm.getValue("/user/email");         usersList.add(new User(firstName, lastName, email));         return mapping.findForward("success");      }  }

The sample application shown in this recipe represents a fraction of the capabilities of STXX. STXX supports validation, XForms, SOAP, FOP, and Velocity just to name a few. If you have a site that relies heavily on XML-based data, and needs to render that data in a number of formats, STXX may be what you need.

See Also

The STXX project web site (http://stxx.sourceforge.net) has complete details on the full functionality of STXX.

The StrutsCX project (http://it.cappuccinonet.com/strutscx) is another popular Struts-XSL integration framework.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

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