JavaServer Pages Standard Tag Library

 

Overview

The JavaServer Pages Standard Tag Library (JSTL) encapsulates core functionality common to many JSP applications. For example, instead of iterating over lists using a scriptlet or different iteration tags from numerous vendors, JSTL defines a standard tag that works the same everywhere. This standardization lets you learn a single tag and use it on multiple JSP containers. Also, when tags are standard, containers can optimize their implementation.

JSTL has support for common, structural tasks such as iteration and conditionals, tags for manipulating XML documents, internationalization tags, and tags for accessing databases using SQL. It also introduces the concept of an expression language to simplify page development. JSTL also provides a framework for integrating existing tag libraries with JSTL.

This chapter demonstrates the JSTL through excerpts from the JSP version of the Duke's Bookstore application discussed in previous chapters. It assumes that you are familiar with the material in the Using Tags section of Chapter 15.

The Example JSP Pages

This chapter illustrates JSTL with excerpts from the JSP version of the Duke's Bookstore application discussed in Chapter 15 rewritten as follows:

The source for the Duke's Bookstore application is located in the $JWSDP_HOME/docs/tutorial/examples/web/bookstore4 directory created when you unzip the tutorial bundle (see Running the Examples).

To build, install, and run the example:

  1. In a terminal window, go to $JWSDP_HOME/docs/tutorial/examples/web/bookstore4.
  2. Run ant build. The build target will spawn any necessary compilations and copy files to the $JWSDP_HOME/docs/tutorial/examples/web/bookstore4/build directory.
  3. Make sure Tomcat is started.
  4. Run ant install. The install target notifies Tomcat that the new context is available.
  5. Start the PointBase database server and populate the database if you have not done so already (see Accessing Databases from Web Applications).
  6. Open the bookstore URL http://localhost:8080/bookstore4/enter.

To deploy the application using deploytool:

  1. Make sure Tomcat is started.
  2. Start deploytool.
  3. Create a webapp called bookstore4.
    1. Select FileNew Web Application.
    2. Click Browse.
    3. In the file chooser, navigate to $JWSDP_HOME/docs/tutorial/examples/web/bookstore4/build.
    4. In the File Name field, enter bookstore4.
    5. Click Choose Module File.
    6. In the WAR Display Name field, enter bookstore4.
    7. Click Edit to add the content files. In the Edit Contents dialog, navigate to $JWSDP_HOME/docs/tutorial/examples/web/web/bookstore4/build. Select the JSP pages banner.jsp, bookstore.jsp, bookdetails.jsp, catalog.jsp, showcart.jsp, cashier.jsp, receipt.jsp, template.jsp, screendefinitions.jsp, and errorpage.jsp, and duke.books.gif and click Add. Navigate to WEB-INF. Add Dispatcher.class and the cart, database, messages, taglib, and util packages from classes and the JSTL TLDs and libraries from lib. Click OK.
    8. Click Next.
    9. Select the Servlet radio button.
    10. Click Next.
    11. Select Dispatcher from the Servlet class combo box.
    12. Click Finish.
  4. Add the aliases.
    1. Select Dispatcher
    2. Select the Aliases tab.
    3. Click Add and then type /enter in the Aliases field. Repeat to add the aliases /catalog, /bookdetails, /showcart, /cashier, and /receipt.
  5. Add the JSTL basename context parameter.
    1. Select the Context tab.
    2. Click Add.
    3. Enter javax.servlet.jsp.jstl.fmt.localizationContext for the Coded Parameter.
    4. Enter messages.BookstoreMessages for the Value.
  6. Add a resource reference for the database.
    1. Select the WAR.
    2. Select the Resource Refs tab.
    3. Click Add.
    4. Select javax.sql.DataSource from the Type column
    5. Enter jdbc/BookDB in the Coded Name field.
    6. Click the Import Data Sources button.
    7. Dismiss the confirmation dialog.
    8. Select pointbase from the drop down list.
  7. Add the tag library URI to location mappings (see Declaring Tag Libraries):
    1. Select the File Refs tab.
    2. Click the Add button in the JSP Tag Libraries tab.
    3. Enter the relative URI /tutorial-template in the Coded Reference field.
    4. Enter the absolute location /WEB-INF/tutorial-template.tld in the Tag Library field.
    5. Repeat for /jstl-c to /WEB-INF/c.tld, /jstl-fmt to /WEB-INF/fmt.tld, and /jstl-sql to /WEB-INF/sql.tld.
  8. Deploy the application.
    1. Select Tools->Deploy.
    2. Click OK to select the default context path /bookstore4.
    3. Click Finish.

