JavaServer Pages标准标签库简介

  JavaServer Pages标准标签库(JSTL)封装了许多JSP应用程序共有的核心功能。例如,不需要用脚本或者众多不同厂商的不同迭代器标签对列表进行迭代,JSTL定义了在所有地方都可以使用的标准标签。这种标准化使您可以学习一种标签后,在多个JSP容器中使用它。而且,当标签标准化以后,容器可以优化对它们的实现。
JSTL支持通用的、结构化的任务,如迭代和条件、操作XML文档的标签、国际化标签以及以及用SQL访问数据库的标签。它还引入了表达式语言的概念以简化页面的开发。JSTL还提供了集成现有标签库与JSTL的框架。

本章通过在前面几章讨论的Duke's Bookstore应用程序的JSP版本的内容展示JSTL。假定您已经熟悉了第16章中的使用标签中的内容。

JSP页面示例

本章通过如下重新编写JSP版本的、在第16章讨论过的Duke's Bookstore应用程序的内容来展示JSTL

·  JSTL核心标签替换Struts逻辑标签。

·  用消息格式标签替换访问消息储存的scriptlet

·  用通过JSTL SQL标签对数据库的直接调用替换JavaBean组件数据库helper。对于大多数应用程序来说,最好将对数据库的调用封装到bean中。JSTL包含SQL标签,在创建已有原型的应用程序并有可能减少创建bean的开销的情况下可以使用这个标签。

Duke's Bookstore应用程序的源代码在解开教程压缩包时创建的<JWSDP_HOME>/docs/tutorial/examples/web/bookstore4目录中(运行示例)

要编译、安装和运行这个例子:

1.     在终端窗口,进入 <JWSDP_HOME>/docs/tutorial/examples/web/bookstore4.

2.     运行ant buildBuild目标会进行所有需要的编译并将文件拷贝到<JWSDP_HOME>/docs/tutorial/examples/web/bookstore4/build 目录中。

3.     确保已经启动Tomcat

4.     运行ant installinstall目标通知Tomcat新的内容已经可用。

5.     如果还没有做的话,启动PointBase数据库服务器并填入数据 (Web应用程序访问数据库)

6.     打开书店URL http://localhost:8080/bookstore4/enter.

有关诊断常问题的帮助见常见问题及其解决方法故障排除

使用JSTL

JSTL包括很多种不同的标签,可应用到不同功能的领域中。因此,通过多个标签库描述符(TLD)明确表明它所覆盖的功能领域,并给每一领域它自己的命名空间。17-1总结了这些功能领域,以及在本章和Duke's Bookstore应用程序中使用的逻辑TLD名和前缀。

17-1 JSTL 标签 

领域

功能

标签

TLD

前缀

核心

支持表达式语言

catch

out

remove

set

/jstl-c

c

流程控制

choose

  when

  otherwise

forEach

forTokens

if

URL管理

import

  param
redirect

  param

url

  param

XML

核心

out

parse

set

/jstl-x

x

流程控制

choose
  when
  otherwise

forEach

if

转换

transform

  param

I18n

区域

setLocale

/jstl-fmt

fmt

编排消息格式

bundle

message

  param

setBundle

编排数字和日期格式

formatNumber

formatDate

parseDate

parseNumber

setTimeZone

timeZone

数据库

setDataSource

/jstl-sql

sql

SQL

query

  dateParam

  param

transaction

update
  dateParam

  param

例如,要在JSP页面中使用JSTL核心标签,用引用TLDtaglib指令声明库:

<%@ taglib uri="/jstl-core" prefix="c" %>

JSTL标签库有两种版本(孪生库)JSTL-EL库的TLD命名为prefix.tldJSTL-RT库的TLD命名为prefix-rt.tld。由于在本章讨论的例子使用逻辑TLD名,所以我们用Web应用部署描述符中的taglib元素将逻辑名映射为实际TLD位置。下面是将核心库逻辑TLD/jstl-c映射到其位置/WEB-INF/c.tld的项:

<taglib>
 <taglib-uri>/jstl-c</taglib-uri>
 <taglib-location>/WEB-INF/c.tld</taglib-location>
</taglib>

Java WSDP中,JSTL TLD储存在<JWSDP_HOME>/jstl-1.0.3/tld中。在构建Duke's Bookstore应用程序时,这些TLD自动拷贝到<JWSDP_HOME>/docs/tutorial/examples/web/bookstore4/build/WEB-INF中。

