级别: 初级 Pramod Kankure (pkankure@yahoo.com), 软件工程师
2001 年 4 月 01 日 本文讨论了通过将用户请求参数从 Java后端程序发送到用于形成 Web 页面的 XSLT 样式表来用 Java 和 XSLT生成动态 Web 页面的两种方法。样本代码演示 了如何使用
XSLTProcessor 方法和定制方法,以及如何在 XPath表达式中使用全局参数。
在 XML
之前,开发人员必须用一些服务器方脚本技术(如 CGI、Java 小服务程序或
JSP)来生成动态 Web 页面。 在 XML 以前的模型中,内置的 API
使得可以使用用户请求参数;然后服务器方脚本生成动态内容并将其内容返还回浏览器。
对于需要实时访问存储在数据库中数据的应用程序,这仍可能是最佳编程模型。
在所有其它情况下,我认为逐渐发展起来的使用 XML
技术的新模型在动态生成 Web 页面的方面代替服务器方脚本。
在这种新模型中,根据存储在数据库中的数据定期创建 XML
文档。 然后,直接将 XML 文档提供给客户机。对于 Web
浏览器客户机,经由XSLT 样式表将 XML 变换为
XHTML。到目前为止,一切顺利。当必须仅使用一种样式表创建基于用户输入的各种
XHTML
页面时,事情会变得十分有趣。这里向您演示如何实现这一技术。
应用体系结构
设想有一个 XML
文档,它包含组织进行商务活动所在的所有国家或地区的销售联系信息。
每个晚上,通过提取后端数据库中的信息来批处理创建文档。 在 Web
站点上,根据每个用户选择的国家或地区来显示定制内容。
这可以通过编写服务器方 Java 程序 -- 小服务程序 --
在用户选择国家或地区后调用该程序来实现此任务。
然后,小服务程序以二进制流方式读取 XSLT
样式表,并将所选国家的值发送到样式表。 XSLT
样式表将它作为全局参数接受。然后,小服务程序将 XML
文档作为另一个二进制流读取。 它将这两个流发送到
XSLTProcessor 类的实例, 该实例依次对 XML
文档进行分析,以创建特定于国家或地区的 XHTML。 图 1
显示了该应用体系结构。
图 1.
使用小服务程序显示包含 XML 文档的 Web 页面的体系结构
这个解决方案是很容易移植的。XML
文档可以驻留在任何类型的服务器上。 另外,Java
允许平台的独立性,并且小服务程序本身可以在任何应用程序服务器上运行。
唯一的条件是 Java 程序必须能够经由 HTTP 协议与包含 XML
文档的服务器对话。
将参数发送到样式表有两种方法:使用
XSLTProcessor 方法,或使用定制方法。这里描述了这两种方法并做简要的比较
方法 1:使用 XSLTProcessor 方法发送参数
如果要将全局参数发送到 XSLT 样式表,可以使用
XSLTProcessor 类提供的
setStylesheetParam
方法,如清单 1 中所示。
清单 1. XSLTProcessor
方法
XSLTProcessor processor =XSLTProcessorFactory.getProcessor();
processor.setStylesheetParam("cntry","\""+styleParam+"\"");
//xmlSource --- XML Document Binary Stream
//xslSource --- XSLT Style sheet Binary Stream
//htmlOutPut --- Instance of class that represents the response to
// browser e.g. PrintWriter
processor.process(xmlSource, xslSource,
htmlOutput);
|
程序创建
XSLTProcessor 类的实例,然后对该实例使用
setStyleSheetParam
方法。如果已经将参数的值存储在变量中,
则必须在该变量的前后加引号,如
清单 1
中所示。
XSLTProcessor 类的处理方法使用
xmlSource 和
xslSource
这两个流来生成动态的 XHTML 页面。
方法 2:使用定制方法发送参数
也可以通过编写定制方法来设置样式表中的参数, 如
清单 2 所示。 在将 XML
文档和 XSLT 样式表流发送到
XSLTProcessor 类实例之前,
调用
清单 2
中的方法。
比较这两种方法
在这个示例中,定制方法的运行速度要比
XSLTProcessor
类方法的运行速度快许多。 例如,在 Notes Domino
服务器上,定制方法只需所提供方法的一半时间。 然而,如果 W3C
更改了全局参数的标准,则需要在 Web
站点上所有使用该定制方法的地方修改它。
访问 XSLT
样式表内部的全局参数
全局参数在样式表的顶部指定,如
清单 3 中所示。 代码将
cntry
参数的缺省值设置为 "United
States"。小服务程序将使用用户选择的值重新设置它。
在 XPath
表达式中使用全局参数
XSLT 不是类似于 Java 那样的 3GL 语言。 对于那些不熟悉 XSLT
语言特征的 Java 程序员或其它程序员, 调试 XSLT
内部的问题是相当具有挑战性的。我希望下列建议可以为您节省许多因受挫而浪费的时间!考虑清单
4 中所示的 XML 文档。
清单 4.
简化成仅包含一个国家或地区的数据的样本 XML 文档
<page>
<countrylist>
<country isocode="US" name="United States">
--- more country details would appear here ---
</country>
--- other countries ---
</countrylist>
</page>
|
现在,如果
isocode 作为参数发送到样式表并且您想要获得相关国家或地区的名称,则可以写为:
<xsl:value-ofselect="/page/countrylist/country[@isocode=$cntry]/name"> |
然而,当如上所示在 XPath
表达式中使用全局参数时,会产生错误的结果。
但可以通过使用循环逻辑来避免这一难点,如清单 5 中所示。
清单 5. 循环逻辑以避免
XPath 表达式中的问题
<xsl:for-each select="/page/countrylist/country">
<xsl:variable name="tempVar">
<xsl:value-of select=
"./@isocode"/> </xsl:variable><xsl:iftest="$tempVar=$cntry">
<xsl:value-of select="./@name"/>
</xsl:if>
</xsl:for-each>
|
该代码循环
country 节点的所有子节点。
对于每个节点,将
isocode
属性的值存储在一个变量中。然后,代码将该变量与接收到的全局参数进行比较。
只要发现匹配,它就抽取
name 属性的值。
参考资料
关于作者  | 
|  |
Pramod Kankure
是居住于纽约的一位顾问,他广泛地专注于 Java、XML、WebSphere 和
Lotus Domino。 他曾经向几家公司(包括 IBM、Citi Group、Ernst &
Young 和 GE Capital)提供过咨询服务。可通过
pkankure@yahoo.com
与他联系。
|
对本文的评价
|