See Common Problems and Their Solutions and Troubleshooting for help with diagnosing common problems.

Using JSTL

JSTL includes a wide variety of tags that naturally fit into discrete functional areas. Therefore, JSTL is exposed via multiple tag library descriptors (TLDs) to clearly show the functional areas it covers and give each area its own namespace. Table 16-1 summarizes these functional areas along with the logical TLD names and prefixes used in this chapter and Duke's Bookstore application.

Area
Function
Tags
TLD
Prefix
Core
Expression Language Support
catch
out
remove
set
/jstl-c
c
Flow Control
choose
when
otherwise
forEach
forTokens
if
URL Management
import
paramredirect
param
url
param
XML
Core
out
parse
set
/jstl-x
x
Flow Control
choose when otherwise
forEach
if
Transformation
transform
param
I18n
Locale
setLocale
/jstl-fmt
fmt
Message formatting
bundle
message
param
setBundle
Number and dateformatting
formatNumber
formatDate
parseDate
parseNumber
setTimeZone
timeZone
Database

setDataSource
/jstl-sql
sql
SQL
query
dateParam
param
transaction
update dateParam
param

For example, to use the JSTL core tags in a JSP page, you declare the library using a taglib directive that references the TLD:

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

The JSTL tag libraries comes in two versions (see Twin Libraries). The TLDs for the JSTL-EL library are named prefix.tld. The TLDs for the JSTL-RT library are named prefix-rt.tld. Since the examples discussed in this chapter use logical TLD names, we map the logical names to actual TLD locations with taglib elements in the webapp deployment descriptor. Here is the entry that maps the core library logical TLD name /jstl-c to its location /WEB-INF/c.tld:

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

In the Java WSDP, the JSTL TLDs are stored in $JWSDP_HOME/tools/jstl/tlds. When you build the Duke's Bookstore application these TLDs are automatically copied into $JWSDP_HOME/docs/tutorial/examples/web/bookstore4/build/WEB-INF.

You can also reference a TLD in a taglib directive with an absolute URI:

When you use an absolute URI, you do not have to add the taglib element to web.xml; the JSP container automatically locates the TLD inside the JSTL library implementation.

In addition to declaring the tag library, you also need to make the JSTL API and implementation available to the webapp. These are distributed as the archives jstl.jar in $JWSDP_HOME/tools/jstl and standard.jar in $JWSDP_HOME/tools/jstl/standard. When you build the Duke's Bookstore application these libraries are automatically copied into $JWSDP_HOME/docs/tutorial/examples/web/bookstore4/build/WEB-INF/lib.

Expression Language Support

A primary feature of JSTL is its support for an expression language (EL). An expression language, in concert with JSTL tags, makes it possible to easily access application data and manipulate it in simple ways without having to use scriptlets or request-time expressions. Currently, a page author has to use an expression <%= aName %> to access the value of a system or user-defined JavaBeans component. For example:

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

Referring to nested bean properties is even more complex:

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

This makes page authoring more complicated than it need be.

An expression language allows a page author to access an object using a simplified syntax such as

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

for a simple variable or

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

for a nested property.

The JSTL expression language promotes JSP scoped attributes as the standard way to communicate information from business logic to JSP pages. For example, the test attribute of the this conditional tag is supplied with an expression that compares the number of items in the session-scoped attribute named cart with 0:

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

The next version of the JSP specification will standardize on an expression language for all custom tag libraries. This release of JSTL includes a snapshot of that expression language.

 

Twin Libraries

The JSTL tag libraries come in two versions which differ only in the way they support the use of runtime expressions for attribute values.

In the JSTL-RT tag library, expressions are specified in the page's scripting language. This is exactly how things currently work in current tag libraries.

In the JSTL-EL tag library, expressions are specified in the JSTL expression language. An expression is a String literal in the syntax of the EL.

When using the EL tag library you cannot pass a scripting language expression for the value of an attribute. This rule makes it possible to validate the syntax of an expression at translation time.

 

JSTL Expression Language

The JSTL expression language is responsible for handling both expressions and literals. Expressions are enclosed by the ${ } characters. For example:

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

