Model 2x架构概观 Model 2x是 Struts和XSLT结合的产物。Model 2x基在视图部分用XSLT和最后会被串行化成XML文件的Bean替代了原来Struts视图部分的JSP文件,但原封不动地保留Struts的Controller和Model部分。
XSLT定义 作为一种W3C的正式标准,XSLT是用来对XML文档进行转化的一种语言。它是XSL(可扩展样式表语言)的一部分。XPath是用作对XML文档各部分进行定位的语言。在XSL样式中,我们可以利用XPath表达式以一种紧凑而高效的形式选取XML文档的一部分进行处理。
XSL/FO也是XSL的规范的一部分,用来描述显示给读者的页面外观。XSL/FO主要的一个应用就是生成PDF文档。
XSLT和Struts的合成 把Struts和XSLT结合在一起的方法一是在JSP页面中执行XSLT转换。我们可以用标志库来实现这一功能,比如你可以使用Jakarta项目中的一个XSL标志库项目来实现。如果使用这种方式,那么在JSP页面中生成的是应该是XML而不是原来的HTML。借助XSLT样式表,XML转化成HTML或其他格式。然而这种方式需要对Struts本身加以修改。
生成HTML最通常的方式是由Struts的HTML标签库来生成,但这类标志库与XML并不兼容,也就不能和XSLT结合起来使用。当然可以对HTML标志库加以修改让其输出XHTML,这并不困难,但这就要修改现有的Struts 1.0 代码。
此外,这一解决方案需要在四个不同的地方开发:Action 类(控制器)、
模型Bean、JSP页面、XSLT样式表(视图)。JSP与标签库的作用也只限于把模式Bean转化成一个XML文档。
第二种方法就是我们提出的Model 2x。这种方法会自动执行这一任务,而且把JSP页面从我们的解决方案中删除了。图2向我们很好地展示了Model 2x
设计的核心构成。

图2
我们从图2中可以看出来,Model 2x处理流程的最初部分和Struts的类似。请求被发送到Struts的控制器,然后又被分派给各自的业务逻辑处理单元(Action类的子类)。控制器创建ActionForm对象。请求的参数都保存到这个ActionForm对象中。Action类的子类生成结果Bean(Result Bean),然后把这些Bean交给视图来显示。
Model 2x和Struts处理流程不同的地方在于:Model 2x中用一个XSL Servlet配合XSLT样式表实现了原来在Struts中由JSP实现的视图部分。这个XSL Servlet首先根据Bean和上下文环境生成XML文档,然后调用XSLT进行转换。接下来我们会详细地讲述这个过程。由于我们可以把一个请求提交给任何一个已经在Struts配置文件中注册的URL,所以在这个过程中不用对Struts做任何的修改。
XML文档的生成 把一个对象转换到一个Stream的过程我们称之为串行化。在
Java 1.1中引入了java.io.Serializable接口和相关的API。二进制串行化可以把一个Java对象转化到二进制流,在
网络上传输或是保存到文件中。相比之下,XML串行化是把一个Java对象树转化到文本型的XML流中。
许多开放源代码的
软件包,譬如Castor都可以用来执行XML串行化。在我们文章中提到的Model 2x案例中我们自行设计了一个简单的XML串行化方案。这个方案中假设Bean的所有属性是Java的基本类型或者java.util.Colleciton的子类。
这个方案会递归地对窗体Bean(Form Bean)、请求Bean(Request Bean)和Session bean进行自省,创建一个DOM树。同时,也串行化了资源和Struts配置数据也就是上下文环境信息。图3说明了这个过程

图3 XML/XSL 工作流程
XSLT处理 在这个Model 2x案例中,XSLT转换只限于样式表对XML流的转换。为了提高性能XSLServlet会对这个样式表进行了缓存处理。XML流着由Struts的处理流程生成。你可以通过提供连续转化或者使用更高级的配置来改进这个简单的架构。Cocoon中你就可以看到这两种方式的使用。Cocoon框架使用XML和XSLT构建服务器端的应用
程序。Cocoon基于管道(Pipeline)的架构使其能够更容易对内容和逻辑的加以分离、与大量不同的数据源交互也很方便。通过XSLT,Cocoon的输出可以与不同的设备兼容,比如HTML、WAP等等。
图3显示的是XSLT的处理流程。下面一节提供了一个将内容和版面设计分离的一个例子。
转化例子
TestForm是一个简单的窗体bean,它只有两个属性:
public class TestForm extends ActionForm { private String testString; private List testList; } |
假设testString的值为My Test String,testList的值为One、two、Three,XML串行化代码会生成一下XML片断。在XML文档中的元素名是可以预见的,这样编写样式表的时候会简单一些。
<page name="TestForm"> <request> <TestForm> <testString>My Test String</testString> <testList> <item>One</item> <item>Two</item> <item>Three</item> </testList> </TestForm> </request> </page> |
简单的XSLT模板把已经串行化的XML流转换到XHTML片断。
<xsl:template match="page"> <h2>Please enter some text and submit</h2> <br/> <form name="testForm" method="get" action="result"> <input type="text" name="testString" value="{request/TestForm/testString}"/> <br/> <select name="outSelect"> <xsl:for-each select="request/TestForm/testList/item"> <option><xsl:value-of select="."/></option> </xsl:for-each> </select> <br/> <input type="submit" value="Submit"/> </form> <hr/> </xsl:template> |
经过转化和HTML串行化,结果应该是如下
<h2>Please enter some text and submit</h2> <br> <form name="testForm" method="get" action="result"> <input type="text" name="testString" value="My Test String"> <br> <select name="outSelect"> <option>One</option> <option>Two</option> <option>Three</option> </select> <br> <input type="submit" value="Submit"> </form> <hr> |