还可以在taglib指令中用绝对URI引用TLD

·  核心: http://java.sun.com/jstl/core

·  XML http://java.sun.com/jstl/xml

·  国际化: http://java.sun.com/jstl/fmt

·  SQL http://java.sun.com/jstl/sql

在使用绝对URI时,不必在web.xml中添加taglib元素,JSP容器会自动定位在JSTL库实现中的TLD

除了声明标签库,还需要使JSTL API及其实现对于Web应用程序是可用的。它们是以<JWSDP_HOME>/jstl-1.0.3中的jstl.jar<JWSDP_HOME>/jstl-1.0.3/standard中的standard.jar文档形式发布的。在构建Duke's Bookstore应用程序时,这些库会自动拷贝到<JWSDP_HOME>/docs/tutorial/examples/web/bookstore4/build/WEB-INF/lib中。

表达式语言支持

JSTL的一个重要功能就是对表达式语言(EL)的支持。表达式语言结合JSTL标签,使得访问应用程序数据和以简单方式操纵它变得容易了,不需要使用scriptlet或者请求时表达式。当前,页面编写者必须使用表达式<%= aName %>访问系统的值或者用户定义的JavaBean组件。如:

<x:aTag att="<%= pageContext.getAttribute("aName") %>">  

对于嵌入式bean属性就更复杂了:

<%= aName.getFoo().getBar() %>

这使得页面的编写比它需要的更复杂。

表达式语言使页面编写者可以用简单的语法访问对象,如对于简单的变量

<x:atag att="${aName}">  

或者对于嵌入的属性

<x:aTag att="${aName.foo.bar}">  

JSTL表达式语言将JSP scoped 属性提升为业务逻辑与JSP页面交换信息的标准方式。例如,为这个条件标签的test属性提供一个比较名为cart的会话作用域属性中的项目数是否为0的表达式:

<c:if test="${sessionScope.cart.numberOfItems > 0}">   ... </c:if>

JSP规范的下一个版本将会对所有自定义标签库的表达式语言进行标准化。这一版本的JSTL包括这一表达式语言的一个快照。

孪生库

JSTL标签库有两个版本,它们只是在对属性值使用运行时表达式的方式上有所不同。

JSTL-RT标签库,表达式是在页面的脚本语言中指定的。这正是当前标签库的工作方式。

JSTL-EL标签库中,表达式是在JSTL表达式语言中指定的。表达式是以EL的语法所写的一个String文字。

在使用EL标签库时,不能为一个属性的值传递脚本语言表达式。这个规则使它可以在转换时验证表达式的语法。

JSTL 表达式语言

JSTL表达式语言负责处理表达式和文字。表达式由${ }字符所包围。例如:

<c:if test="${bean1.a < 3}" />