Any value that does not begin with ${ is treated as a literal that is parsed to the expected type using the PropertyEditor for the expected type:

<c:if test="true" />

Literal values that contain the ${ characters must be escaped as follows:

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

Attributes

Attributes are accessed by name, with an optional scope. Properties of attributes are accessed using the . operator, and may be nested arbitrarily.

The EL unifies the treatment of the . and [ ] operators. Thus, expr-a.expr-b is equivalent to expr-a[expr-b]. To evaluate expr-a[expr-b], evaluate expr-a into value-a and evaluate expr-b into value-b.

The EL evaluates an identifier by looking up its value as an attribute, according to the behavior of PageContext.findAttribute(String). For example, ${product} will look for the attribute named product, searching the page, request, session, and application scopes and will return its value. If the attribute is not found, null is returned. Note that an identifier that matches one of the implicit objects described in the next section will return that implicit object instead of an attribute value.

Implicit Objects

The JSTL expression language defines a set of implicit objects:

When an expression references one of these objects by name, the appropriate object is returned instead of the corresponding attribute. For example: ${pageContext} returns the PageContext object, even if there is an existing pageContext attribute containing some other value. Table 16-2 shows some examples of using these implicit objects.

Expression
Result
${pageContext.request.contextPath}
The context path (obtained from HttpServletRequest)
${sessionScope.cart.numberOfItems}
The numberOfItems property of the session-scoped attribute named cart
${param["mycom.productId"]}
The String value of the mycom.productId parameter

Literals

Operators

The EL provides the following operators:

Consult the JSTL 1.0 Specification for the precedence and effects of these operators.

 

Tag Collaboration

Tags usually collaborate with their environment in implicit and explicit ways. Implicit collaboration is done via a well defined interface that allows nested tags to work seamlessly with the ancestor tag exposing that interface. The JSTL iterator tags support this mode of collaboration.

Explicit collaboration happens when a tag exposes information to its environment. Traditionally, this has been done by exposing a scripting variable (with a JSP scoped attribute providing the actual object). Because JSTL has an expression language, there is less need for scripting variables. So the JSTL tags (both the EL and RT versions) expose information only as JSP scoped attributes; no scripting variables are used. The convention JSTL follows is to use the name var for any tag attribute that exports information about the tag. For example, the forEach tag exposes the current item of the shopping cart it is iterating over in the following way:

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

The name var was selected to highlight the fact that the scoped variable exposed is not a scripting variable (which is normally the case for attributes named id).

In situations where a tag exposes more than one piece of information, the name var is used for the primary piece of information being exported, and an appropriate name is selected for any other secondary piece of information exposed. For example, iteration status information is exported by the forEach tag via the attribute status.

Core Tags

The core tags include those related to expressions, flow control, and a generic way to access URL-based resources whose content can then be included or processed within the JSP page.

Area
Function
Tags
TLD
Prefix
Core
Expression Language Support
catch
out
remove
set
/jstl-c
c
Flow Control
choose
when
otherwise
forEach
forTokens
if
URL Management
import
param
redirect
param
url
param

 

Expression Tags

The out tag evaluates an expression and outputs the result of the evaluation to the current JspWriter object. It is the equivalent of the JSP syntax <%= expression %>. For example, showcart.jsp displays the number of items in a shopping cart as follows:

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

The set tag sets the value of an attribute in any of the JSP scopes (page, request, session, application). If the attribute does not already exist, it is created.

The JSP scoped attribute can be set either from attribute value:

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

or from the body of the tag:

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

For example, the following sets a page-scoped attribute named bookID with the value of the request parameter named Remove:

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

If you were using the RT version of the library, the statement would be:

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

To remove a scoped attribute, you use the remove tag. When the bookstore JSP page receipt.jsp is invoked, the shopping session is finished, so the cart session attribute is removed as follows:

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

The JSTL expression language reduces the need for scripting. However, page authors will still have to deal with situations where some attributes of non-JSTL tags must be specified as expressions in the page's scripting language. The standard JSP element jsp:useBean is used to declare a scripting variable that can be used in a scripting language expression or scriptlet. For example, showcart.jsp removes a book from a shopping cart using a scriptlet. The ID of the book to be removed is passed as a request parameter. The value of the request parameter is first set as a page attribute (to be used later by the JSTL sql:query tag) and then declared as scripting variable and passed to the cart.remove method:

<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>

The catch tag provides a complement to the JSP error page mechanism. It allows page authors to recover gracefully from error conditions that they can control. Actions that are of central importance to a page should not be encapsulated in a catch, so their exceptions will propagate to an error page. Actions with secondary importance to the page should be wrapped in a catch, so they never cause the error page mechanism to be invoked.

The exception thrown is stored in the scoped variable identified by var, which always has page scope. If no exception occurred, the scoped variable identified by var is removed if it existed. If var is missing, the exception is simply caught and not saved.

 

Flow Control Tags

To execute flow control logic, a page author must generally resort to using scriptlets. For example, the following scriptlet is used to iterate through a shopping cart:

<% 
  Iterator i = cart.getItems().iterator();
  while (i.hasNext()) {
    ShoppingCartItem item =
      (ShoppingCartItem)i.next();
    ...
%>
    <tr>
    <td align="right" bgcolor="#ffffff"> 
    <%=item.getQuantity()%>
    </td>
    ...
<% 
  } 
%>

Flow control tags eliminate the need for scriptlets. The next two sections have examples that demonstrate the conditional and iterator tags.

Conditional Tags

The if tag allows the conditional execution of its body according to value of a test attribute. The following example from catalog.jsp tests whether the request parameter Add is empty. If the test evaluates to true, the page queries the database for the book record identified by the request parameter and adds the book to the shopping cart:

<c:if test="${!empty param.Add}">
  <c:set var="bid" value="${param.Add}"/>
  <jsp:useBean id="bid"  type="java.lang.String" />
   <sql:query var="books" 
    dataSource="${applicationScope.bookDS}">
    select * from PUBLIC.books where id = ?
    <sql:param value="${bid}" />
  </sql:query>
  <c:forEach var="bookRow" begin="0" items="${books.rows}"> 
    <jsp:useBean id="bookRow" type="java.util.Map" />
    <jsp:useBean id="addedBook"
      class="database.BookDetails" scope="page" />
  ...
  <% cart.add(bid, addedBook); %>
...
</c:if>

The choose tag performs conditional block execution by the embedded when sub tags. It renders the body of the first when tag whose test condition evaluates to true. If none of the test conditions of nested when tags evaluate to true, then the body of an otherwise tag is evaluated, if present.

For example, the following sample code shows how to render text based on a customer's membership category.

<c:choose> 
  <c:when test="${customer.category == 'trial'}" > 
    ... 
  </c:when> 
  <c:when test="${customer.category == 'member'}" > 
    ... 
  </c:when> 
    <c:when test="${customer.category == 'preferred'}" > 
    ... 
  </c:when> 
  <c:otherwise> 
    ... 
  </c:otherwise> 
</c:choose> 

The choose, when, and otherwise tags can be used to construct an if-then-else statement as follows:

<c:choose> 
  <c:when test="${count == 0} > 
    No records matched your selection. 
  </c:when> 
  <c:otherwise> 
    <c:out value="${count}"/> records matched your selection. 
  </c:otherwise> 
</c:choose>

Iterator Tags

The forEach tag allows you to iterate over a collection of objects. You specify the collection via the items attribute, and the current item is available through a scope variable named by the item attribute.

A large number of collection types are supported by forEach, including all implementations of java.util.Collection and java.util.Map. If the items attribute is of type java.util.Map, then the current item will be of type java.util.Map.Entry, which has the following properties:

Arrays of objects as well as arrays of primitive types (for example, int) are also supported. For arrays of primitive types, the current item for the iteration is automatically wrapped with its standard wrapper class (for example, Integer for int, Float for float, and so on).

Implementations of java.util.Iterator and java.util.Enumeration are supported but these must be used with caution. Iterator and Enumeration objects are not resettable so they should not be used within more than one iteration tag. Finally, java.lang.String objects can be iterated over if the string contains a list of comma separated values (for example: Monday,Tuesday,Wednesday,Thursday,Friday).

Here's the shopping cart iteration from the previous section with the forEach tag:

<c:forEach var="item" items="${sessionScope.cart.items}">
  ...
  <tr> 
    <td align="right" bgcolor="#ffffff"> 
    <c:out value="${item.quantity}"/>
  </td>
  ...
</c:forEach>

The forTokens tag is used to iterate over a collection of tokens separated by a delimiter.

 

URL Tags

The jsp:include element provides for the inclusion of static and dynamic resources in the same context as the current page. However, jsp:include cannot access resources that reside outside of the webapp and causes unnecessary buffering when the resource included is used by another element.

In the example below, the transform element uses the content of the included resource as the input of its transformation. The jsp:include element reads the content of the response, writes it to the body content of the enclosing transform element, which then re-reads the exact same content. It would be more efficient if the transform element could access the input source directly and avoid the buffering involved in the body content of the transform tag.

<acme:transform>
  <jsp:include page="/exec/employeesList"/>
<acme:transform/>

The import tag is therefore the simple, generic way to access URL-based resources whose content can then be included and or processed within the JSP page. For example, in XML Tags, import is used to read in the XML document containing book information and assign the content to the scoped variable xml:

<c:import url="/books.xml" var="xml" />
<x:parse xml="${xml}" var="booklist" 
  scope="application" />

The param tag, analogous to the jsp:param tag (see jsp:param Element), can be used with import to specify request parameters.

In Session Tracking we discussed how an application must rewrite URLs to enable session tracking whenever the client turns off cookies. You can use the url tag to rewrite URLs returned from a JSP page. The tag includes the session ID in the URL only if cookies are disabled; otherwise, it returns the URL unchanged. Note that this feature requires the URL to be relative. The url tag takes param subtags for including parameters in the returned URL. For example, catalog.jsp rewrites the URL used to add a book to the shopping cart as follows:

<c:url var="url" 
  value="/catalog" >
  <c:param name="Add" value="${bookId}" />
</c:url>
<p><strong><a href="<c:out value='${url}'/>">

The redirect tag sends an HTTP redirect to the client. The redirect tag takes param subtags for including parameters in the returned URL.

XML Tags

A key aspect of dealing with XML documents is to be able to easily access their content. XPath, a W3C recommendation since 1999, provides an easy notation for specifying and selecting parts of an XML document. The JSTL XML tag set, listed in Table 16-4, is based on XPath (see How XPath Works).

Area
Function
Tags
TLD
Prefix
XML
Core
out
parse
set
/jstl-x
x
Flow Control
choose
when
otherwise
forEach
if
Transformation
transform
param

The XML tags use XPath as a local expression language; XPath expressions are always specified using attribute select. This means that only values specified for select attributes are evaluated using the XPath expression language. All other attributes are evaluated using the rules associated with the global expression language.

In addition to the standard XPath syntax, the JSTL XPath engine supports the following scopes to access webapp data within an XPath expression:

These scopes are defined in exactly the same way as their counterparts in the JSTL expression language discussed in Implicit Objects. Table 16-5 shows some examples of using the scopes.

XPath Expression
Result
$sessionScope:profile
The session-scoped attribute named profile
$initParam:mycom.productId
The String value of the mycom.productId context parameter

The XML tags are illustrated in another version (bookstore5) of the Duke's Bookstore application. This version replaces the database with an XML representation (books.xml) of the bookstore database. To build and install this version of the application, follow the directions in The Example JSP Pages replacing bookstore4 with bookstore5.

Since the XML tags require an XPath evaluator, the Java WSDP includes the Jaxen XPath evaluator in two libraries, jaxen-full.jar and saxpath.jar, in $JWSDP_HOME/tools/jstl/standard. When you build the Duke's Bookstore application these libraries are automatically copied into $JWSDP_HOME/docs/tutorial/examples/web/bookstore5/build/WEB-INF/lib.

 

Core Tags

The core XML tags provide basic functionality to easily parse and access XML data.

The parse tag parses an XML document and saves the resulting object in the scoped attribute specified by attribute var. In bookstore5, the XML document is parsed and saved to a context attribute in parseBooks.jsp, which is included by all JSP pages that need access to the document:

<c:if test="${applicationScope:booklist == null}" > 
  <c:import url="/books.xml" var="xml" />
  <x:parse xml="${xml}" var="booklist" scope="application" />
</c:if>

The out and set tags parallel the behavior described in Expression Tags for the XPath local expression language. The out tag evaluates an XPath expression on the current context node and outputs the result of the evaluation to the current JspWriter object.

The set tag evaluates an XPath expression and sets the result into a JSP scoped attribute specified by attribute var.

The JSP page bookdetails.jsp selects a book element whose id attribute matches the request parameter bookId and sets the abook attribute. The out tag then selects the book's title element and outputs the result.

<x:set var="abook"
select="$applicationScope.booklist/
        books/book[@id=$param:bookId]" />
  <h3><x:out select="$abook/title"/></h3>

As you have just seen, x:set stores an internal XML representation of a node retrieved using an XPath expression; it doesn't convert the selected node into a String and store it. Thus, x:set is primarily useful for storing parts of documents for later retrieval.

If you want to store a String, you need to use x:out within c:set. The x:out tag converts the node to a String, and c:set> then stores the String as a scoped attribute. For example, bookdetails.jsp stores a scoped attribute containing a book price, which is later fed into a fmt tag, as follows:

<c:set var="price">
  <x:out select="$abook/price"/>
</c:set>
<h4><fmt:message key="ItemPrice"/>: 
  <fmt:formatNumber value="${price}" type="currency"/>  

The other option, which is more direct but requires that the user have more knowledge of XPath, is to coerce the node to a String manually using XPath's string function.

<x:set var="price" select="string($abook/price)"/>

 

Flow Control Tags

The XML flow control tags parallel the behavior described in Flow Control Tags for the XPath expression language.

The JSP page catalog.jsp uses the forEach tag to display all the books contained in booklist as follows:

<x:forEach var="book" 
  select="$applicationScope:booklist/books/*">
  <tr>
    <c:set var="bookId">
      <x:out select="$book/@id"/>
    </c:set>=
    <td bgcolor="#ffffaa"> 
      <c:url var="url"
      value="/bookdetails" >
        <c:param name="bookId" value="${bookId}" />
        <c:param name="Clear" value="0" />
      </c:url>
      <a href="<c:out value='${url}'/>">
      <strong><x:out select="$book/title"/>&nbsp;
      </strong></a></td> 
    <td bgcolor="#ffffaa" rowspan=2> 
      <c:set var="price">
        <x:out select="$book/price"/>
      </c:set>
      <fmt:formatNumber value="${price}" type="currency"/> 
      &nbsp;
    </td> 
    <td bgcolor="#ffffaa" rowspan=2> 
    <c:url var="url" value="/catalog" >
      <c:param name="Add" value="${bookId}" />
    </c:url> 
    <p><strong><a href="<c:out value='${url}'/>">&nbsp;
      <fmt:message key="CartAdd"/>&nbsp;</a>
    </td>
  </tr> 
  <tr> 
    <td bgcolor="#ffffff"> 
    &nbsp;&nbsp;<fmt:message key="By"/> <em>
      <x:out select="$book/firstname"/>&nbsp;
      <x:out select="$book/surname"/></em></td></tr>
</x:forEach>

 

Transformation Tags

The transform tag applies a transformation, specified by a XSLT stylesheet set by the attribute xslt, to an XML document, specified by the attribute xml. If the xml attribute is not specified, the input XML document is read from the tag's body content.

The param subtag can be used along with transform to set transformation parameters. The attributes name and value are used to specify the parameter. The value attribute is optional. If it is not specified the value is retrieved from the tag's body.

Internationalization Tags

In Internationalizing and Localizing Web Applications we discussed the how to adapt webapps to the language and formatting conventions of client locales. This section describes tags that support the internationalization of JSP pages.

JSTL defines tags for:

 

Setting the Locale

The setLocale tag is used to override the client-specified locale for a page. The requestEncoding tag is used to set the request's character encoding, in order to be able to correctly decode request parameter values whose encoding is different from ISO-8859-1.

 

Messaging Tags

By default, browser-sensing capabilities for locales are enabled. This means that the client determines (via its browser settings) which locale to use, and allows page authors to cater to the language preferences of their clients.

bundle Tag

You use the bundle tag to specify a resource bundle for a page.

To define a resource bundle for a webapp you specify the context parameter javax.servlet.jsp.jstl.fmt.localizationContext in the webapp deployment descriptor. Here is the declaration from the Duke's Bookstore descriptor:

<context-param>
  <param-name>
    javax.servlet.jsp.jstl.fmt.localizationContext
  </param-name>
  <param-value>messages.BookstoreMessages</param-value>
</context-param>  

message Tag

The message tag is used to output localized strings. The following tag from catalog.jsp

<h3><fmt:message key="Choose"/></h3>

is used to output a string inviting customers to choose a book from the catalog.

The param subtag provides a single argument (for parametric replacement) to the compound message or pattern in its parent message tag. One param tag must be specified for each variable in the compound message or pattern. Parametric replacement takes place in the order of the param tags.

 

Formatting Tags

JSTL provides a set of tags for parsing and formatting locale-sensitive numbers and dates.

The formatNumber tag is used to output localized numbers. The following tag from showcart.jsp

<fmt:formatNumber value="${book.price}" type="currency"/>

is used to display a localized price for a book. Note that since the price is maintained in the database in dollars, the localization is somewhat simplistic, because the formatNumber tag is unaware of exchange rates. The tag formats currencies but does not convert them.

Analogous tags for formatting dates (formatDate), and parsing numbers and dates (parseNumber, parseDate) are also available. The timeZone tag establishes the time zone (specified via the value attribute) to be used by any nested formatDate tags.

In receipt.jsp, a "pretend" ship date is created and then formatted with the formatDate tag:

<jsp:useBean id="now" class="java.util.Date" />
<jsp:setProperty name="now" property="time" 
  value="<%= now.getTime() + 432000000 %>" />
<fmt:message key="ShipDate"/> 
<fmt:formatDate value="${now}" type="date"
  dateStyle="full"/>.

SQL Tags

The JSTL SQL tags are designed for quick prototyping and simple applications. For production applications, database operations are normally encapsulated in JavaBeans components.

Area
Function
Tags
TLD
Prefix
Database

setDataSource
/jstl-sql
sql
SQL
query
dateParam paramtransaction
update dateParam
param

The setDataSource tag is provided to allow you to set data source information for the database. You can provide a JNDI name or DriverManager parameters to set the data source information. All the Duke's Bookstore pages that have more than one SQL tag use the following statement to set the data source:

<sql:setDataSource dataSource="jdbc/BookDB" />

The query tag is used to perform an SQL query that returns a result set. For parameterized SQL queries, you use a nested param tag inside the query tag.

In catalog.jsp, the value of the Add request parameter determines which book information should be retrieved from the database. This parameter is saved as the attribute name bid and passed to the param tag. Notice that the query tag obtains its data source from the context attribute bookDS set in the context listener.

<c:set var="bid" value="${param.Add}"/>
<sql:query var="books" >
  select * from PUBLIC.books where id = ?
  <sql:param value="${bid}" />
</sql:query>

The update tag is used to update a database row. The transaction tag is used to perform a series of SQL statements atomically.

The JSP page receipt.jsp page uses both tags to update the database inventory for each purchase. Since a shopping cart can contain more than one book, the transaction tag is used to wrap multiple queries and updates. First the page establishes that there is sufficient inventory, then the updates are performed.

<c:set var="sufficientInventory" value="true" />
<sql:transaction>
  <c:forEach var="item" items="${sessionScope.cart.items}">
    <c:set var="book" value="${item.item}" />
    <c:set var="bookId" value="${book.bookId}" />

    <sql:query var="books" 
      sql="select * from PUBLIC.books where id = ?" >
      <sql:param value="${bookId}" />
    </sql:query>
    <jsp:useBean id="inventory"
      class="database.BookInventory" />
    <c:forEach var="bookRow" begin="0"
      items="${books.rowsByIndex}">
      <jsp:useBean id="bookRow"  type="java.lang.Object[]" />
      <jsp:setProperty name="inventory" property="quantity"
        value="<%=(Integer)bookRow[7]%>" />

      <c:if test="${item.quantity > inventory.quantity}">
        <c:set var="sufficientInventory" value="false" />
        <h3><font color="red" size="+2">
        <fmt:message key="OrderError"/> 
        There is insufficient inventory for 
        <i><c:out value="${bookRow[3]}"/></i>.</font></h3>
      </c:if>
    </c:forEach>
  </c:forEach>

  <c:if test="${sufficientInventory == 'true'}" />
    <c:forEach var="item" items="${sessionScope.cart.items}">
      <c:set var="book" value="${item.item}" />
      <c:set var="bookId" value="${book.bookId}" />

      <sql:query var="books" 
        sql="select * from PUBLIC.books where id = ?" >
        <sql:param value="${bookId}" />
      </sql:query>

      <c:forEach var="bookRow" begin="0"
        items="${books.rows}">            
        <sql:update var="books" sql="update PUBLIC.books set
          inventory = inventory - ? where id = ?" >
          <sql:param value="${item.quantity}" />
          <sql:param value="${bookId}" />
        </sql:update>
      </c:forEach>
    </c:forEach>
    <h3><fmt:message key="ThankYou"/>
      <c:out value="${param.cardname}" />.</h3><br>  
  </c:if>
</sql:transaction>

 

query Tag Result Interface

The Result interface is used to retrieve information from objects returned from a query tag.

public interface Result
  public String[] getColumnNames();
  public int getRowCount()
  public Map[] getRows();
  public Object[][] getRowsByIndex();
  public boolean isLimitedByMaxRows();

For complete information about this interface, see the API documentation for the javax.servlet.jsp.jstl.sql package.

The var attribute set by a query tag is of type Result. The getRows method returns an array of maps that can be supplied to the items attribute of a forEach tag. The JSTL expression language converts the syntax ${result.rows} to a call to result.getRows. The expression ${books.rows} in the following example returns an array of maps.

When you provide a array of maps to the forEach tag, the var attribute set by the tag is of type Map. To retrieve information from a row, use the get("colname") method to get a column value. The JSTL expression language converts the syntax ${map.colname} to a call to map.get("colname"). For example, the expression ${book.title} returns the value of the title entry of a book map.

The Duke's Bookstore page bookdetails.jsp retrieves the column values from the book map as follows.

<c:forEach var="book" begin="0" items="${books.rows}">
  <h3><c:out value="${book.title}"/></h3>
  &nbsp;<fmt:message key="By"/> <em><c:out
  value="${book.firstname}"/> <c:out
  value="${book.surname}"/></em>&nbsp;&nbsp;
  (<c:out value="${book.year}"/>)<br> &nbsp; <br>
  <h4><fmt:message key="Critics"/></h4>
  <blockquote><c:out value="${book.description}"/>
  </blockquote>
  <h4><fmt:message key="ItemPrice"/>: 
  <fmt:formatNumber value="${book.price}" type="currency"/> 
  </h4>
</c:forEach>

The following excerpt from catalog.jsp uses the Row interface to retrieve values from the columns of a book row using scripting language expressions. First the book row that matches a request parameter (bid) is retrieved from the database. Since the bid and bookRow objects are later used by tags that use scripting language expressions to set attribute values and a scriptlet that adds a book to the shopping cart, both objects are declared as scripting variables using the jsp:useBean tag. The page creates a bean that describes the book and scripting language expressions are used to set the book properties from book row column values. Finally the book is added to the shopping cart.

You might want to compare this version of catalog.jsp to the versions in JavaServer Pages Technology and Custom Tags in JSP Pages that use a book database JavaBeans component.

<sql:query var="books" 
  dataSource="${applicationScope.bookDS}">
  select * from PUBLIC.books where id = ?
  <sql:param value="${bid}" />
</sql:query>
<c:forEach var="bookRow" begin="0"
      items="${books.rowsByIndex}"> 
  <jsp:useBean id="bid"  type="java.lang.String" />
  <jsp:useBean id="bookRow" type="java.lang.Object[]" />
  <jsp:useBean id="addedBook" class="database.BookDetails"
    scope="page" />
    <jsp:setProperty name="addedBook" property="bookId"
      value="<%=bookRow[0]%>" />
    <jsp:setProperty name="addedBook" property="surname"
      value="<%=bookRow[1]%>" />
    <jsp:setProperty name="addedBook" property="firstName"
      value="<%=bookRow[2]%>" />
    <jsp:setProperty name="addedBook" property="title"
      value="<%=bookRow[3]%>" />
    <jsp:setProperty name="addedBook" property="price"
      value="<%=((Double)bookRow[4]).floatValue()%>" />
    <jsp:setProperty name="addedBook" property="year"
      value="<%=(Integer)bookRow[5]%>" />
    <jsp:setProperty name="addedBook" 
      property="description" value="<%=bookRow[6]%>" />
    <jsp:setProperty name="addedBook" property="inventory"
      value="<%=(Integer)bookRow[7]%>" />
  </jsp:useBean>
  <% cart.add(bid, addedBook); %>
  ...
</c:forEach>

Further Information

For further information on JSTL see:


 

Home