Web应用程序的标志是多个子系统的集成。SQL和XML是在这类子系统之间交换数据的两种最通用的机制。在本文中,Mark Kolb介绍访问JSP页面数据库和XML内容的sql和xml库并对JSTL进行了总结。
Web应用程序的模板式(stereotypical)架构分为三层:处理请求的Web服务器、实施业务逻辑的应用程序服务器以及管理永久性数据的数据库。应用程序和数据库层之间的联接通常采用关系数据库中的SQL调用格式。当业务逻辑被写入到Java语言中时,JDBC用于实现这些调用。
如果应用程序调用与其它服务器(本地或远程)的集成,我们将需要用于在不同子系统之间交换数据的更深层次的机制。在Web应用程序内部和应用程序之间传送数据采用的越来越普遍的一种方法是XML文件的交换。
迄今为止,在我们的JSTL之旅中,我们讨论了JSTL 表达式语言(expression language,EL)和core和fmt标记库。在最后一部分,我们将考虑sql和xml库--正如它们的名字表示的一样 -- 提供定制标记来接入和管理从SQL数据库和XML文件检索到的数据。
xml库
根据设计,XML提供灵活的方式来表示结构化数据,这些数据同时准备进行验证,因此它尤其适应于在松散联合的系统之间交换数据。这反过来使其成为Web应用程序极具吸引力的集成技术。
与使用XML表示的数据进行交互的第一步是把数据作为一个XML文件,对其进行检索并进行分解,以创建数据结构来接入该文件中的内容。在分解文件后,您可以有选择的对其进行转换以创建新的XML文件,您可以对新的XML文件进行相同的操作。最终,文件中的数据可以被提取,然后显示或使用作为输入数据来运行其它操作。
这些步骤都在用于控制XML的JSTL标记中反映出。根据我们在第2部分探讨核心中所讨论的,我们使用core库中的<c:import标记来检索XML文件。然后使用<x:parse标记来分解该文件,支持标准的XML分解技术,如文件对象模式(Document Object Model,DOM)和简单XML API(Simple API for XML,SAX)。<x:transform标记可用于转换XML文件并依赖标准技术来转换XML数据:扩展样式表语言(Extensible Stylesheet Language,XSL)。最后,我们提供多个标记来接入和控制分解后的XML数据,但是所有这一切都依赖于另一种标准-XML路径语言(XML Path Language,XPath),以引用分解后的XML文件中的内容。
分解XML
<x:parse标记有多种格式,取决于用户希望的分解类型。这一项操作最基本的格式使用以下语法:
<x:parse xml="expression" var="name" scope="scope"
filter="expression" systemId="expression"/
在这五种属性中,只有xml属性是需要的,其值应该是包含要分解的XML文件的字符串,或者是java.io.Reader实例,通过它可以读取要被分解的文件。此外,您可以使用以下语法,根据<x:parse标记的主体内容来规定要被分解的文件:
<x:parse var="name" scope="scope"
filter="expression" systemId="expression"
body content
</x:parse
var和scope属性规定存储分解后的文件的scoped变量。然后xml库中的其它标记可以使用这一变量来运行其它操作。注意,当var和 scope 属性存在时,JSTL用于表示分解后的文件的数据结构类型以实施为导向,从而厂商可以对其进行优化。
如果应用程序需要对JSTL提供的分解后的文件进行处理,它可以使用另一种格式的<x:parse,它要求分解后的文件坚持使用一个标准接口。在这种情况下,该标记的语法如下:
<x:parse xml="expression" varDom="name" scopeDom="scope"
filter="expression" systemId="expression"/
当您使用<x:parse的这一版本时,表示分解后的XML文件的对象必须使用org.w3c.dom.Document接口。当根据<x:parse中的主体内容来规定XML文件时,您还可以使用varDom和scopeDom属性来代替var 和 scope属性,语法如下:
<x:parse varDom="name" scopeDom="scope"
filter="expression" systemId="expression"
body content
</x:parse
其它两个属性filter 和 systemId 可以实现对分解流程的精确控制。filter 属性规定org.xml.sax.XMLFilter类的一个实例,以在分解之前对文件进行过滤。如果要被分解的文件非常大,但目前的工作只需要处理一小部分内容时这一属性尤其有用。systemId属性表示要被分解的文件的URI并解析文件中出现的任何相关的路径。当被分解的XML文件使用相关的URL来引用分解流程中需要接入的其它文件或资源时需要这种属性
清单1展示了<x:parse 标记的使用,包括与 <c:import的交互。此处<c:import 标记用于检索众所周知的Slashdot Web 网站的RDF Site Summary (RSS)反馈,然后使用<x:parse分解表示RSS 反馈的XML文件,表示分解后的文件的以实施为导向的数据结构被保存到名为rss的变量(带有page 范围)中。
清单1:<x:parse与<c:import的交互
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/
<x:parse var="rss" xml="${rssFeed}"/
转换XML
XML通过XSL样式表来转换。JSTL使用<x:transform标记来支持这一操作。与<x:parse的情况一样,<x:transform 标记支持多种不同的格式。<x:transform 最基本的格式的语法是:
<x:transform xml="expression" xslt="expression"
var="name" scope="scope"
xmlSystemId="expression" xsltSystemId="expression"
<x:param name="expression" value="expression"/
...
</x:transform
此处,xml 属性规定要被转换的文件,xslt 属性规定定义这次转换的样式表。这两种属性是必要的,其它属性为可选。
与<x:parse的xml属性一样,<x:transform的xml 属性值可以是包含XML文件的字符串,或者是接入这类文件的Reader。此外,它还可以采用 org.w3c.dom.Document 类或javax.xml.transform.Source 类的实例格式。最后,它还可以是使用<x:parse 操作的var或varDom属性分配的变量值。
而且,您可以根据<x:transform 操作的主体内容来包含要被转换的XML文件。在这种情况下,<x:transform 的语法是:
<x:transform xslt="expression"
var="name" scope="scope"
xmlSystemId="expression" xsltSystemId="expression"
body content
<x:param name="expression" value="expression"/
...
</x:transform
在这两种情况下,规定XSL 样式表的xslt 属性应是字符串、Reader或javax.xml.transform.Source实例。
如果var 属性存在,转换后的XML文件将分配给相应的scoped变量,作为org.w3c.dom.Document 类的一个实例。通常,scope属性规定这类变量分配的范围。
<x:transform 标记还支持将转换结果存储到javax.xml.transform.Result 类的一个实例中,而不是作为org.w3c.dom.Document的一个实例。如果var 和 scope 属性被省略,result对象规定作为result属性的值,<x:transform标记将使用该对象来保存应用该样式表的结果。清单2中介绍了使用<x:transform 的result属性的这两种语法的变化:
清单2:使用result属性来提供javax.xml.transform.Result实例时,<x:transform操作的语法变化
<x:transform xml="expression" xslt="expression"
result="expression"
xmlSystemId="expression" xsltSystemId="expression"
<x:param name="expression" value="expression"/
...
</x:transform
<x:transform xslt="expression"
result="expression"
xmlSystemId="expression" xsltSystemId="expression"
body content
<x:param name="expression" value="expression"/
...
</x:transform
无论您采用这两种<x:transform格式中的那一种,您都必须从定制标记单独创建javax.xml.transform.Result对象。该对象自身作为result属性的值提供。
如果既不存在var 属性,也不存在result属性,转换的结果将简单地插入到JSP页面,作为处理<x:transform 操作的结果。当样式表用于将数据从XML转换成HTML时尤其有用,如清单3所示:
清单3:在JSP页面直接显示转换的XML数据
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/
<c:import var="rssToHtml" url="/WEB-INF/xslt/rss2html.xsl"/
<x:transform xml="${rssFeed}" xslt="${rssToHtml}"/
在本例中,使用 <c:import 标记来读取RSS反馈和适当的样式表。样式表的输出结果是HTML,通过忽略<x:transform的var和result 属性来直接显示。图1显示了实例结果:
图1:清单3的输出结果
与<x:parse的systemId 属性一样,<x:transform的xmlSystemId 和 xsltSystemId 属性用于解析XML文件中相关的路径。在这种情况下,xmlSystemId 属性应用于根据标记的 xml属性值提供的文件,而xsltSystemId 属性用于解析根