XML Server Pages(XSP) 笔记
1、基本概念
XSP可以将动态数据添加到XML 文档中以创建更丰富的网站,也可以使 Cocoon 2 集成现有数据源和/或 API 以在因特网上用多种格式发布数据。它是一种能够创建动态 XML 数据源以便将数据传输到 Cocoon 2 管道的 Cocoon 2 技术。通过使用 XML 标记和应用逻辑的组合来描述这些数据源,然后由 Cocoon 2 引擎自动将这种组合编译为 Java 类。XSP 为使用 Cocoon 2 开发应用程序提供了一个灵活的平台。例如,Cocoon 2 应用程序可以显示现有应用程序数据库中的信息,而且启用了更为多样的数据发送选项。通过提供一种通过 XML 界面显示数据源的方法,XSP 允许在诸如中间件和文档发布那样的应用程序集成环境中使用 Cocoon 2。
1.1 XSP 与 JSP
1.1.1相同点:
1)由程序代码和标记的混合体组成
2)被编译成用于执行的二进制形式
3)允许创建定制标记库
1.1.2不同点:
1) XSP 为将任何编程语言中的代码与 XML 标记混合在一起提供了一个框架。
2) XSP 生成动态数据
XSP 生成动态数据,而不是动态表示。与之不同,JSP 则是一种通常用于在一系列处理步骤的最后阶段产生 HTML 或 XML 的表示层技术。XSP 页面为 Cocoon 管道生成 XML 数据,而由管道创建了所期望的表示。
1.2 XSP 编译过程
- 解析 XSP 文档
- 通过使用专用 XSLT 样式表转换 XSP 页面,以生成 Java 源代码
- 通过使用代码格式化器,在整齐地缩排和格式化源代码后,存储结果 Java 文件
- 将源代码编译成生成器
- 在请求管道中装入并执行已编译的生成器
1.3 一个XSP运行例子
Cocoon 2 提供了一个协调个别 XSP 页面的编译和执行的 ServerPagesGenerator
组件。在网站地图中,ServerPagesGenerator
声明如下:
<map:generators default="file">
<map:generator name="xsp" src="org.apache.cocoon.generation.ServerPagesGenerator"/>
<!-- ... other generator declarations ... -->
</map:generators>
要在管道中使用这个生成器,只须简单声明应当使用(而不是缺省值)并且指出在何处可以找到特定的 XSP 页面的源代码,如下所示:
<map:pipeline>
<map:match pattern="tutorial/*.xml">
<map:generate type="xsp" src="tutorial/{1}.xsp"/>
<map:serialize type="xml"/>
</map:match>
</map:pipeline>
2、语法
2.1 xsp:page 元素
xsp:page
元素是每个 XSP 文档的根元素。
<xsp:page language="java" xmlns:xsp="http://apache.org/xsp">
<!-- page contents -->
</xsp:page>
2.2 xsp:structure 和 xsp:include 元素
当添加利用标准或定制 Java API 的编程逻辑时,必须在 XSP 中指出生成的源代码中需要另外的 import 语句以确保编译成功地完成。xsp:structure
和 xsp:include
元素用于向代码生成过程提供这些附加提示。
<xsp:page language="java" xmlns:xsp="http://apache.org/xsp">
<xsp:structure>
<xsp:include>java.util.Calendar</xsp:include>
<xsp:include>java.text.*</xsp:include>
</xsp:structure>
<!-- page contents -->
</xsp:page>
2.3 xsp:logic 元素
xsp:logic
元素用于将 Java 代码块添加到 XSP。例如:
<xsp:page language="java" xmlns:xsp="http://apache.org/xsp">
<xsp:logic>
public String getTime()
{
return java.util.Calendar.getInstance().getTime().toString();
}
</xsp:logic>
<document/>
</xsp:page>
<xsp:page language="java" xmlns:xsp="http://apache.org/xsp">
<document>
<xsp:logic>
SimpleDateFormat format = new SimpleDateFormat("EEE, MMM d, yyyy");
String timestamp = format.format(
java.util.Calendar.getInstance().getTime()
);
</xsp:logic>
<time><xsp:expr>timestamp</xsp:expr></time>
<!-- additional elements -->
</document>
</xsp:page>
这个代码包含了对 XSP 文档求值时创建时间戳记的逻辑。然后通过使用 xsp:expr
,这个时间戳记被添加到了 time
元素内的文档中。
2.4 避免错误,保持良好的格式
2.4.1
程序代码与 XML 标记
把 if (a < b && c > d) { ... }改为①if (a < b && c >) { ... }或者②
<xsp:logic>
<![CDATA[
if (a < b && c > d) { ... }
]]>
</xsp:logic>
但是②
将忽略这些节内出现的任何 XSP 或用户元素,而将它们当作纯文本而不是 XML 标记进行处理,这样更可能导致隐蔽的、耗时的错误。
2.4.2
xsp:logic
元素内 XML格式规则
以下有错:
<search-results>
<xsp:logic>
if (firstResult())
{
<result id="first">
} else
{
<result>
}
<!-- ...result generation code here... -->
</result>
</xsp:logic>
</search-results>
应改为
<search-results>
<xsp:logic>
if (firstResult())
{
<result id="first">
<!--... handle first result..-->
</result>
} else
{
<result>
<!--...handle other results...-->
</result>
}
</xsp:logic>
</search-results>
2.5 xsp:expr 元素
xsp:expr
元素等价于在 JSP 中实现类似角色的<%= ... %>
表达式语法。
<elements>
<xsp:logic>
for (int i=1; i<11; i++)
{
<element><xsp:expr>i</xsp:expr></element>
}
</xsp:logic>
</elements>
2.6 通过使用 xsp:element 生成动态元素
通过使用 xsp:element
,还可以动态地创建元素,它的工作原理类似于其 XSLT 等价机制的工作原理。
<xsp:element>
<xsp:param name="name"><xsp:expr>"myElementName"</xsp:expr></xsp:param>
Element content
</xsp:element>
还可以与一个特定的名称空间和前缀关联
<xsp:element prefix="my" uri="http://www.examples.org">
<xsp:param name="name"><xsp:expr>"myElementName"</xsp:expr></xsp:param>
Element content
</xsp:element>
这个示例生成了以下 XML 输出:
<my:myElementName xmlns:my="http://www.examples.org">Element content</my:myElementName>
还可能动态地生成名称空间 URI 和前缀。无须添加 prefix
和 uri
属性,而是使用带适当名称的附加 xsp:param
元素。下列代码等价于上面的示例:
<xsp:element prefix="my" uri="http://www.examples.org">
<xsp:param name="name"><xsp:expr>"myElementName"</xsp:expr></xsp:param>
<xsp:param name="prefix">"my"</xsp:param>
<xsp:param name="uri">"http://www.examples.org"</xsp:param>
Element content
</xsp:element>
2.7 通过使用 xsp:attribute 生成动态属性
xsp:attribute
元素的工作原理类似于 xsp:element
,它允许动态创建属性的名称及其值:
<xsp:element>
<xsp:param name="name"><xsp:expr>"myElementName"</xsp:expr></xsp:param>
<xsp:attribute name="myAttribute">myAttributeValue</xsp:attribute>
Element content
</xsp:element>
这个属性的名称定义在 name
属性内,尽管是用与 xsp:element
类似的方法定义的,但它还能通过使用 xsp:param
子元素来定义。属性值被指定成元素内容。这可以是一个简单文本值或更有效地由 xsp:expr
元素生成。
2.8 创建注释和处理指令
2.8.1 创建注释:
<xsp:comment>This is a comment</xsp:comment>
然后这个注释变成:
<!-- This is a comment -->
2.8.2 创建处理指令类似于创建动态元素或属性:
<xsp:pi target="myApplication">
<xsp:expr>"param1=value, param2=value, generatorTimestamp=" +
System.currentTimeMillis()</xsp:expr>
</xsp:pi>
输出如下:
<?myApplication param1=value, param2=value, generatorTimestamp=1017407796870?>
还可以通过在 xsp:param
元素内创建处理指令的目标来自动生成它,如同以下示例演示的那样:
<xsp:pi>
<xsp:param name="target"><xsp:expr>"myApplication"</xsp:expr></xsp:param>
<xsp:expr>"param1=value, param2=value, generatorTimestamp=" +
System.currentTimeMillis()</xsp:expr>
</xsp:pi>
3 逻辑单
逻辑单是能被钩接入代码生成过程以允许创建定制标记库的 XSLT 转换。这些逻辑单使 XSP 页面更容易处理,从而减少了直接嵌入代码的需要。
3.1 使用逻辑单
每个逻辑单都与一个特殊的名称空间关联。使用逻辑单仅仅涉及在 XSP 文档中声明相应的名称空间,然后在需要的时候添加来自那个名称空间的元素。
<xsp:page language="java"
xmlns:xsp="http://apache.org/xsp"
xmlns:util="http://apache.org/xsp/util/2.0">
<clock>
<day><util:time format="EE"/></day>
<month><util:time format="MMMM"/></month>
<year><util:time format="yyyy"/></year>
<time><util:time format="HH:mm:ss 'on' dd/MM/yyyy"/></time>
</clock>
</xsp:page>
3.2内置逻辑单
3.2.1 环境逻辑单
在这个环境类别中有四个逻辑单,每个逻辑单都提供对与 Web 请求关联的处理环境的特殊方面的访问。这些逻辑单提供的功能类似于与 JSP 页面关联的隐式对象(例如,request
和 response
对象)提供的功能,并且是从 HTTP Servlet API 中直接提取的。
1) 请求(request)逻辑单
提供了对请求属性的访问,包括对请求参数、请求方法(例如,GET
、POST
等等)以及请求标题的访问。当请求参数的某些方面用于改变输出文档的生成时,这个逻辑单就格外有用。
2)响应(response)逻辑单
提供对与当前请求关联的 HTTP 响应的限制访问;它只提供对请求标题的访问。XSP 文档不能用与 Java Servlet 或 JSP 页面相同的方法执行包含或转发,因为分离问题是 Cocoon 2 体系结构的核心部分。这个功能描述在网站地图中;XSP 页面生成 XML 内容而不指导处理。
3)会话(session)逻辑单
提供了对 HTTP 会话信息的访问,包括创建和删除会话以及添加和除去会话属性的能力。很明显,这个功能在必须为上下文维护用户会话的 Web 应用程序中是最有用的。Cocoon 2 中的会话管理正好等价于它的 JSP 对手。
4)cookie 逻辑单
提供了 cookie 维护功能,诸如添加和除去 cookie、允许优先存储到用户的浏览器中。
3.2.2 实用程序逻辑单
1) 日志(log)逻辑单
<xsp:page language="java" xmlns:xsp="http://apache.org/xsp"
xmlns:util="http://apache.org/xsp/log
/2.0">
<log:debug>This is a debug message from an XSP generator</log:debug>
</xsp:page>
2)
发送邮件(sendmail) 逻辑单
<sendmail:send-mail from="[email protected]" to="[email protected]" smtphost="[email protected]">
<xsp:param name="subject"><xsp:expr>"The subject of this email..."</xsp:expr></xsp:param>
<xsp:param name="body"><xsp:expr>"The body of this email..."</xsp:expr></xsp:param>
</sendmail:send-mail>
3) 时间逻辑单
如前面的示例。
3.2.3 数据操作
1) 表单验证器(form validator)逻辑单
表单验证器(form validator)逻辑单从未真正单独使用。它向 Cocoon 表单验证器行为(Cocoon Form Validator Action)提供一个整齐的界面。这个行为能够对从 HTML 表单发送到 Cocoon 应用程序的数据执行基本验证操作,包括检查整数的最小和最大值、检查字符串的大小以及检查提供的某些参数。一个著名功能是能够测试传递的变量是否匹配给定的正则表达式。
2) esql 逻辑单
esql 逻辑单提供了执行这一步的方法,并提供了更多的功能,包括选择、删除和更新数据库。本质上,esql 逻辑单提供了将 SQL 语句直接嵌入到 XSP 文档的方法。然后这个逻辑单生成相应的 JDBC 代码来实现 SQL 操作,这样通过使用 Cocoon 2 简化了对数据库数据的操作和检索。
3.3 编写逻辑单
因为逻辑单转换可能以任何顺序发生,所以每个逻辑单都需要保留输入文档中它不理解的任何内容。换句话说,逻辑单的基本模板是恒等转换。这是一个将它的输入未做更改而直接简单复制到它的输出的转换。
<xsl:template match="time:time">
<xsp:logic>
SimpleDateFormat timeFormat = new SimpleDateFormat("<xsl:value-of select="@format"/>");
</xsp:logic>
<xsp:expr>
timeFormat.format(java.util.Calendar.getInstance().getTime())
</xsp:expr>
</xsl:template>
该单一模板与 time
元素匹配,并用封装在 xsp:logic
和 xsp:expr
元素中的代码来替代它们以创建日期。所需的日期格式由用户通过这个元素上的 format
属性来说明。
3.4 配置逻辑单
在该配置文件中搜索 xsp-language
元素,并注意它包含一个名为 target-language
的子元素。应声明这个元素内的所有逻辑单。还可能看到已预先定义了内置逻辑单。这里是 util 逻辑单的项:
<builtin-logicsheet>
<parameter name="prefix" value="util"/>
<parameter name="uri" value="http://apache.org/xsp/util/2.0"/>
<parameter name="href" value="resource://org/apache/cocoon/components/language/markup/xsp/java/util.xsl"/>
</builtin-logicsheet>
另例如:
<!--*************** Test By David *************** -->
<builtin-logicsheet>
<parameter name="prefix" value="xsp-time"/>
<parameter name="uri" value="$CATALINA_HOME/webapps/cocoon/WEB-INF/classes/logicsheets/time.xsl"/>
<parameter name="href" value="resource://logicsheets/time.xsl"/>
</builtin-logicsheet>
3.5 逻辑单的开发技巧
3.5.1 使用助手类:
虽然创建逻辑单将从 XSP 页面中提取出程序代码,但这个代码仍被锁藏在 XSLT 样式表中。这使不依赖 Cocoon 而要维护和测试代码很困难。一个好的设计技巧是将尽可能多的代码放入助手类中。这样使得逻辑单的实现简化为只是收集参数,然后调用所需的助手方法。内置逻辑单遵循这个指南,并且每个逻辑单都有单个助手类。
3.5.2 创建逻辑单“宏”:
宏是记录和重新执行一系列操作的一个简单快速的方法。在特殊应用程序中的 XSP 页面可能要重复创建相同的 XML 结构或用同样的方法调用其它逻辑单。提取出 XSP 页面中的公共块,以创建描述这个重复结构的较高级别元素(例如,宏)是很有用的。因为 Cocoon 2 递归地应用逻辑单,直到处理完所有名称空间为止,一个逻辑单的实现可以添加另一个逻辑单上的元素。这种组合可以大大降低 XSP 页面的复杂程度。
3.5.3 考虑用户:
当考虑在逻辑单中提供什么样的标记时,请考虑最终用户。他们需要怎样的灵活性?例如,可以将什么样的参数发送给标记?只能通过属性或嵌套的 xsp:param
元素发送参数吗?后者更加灵活,因为它允许用户通过使用 xsp:expr
动态地创建参数值,而 xsp:expr
不能在属性内使用。还要考虑如何命名标记。赋予它一个清晰和好记的名称,这样它所做的就显而易见了。并不是每个人都乐意深入研究逻辑单的实现来感受这一点的。这个建议的一个很明显扩展是向逻辑单提供支持文档;这使用户能快速找到标记的含义以及如何使用它。