所有不以${开始的值都认为是文字,用所预期的类型的PropertyEditor将文字解析为预期类型:

<c:if test="true" />

包含字符的文字值必须进行如下转义:

<mytags:example attr1="an expression is ${'${'}true}" />

属性

可以通过名称访问属性,也可以加上作用域。属性的属性是用.操作符访问的,并可任意嵌套。

EL统一了对.[ ]操作符的处理。因此,expr-a.expr-b等于expr-a[expr-b]。要判断expr-a[expr-b],需将expr-avalue-a判断,将expr-bvalue-b判断。

·  如果value-a是一个Map,返回value-a.get(value-b)

·  如果value-a是一个List或者数组,强制value-bint并相应并返回value-a.get(value-b)或者Array.get(value-a, value-b)

·  如果value-aJavaBean对象,强制value-bString。如果value-bvalue-a的可读属性,则返回getter调用的结果。

EL通过将标识作为属性查询、根据PageContext.findAttribute(String)的行为对标识进行判断。例如,${product}会查询名为product的属性,搜索页面、请求、会话和应用程序作用域,并返回其值。如果没有找到属性,则返回null。注意与一个在下面一节中描述的隐式对象相匹配的标识会返回该隐式对象而不是属性值。

隐式对象

JSTL 表达式语言定义了一组隐式对象:

·  pageContext PageContext对象

·  pageScope :一个Map,它将页面作用域属性名映射为它们的值

·  requestScope:一个Map,它将请求作用域的属性名映射为它们的值

·  sessionScope :一个Map,它将会话作用域的属性名映射为它们的值

·  applicationScope:一个Map,它将应用程序作用域的属性值映射为它们的值

·  param:一个Map,它将参数名映射为单个String参数值(通过调用ServletRequest.getParameter(String))

·  paramValues一个Map,它将参数名映射为该参数的所有值的String[ ] (通过调用获得ServletRequest.getParameterValues(String) 获得)

·  header :一个Map,它将头名映射到单个String头值(通过调用ServletRequest.getheader(String)获得)

·  headerValues一个Map,它将头名映射到该参数的所有值的String[ ] (通过调用ServletRequest.getHeaders(String) 获得)

·  cookie一个Map,它将cookie名映射为单个Cookie (通过调用HttpServletRequest.getCookie(String) 获得)

·  initParam 一个Map,它将参数名映射到单个String (通过调用ServletRequest.getInitParameter(String) 获得)

当表达式通过名字引用其中一个对象时,返回的是相应的对象而不是相应的属性。例如:${pageContext}返回PageContext对象,即使有一个现有的包含一些其他值的pageContext属性。17-2显示了使用这种隐式对象的一些例子。

17-2 JSTL表达式例子

表达式

结果

${pageContext.request.contextPath}

上下文路径(HttpServletRequest获得)

${sessionScope.cart.numberOfItems}

名为cart的会话作用域的numberOfItems属性

${param["mycom.productId"]}

mycom.productId参数的String

Literals

·  Boolean: truefalse

·  Long: 与在Java中的一样

·  Floating point: 与在Java中一样

·  String: 带单引号和双引号。"转义为""' 转义为"',而" 转义为""

·  Null: null

操作符

EL提供了下列操作符:

·  算术:+-*/div%mod-

·  逻辑: and&&or||not!

·  关系: ==eq!=ne<lt>gt<=ge>=le。可以是针对其他值,也可能针对布尔、字符串、整数或者浮点文字进行比较。

·  空: empty 操作符是一个前缀操作符,可以用来决定一个值是否为null或者空。

有关这些操作符的优先级和效果参见JSTL 1.0规范

标签协作

标签通常与它们的环境以隐式或者显式的方式协作。隐式协作是通过让上级标签公开定义好的接口、使嵌套的标签无缝地与上级标签协作来实现的。JSTL迭代器标签支持这种模式的协作。

显示协作在标签向环境公开信息时出现。传统上,这是通过公开一个脚本变量实现的(JSP作用域的属性提供实际对象)。因为JSTL有一个表达式语言,因此不太需要脚本变量。所以JSTL标签(包括ELRT版本)只是以JSP作用域属性公开信息,不使用脚本变量。下面的JSTL规范对于所有导出有关标签信息的标签属性使用名字var。例如,forEach标签以下面的方式公开购物车中正在迭代的当前项目

<c:forEach var="item" items="${sessionScope.cart.items}">
  ...
</c:forEach>

选用名字var以突出公开的作用域变量不是脚本变量(一般情况下对于属性应命名为id)

对于标签公开多种情息的情况,名字var用于公开的主要信息,对于公开的其他二级信息选用其他合适的名字。例如,forEach标签通过status属性公开迭代状态信息。

核心标签

核心标签包括那些与表达式、流程控制和一种通用的访问那些基于URL的、其内容可以包含在JSP页面或者在JSP页面中被处理的资源的方式相关的标签。

17-3 核心标签 

领域

功能

标签

TLD

前缀

核心

表达式语言支持

catch

out

remove

set

/jstl-c

c

流程控制

choose

  when

  otherwise

forEach

forTokens

if

URL管理

import

  param

redirect

  param

url

  param

表达式标签

out标签判断一个表达式并将判断结果输出为当前JspWriter对象。它对应于JSP语法<%= expression %>。例如,showcart.jsp像下面这样显示在购物车上的项目:

<c:out value="${sessionScope.cart.numberOfItems}"/>

set标签设置在任何JSP作用域(页面、请求、会话、应用程序)中的属性的值。如果该属性不存在,则创建它。

可以用属性值设置JSP作用域属性:

<c:set var="foo" scope="session" value="..."/>  

也可以用标签正文设置JSP作用域属性:

<c:set var="foo">
  ...
</c:set>

例如,下面用名为Remove的请求参数设置名为bookID的页面作用域属性:

<c:set var="bookId" value="${param.Remove}"/>

如果使用RT版本的库,那么语句将为:

<c_rt:set var="bookId"
  value="<%= request.getParameter("Remove") %>" />

要删除一个作用域属性,使用remove标签。调用书店JSP页面receipt.jsp时,购货会话就结束了,所以像下面这样删除会话属性cart

<c:remove var="cart" scope="session"/>

JSTL表达式语言减少了对脚本的需要。不过,页面编写者仍然会遇到在页面的脚本语言中一些非JSTL标签属性必须用表达式指定的情况。用标准JSP元素jsp:useBean声明可以在脚本表达式或者scriptlet中使用的脚本变量。例如,showcart.jsp使用scriptlet从购物车上删除一本书。这本要删除的书的ID作为请求参数传递。请求参数的值首先设置为页面属性(以便在后被标签JSTL sql:query使用),然后声明为脚本变量并传递给cart.remove方法:

<c:set var="bookId" value="${param.Remove}"/>
<jsp:useBean id="bookId" type="java.lang.String" />
<% cart.remove(bookId); %>
<sql:query var="books"
  dataSource="${applicationScope.bookDS}">
  select * from PUBLIC.books where id = ?
  <sql:param value="${bookId}" />
</sql:query>

catch标签为JSP错误页面机制提供了一种补充。它让页面编写者能够从可以控制的错误条件中正常恢复。页面上最重要的行动应当封装在catch中,这样它们的异常就会传播到错误页面。页面中次要的行动应当包装到catch中,这样它们就不会调用错误页面机制。

抛出的异常储存在由var标识的作用域变量中,它总是有页面作用域。如果没有发生异常,那么如果有由var标识的作用域变量的话,就将它删除。如果没有var,那么异常就仅仅被捕捉而不保存。

Database access标签库
Database access标签库中的标签用来提供在JSP页面中可以与数据库进行交互的功能,虽然它的存在对于早期纯JSP开发的应用以及小型的开发有着意义重大的贡献,但是对于MVC模型来说,它却是违反规范的。因为与数据库交互的工作本身就属于业务逻辑层的工作,所以不应该在JSP页面中出现,而是应该在模型层中进行。
对于Database access标签库本书不作重点介绍,只给出几个简单示例让读者略微了解它们的功能。
Database access标签库有以下6组标签来进行工作:<sql:setDataSource><sql:query><sql:update><sql:transaction><sql:setDataSource><sql:param><sql:dateParam>
9.6.1  用于设置数据源的<sql:setDataSource>标签
<sql:setDataSource>标签用于设置数据源,下面看一个示例:
<sql:setDataSource
    var="dataSrc"
    url="jdbc:postgresql://localhost:5432/myDB"
    driver="org.postgresql.Driver"
    user="admin"
    password="1111"/>
该示例定义一个数据源并保存在“dataSrc”变量内。
9.6.2  用于查询的<sql:query>标签
<sql:query>标签用于查询数据库,它标签体内可以是一句查询SQL。下面看一个示例:
<sql:query var="queryResults" dataSource="${dataSrc}">
      select * from table1
</sql:query>
该示例将返回查询的结果到变量“queryResults”中,保存的结果是javax.servlet.jsp.jstl.sql.Result类型的实例。要取得结果集中的数据可以使用<c:forEach>循环来进行。下面看一个示例。
<c:forEach var="row" items="${queryResults.rows}">
      <tr>
            <td>${row.userName}</td>
        <td>${row.passWord}</td>
      </tr>
</c:forEach>
“rows”javax.servlet.jsp.jstl.sql.Result实例的变量属性之一,用来表示数据库表中的集合,循环时,通过“${row.XXX}”表达式可以取得每一列的数据,“XXX”是表中的列名。
9.6.3  用于更新的<sql:update>标签
<sql:update>标签用于更新数据库,它的标签体内可以是一句更新的SQL语句。其使用和<sql:query>标签没有什么不同。
9.6.4  用于事务处理的<sql:transaction>标签
<sql:transaction>标签用于数据库的事务处理,在该标签体内可以使用<sql:update>标签和<sql:query>标签,而<sql:transaction>标签的事务管理将作用于它们之上。
<sql:transaction>标签对于事务处理定义了read_committedread_uncommittedrepeatable_readserializable4个隔离级别。
9.6.5  用于事务处理的<sql:param><sql:dateParam>标签
这两个标签用于向SQL语句提供参数,就好像程序中预处理SQL“?”一样。<sql:param>标签传递除java.util.Date类型以外的所有相融参数,<sql:dateParam>标签则指定必须传递java.util.Date类型的参数。
9.7  Functions标签库
称呼Functions标签库为标签库,倒不如称呼其为函数库来得更容易理解些。因为Functions标签库并没有提供传统的标签来为JSP页面的工作服务,而是被用于EL表达式语句中。在JSP2.0规范下出现的Functions标签库为EL表达式语句提供了许多更为有用的功能。Functions标签库分为两大类,共16个函数。
    长度函数:fn:lengthq
    字符串处理函数:fn:containsfn:containsIgnoreCasefn:endsWithfn:escapeXmlfn:indexOffn:joinfn:replacefn:splitfn:startsWithfn:substringfn:substringAfterfn:substringBeforefn:toLowerCasefn:toUpperCasefn:trimq
以下是各个函数的用途和属性以及简单示例。
9.7.1  长度函数fn:length函数
长度函数fn:length的出现有重要的意义。在JSTL1.0中,有一个功能被忽略了,那就是对集合的长度取值。虽然java.util.Collection接口定义了size方法,但是该方法不是一个标准的JavaBean属性方法(没有get,set方法),因此,无法通过EL表达式“${collection.size}”来轻松取得。
fn:length函数正是为了解决这个问题而被设计出来的。它的参数为input,将计算通过该属性传入的对象长度。该对象应该为集合类型或String类型。其返回结果是一个int类型的值。下面看一个示例。
<%ArrayList arrayList1 = new ArrayList();
            arrayList1.add("aa");
            arrayList1.add("bb");
            arrayList1.add("cc");
%>
<%request.getSession().setAttribute("arrayList1", arrayList1);%>
${fn:length(sessionScope.arrayList1)}
假设一个ArrayList类型的实例“arrayList1”,并为其添加三个字符串对象,使用fn:length函数后就可以取得返回结果为“3”
9.7.2  判断函数fn:contains函数
fn:contains函数用来判断源字符串是否包含子字符串。它包括stringsubstring两个参数,它们都是String类型,分布表示源字符串和子字符串。其返回结果为一个boolean类型的值。下面看一个示例。
${fn:contains("ABC", "a")}<br>
${fn:contains("ABC", "A")}<br>
前者返回“false”,后者返回“true”
9.7.3  fn:containsIgnoreCase函数
fn:containsIgnoreCase函数与fn:contains函数的功能差不多,唯一的区别是fn:containsIgnoreCase函数对于子字符串的包含比较将忽略大小写。它与fn:contains函数相同,包括stringsubstring两个参数,并返回一个boolean类型的值。下面看一个示例。
${fn:containsIgnoreCase("ABC", "a")}<br>
${fn:containsIgnoreCase("ABC", "A")}<br>
前者和后者都会返回“true”
9.7.4  词头判断函数fn:startsWith函数
fn:startsWith函数用来判断源字符串是否符合一连串的特定词头。它除了包含一个string参数外,还包含一个subffx参数,表示词头字符串,同样是String类型。该函数返回一个boolean类型的值。下面看一个示例。
${fn:startsWith ("ABC", "ab")}<br>
${fn:startsWith ("ABC", "AB")}<br>
前者返回“false”,后者返回“true”
9.7.5  词尾判断函数fn:endsWith函数
fn:endsWith函数用来判断源字符串是否符合一连串的特定词尾。它与fn:startsWith函数相同,包括stringsubffx两个参数,并返回一个boolean类型的值。下面看一个示例。
${fn:endsWith("ABC", "bc")}<br>
${fn:endsWith("ABC", "BC")}<br>
前者返回“false”,后者返回“true”
9.7.6  字符实体转换函数fn:escapeXml函数
fn:escapeXml函数用于将所有特殊字符转化为字符实体码。它只包含一个string参数,返回一个String类型的值。
9.7.8  字符匹配函数fn:indexOf函数
fn:indexOf函数用于取得子字符串与源字符串匹配的开始位置,若子字符串与源字符串中的内容没有匹配成功将返回“-1”。它包括stringsubstring两个参数,返回结果为int类型。下面看一个示例。
${fn:indexOf("ABCD","aBC")}<br>
${fn:indexOf("ABCD","BC")}<br>
前者由于没有匹配成功,所以返回-1,后者匹配成功将返回位置的下标,为1
9.7.9  分隔符函数fn:join函数
fn:join函数允许为一个字符串数组中的每一个字符串加上分隔符,并连接起来。它的参数、返回结果和描述如表9.25所示:
9.25 fn:join函数
参数    描述
array    字符串数组。其类型必须为String[]类型
separator    分隔符。其类型必须为String类型
返回结果    返回一个String类型的值
下面看一个示例。
<% String[] stringArray = {"a","b","c"}; %>
<%request.getSession().setAttribute("stringArray", stringArray);%>
${fn:join(sessionScope.stringArray,";")}<br>
定义数组并放置到Session中,然后通过Session得到该字符串数组,使用fn:join函数并传入分隔符“;”,得到的结果为“a;b;c”
9.7.10  替换函数fn:replace函数
fn:replace函数允许为源字符串做替换的工作。它的参数、返回结果和描述如表9.26所示:
9.26  fn:replace函数
参数    描述
inputString    源字符串。其类型必须为String类型
beforeSubstring    指定被替换字符串。其类型必须为String类型
afterSubstring    指定替换字符串。其类型必须为String类型
返回结果    返回一个String类型的值
下面看一个示例。
${fn:replace("ABC","A","B")}<br>
“ABC”字符串替换为“BBC”,在“ABC”字符串中用“B”替换了“A”
9.7.11  分隔符转换数组函数fn:split函数
fn:split函数用于将一组由分隔符分隔的字符串转换成字符串数组。它的参数、返回结果和描述如表9.27所示:
9.27  fn:split函数
参数    描述
string    源字符串。其类型必须为String类型
delimiters    指定分隔符。其类型必须为String类型
返回结果    返回一个String[]类型的值
下面看一个示例。
${fn:split("A,B,C",",")}<br>
“A,B,C”字符串转换为数组{A,B,C}
9.7.12  字符串截取函数fn:substring函数
fn:substring函数用于截取字符串。它的参数、返回结果和描述如表9.28所示:
9.28  fn:substring函数
参数    描述
string    源字符串。其类型必须为String类型
beginIndex    指定起始下标(值从0开始)。其类型必须为int类型
endIndex    指定结束下标(值从0开始)。其类型必须为int类型
返回结果    返回一个String类型的值
下面看一个示例。
${fn:substring("ABC","1","2")}<br>
截取结果为“B”
9.7.13  定位到结束截取字符串函数fn:substringAfter函数
fn:substringAfter函数允许截取源字符串中某个字符串开始到结束的所有字符。它的参数、返回结果和描述如表9.29所示:
9.29  fn:substringAfter函数
参数    描述
string    源字符串。其类型必须为String类型
substring    起始字符串,截取后的内容将不包括它。其类型必须为String类型
返回结果    返回一个String类型的值
下面看一个示例。
${fn:substringAfter("ABCD","BC")}<br>
截取的结果为“D”
9.7.14  起始到定位截取字符串函数fn:substringBefore函数
fn:substringBefore函数允许截取源字符从开始到某个字符串。它的参数和fn:substringAfter函数相同,不同的是substring表示的是结束字符串。下面看一个示例。
${fn:substringBefore("ABCD","BC")}<br>
截取的结果为“A”
9.7.15  小写转换函数fn:toLowerCase函数
fn:toLowerCase函数允许将源字符串中的字符全部转换成小写字符。它只有一个表示源字符串的参数string,函数返回一个String类型的值。下面看一个示例。
${fn:toLowerCase("ABCD")}<br>
转换的结果为“abcd”
9.7.16 大写转换函数fn:toUpperCase函数
fn:toUpperCase函数允许将源字符串中的字符全部转换成大写字符。它与fn:toLowerCase函数相同,也只有一个String参数,并返回一个String类型的值。下面看一个示例。
${fn:toUpperCase("abcd")}<br>
转换的结果为“ABCD”
9.7.17 空格删除函数fn:trim函数
fn:trim函数将删除源字符串中结尾部分的空格以产生一个新的字符串。它与fn:toLowerCase函数相同,只有一个String参数,并返回一个String类型的值。下面看一个示例。
${fn:trim("AB C  ")}D<br>
转换的结果为“AB CD”,注意,它将只删除词尾的空格而不是全部,因此“B”“C”之间仍然留有一个空格。

posted on 2008-05-02 12:28  小顾问  阅读(1477)  评论(0)    收藏  举报