Faster Development with JavaServer Pages Standard Tag Library (JSTL 1.0)

   
   

Articles Index



JavaServer Pages (JSP) technology makes it easy to embed bits of Java code (or scriptlets) in HTML documents. This solution, however, may not be suitable for all HTML content developers, perhaps because they don't know Java and don't care to learn its syntax. To serve these HTML developers, you can introduce custom tags through the JSP Standard Tag Library (JSTL 1.0), which can be deployed and used in an HTML-like syntax.

Custom tags provide a way to reuse valuable components. The typical problem with custom tags, however, is that they still need to be created, tested, and debugged. In addition, developers often have to reinvent the wheel over and over again and the solutions may not be the most efficient. This is the problem that the JavaServer Pages Standard Tag Library solves, by providing a set of reusable standard tags. JSTL defines a standard tag library that works the same everywhere, so you no longer have to iterate over collections using a scriptlet (or iteration tags from numerous vendors).

This article covers the following topics:

  • Overview of the JSTL 1.0
  • Instructions for installing Tomcat 4.1.12 and JSTL
  • Introduction to the JSTL expression language
  • Tutorial on using JSTL core, general purpose tags
  • Tutorial on using the JSTL support for XML

This article assumes that you have hands-on experience with JavaServer Pages (JSP) technology. If you are new to JSP technology, I'd recommend that you start with the Fast Track JSP tutorial.

Overview of JSTL 1.0

The JavaServer Pages Standard Tag Library (JSTL) 1.0, as its name suggests, is a standard tag library that provides support for common, structural tasks, such as: iteration and conditionals, processing XML documents, internationalization, and database access using the Structured Query Language (SQL). The JSTL specification is being developed by the JSR-52 expert group under the Java Community Process.

The JSTL provides four separate tag libraries, each containing custom actions that target a specific functional area: (1) core action, (2) XML processing, (3) internationalization, and (4) database access. In addition, the JSTL introduces the concept of an expression language (EL) to simplify page development.

The goal of this article is to get you quickly up to speed on using JSTL. To that end, there's a detailed treatment of the expression language, the core (general purpose) tags, and the tags for processing XML documents. The support for internationalization and databases will be the topic of a future article.

Getting Started

The JSTL 1.0 requires a JSP container that supports the Java Servlet 2.3 and JavaServer Pages 1.2 specifications. Jakarta Tomcat 4 supports the new specifications, so in this section I will show you how to install Tomcat 4.1.12 and an implementation of the JSTL 1.0. If you have Jakarta Tomcat 4.1.12 installed, you only need to install an implementation of the JSTL 1.0, as discussed below.

Note: An implementation of JSTL 1.0 is also contained in Sun ONE Studio 4 (formerly known as Forte for Java) and the Java Web Services Developer Pack (Java WSDP). If you have either of these installed, you are set to go.

Downloading and Installing Tomcat

The current version of Tomcat is 4.1.12, and it's available for download at http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.1.12/. There are two versions:

  • A standard distribution that includes all optional libraries and XML parsers for J2SE prior to version 1.4.
  • A "lite" edition customized for J2SE 1.4. It doesn't include the optional libraries and XML parsers, since these are included in J2SE 1.4.

If you have J2SE 1.4, I'd recommend that you download the lite edition package, whose filename contains the abbreviation LE. Once you download Tomcat 4.1.12, the installation is self-explanatory. Simply follow the instructions.

Downloading and Installing JSTL

The Jakarta Taglibs project provides a reference implementation for the JSTL. This implementation is known as "project standard." Download the reference implementation from http://jakarta.apache.org/builds/jakarta-taglibs/releases/standard.

Once you download it, unpack the distribution in a directory of your choice, and you should have something like:

Directory of C:\jstl-1.0

<DIR>          .
<DIR>          ..
<DIR>          javadoc
<DIR>          lib
               README
               standard-doc.war
               standard-examples.war
<DIR>          tld

The lib directory contains the JAR files that implement the JSTL.

Running the Standard-Example

As you can see above, the C:\jstl-1.0 directory contains the files standard-doc.war and standard-examples.war. These files provide stand-alone, ready-to-run JSTL documentation and examples. To read the documentation and run the examples, copy these two files from the directory where you installed the Standard Taglib ( c:\jstl-1.0 in this case) to $TOMCAT_HOME\webapps. Now, start Tomcat and point your browser to the documentation and examples using http://localhost:8080/standard-doc and http://localhost:8080/standard-examples, respectively. The standard-examples include several sample JSTL applications that are easy to run; simply click on the application you wish to run. You can also view its source code.

Starting Your Own Project

To start experimenting with the JSTL, create a directory that corresponds to the web application you wish to create; get it ready by performing the following steps:

  1. Inside the directory where you installed Tomcat, there is a directory called webapps. Create a directory (for example, learn) under webapps.
  2. Create a subdirectory under the directory created in Step 1, and call it WEB-INF.
  3. Inside WEB-INF, create a file called web.xml with the following contents:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    
    <!DOCTYPE web-app
        PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://bit.ly/bnsLU6">
    
    <web-app>
      <description>Learning JSTL (or whatever you like</description>
    </web-app>
    

  4. Inside WEB-INF, create another subdirectory called lib.

To use the JSTL tags, you need to copy the JSTL JAR files from the lib directory where you installed the Standard Taglib to the lib directory under WEB-INF.

As a simple example, consider the following snippet of code that uses JSTL. The set action creates a variable named browser and assigns it the value of the User-Agent property. The out action then prints the value of the browser.

<%@ taglib prefix="c" uri="#" %>
<html>
<head>
<title>Simple Example</title>
</head>
<body>

<c:set var="browser" value="${header['User-Agent']}"/>
<c:out value="${browser}"/>

</body>
</html>

This can also be written as: <c:out value="${header['User-Agent']}"/>

To run this example, copy the above snippet of code to a file (let's call it example.jsp) and save it in the directory you have created within webapps. Your application should now be accessible at the URL: http://localhost:8080/dirName/example.jsp, where dirName is the name of the directory you created under webapps. When you call that URL, the output will be something like the following, depending on the browser being used (I'm using Microsoft Internet Explorer on Windows here):

Mozilla/4,0 (compatible; MSIE 6.0; Windows NT 5.0; Q312461; NET CLR 1.0.3705)

The JSTL Expression Language

Information to be passed to JSP pages is communicated using JSP scoped attributes and request parameters. An expression language (EL), which is designed specifically for page authors, promotes JSP scoped attributes as the standard way to communicate information from business logic to JSP pages. Note, however, that while the EL is a key aspect of the JSP, it is not a general purpose programming language. Rather, it is simply a data access language, which makes it possible to easily access (and manipulate) application data without having to use scriptlets or request-time expression values.

Currently, a page author must use an expression <%= aName %> to access the value of a system, as in the following example:

<someTags:aTag attribute="<%= pageContext.getAttribute("aName") %>">

or the value of a custom JavaBeans component:

<%= aCustomer.getAddress().getCountry() %>

An expression language allows a page author to access an object using a simplified syntax. For example, to access a simple variable, you can use something like:

<someTags:aTag attribute="${aName}">

And to access a nested JavaBeans property, you would use something like:

<someTags.aTag attribute="${aCustomer.address.country}">

But, you might ask, isn't this JavaScript syntax? You are absolutely right! If you've worked with JavaScript, you will feel right at home, because the EL borrows the JavaScript syntax for accessing structured data.

Note: The specification for the expression language is really the responsibility of the JSR-152 expert group (JavaServer Pages 1.3). The JSR-52 (JSTL) and the JSR-152 expert groups have worked together on specifying the expression language. However, since JSTL 1.0 was finalized prior to JavaServer Pages 2.0, the goal was to ensure that the current expression-language specification would be compatible with the one in JavaServer Pages 2.0. The good news is that once JavaServer Pages 2.0 is released, you'll be ready to use its expression language, since it's the same as what you see here.

Accessing Application Data

You can access application data either as a property of an object, using the dot (.) operator, or a named array element using the bracket ['name'] operator.

The JSTL expression ${data} represents the scoped variable named data. You can retrieve properties from collections using either the dot (.) or bracket ([]) operator:

  • The dot (.) operator is used to retrieve a named property. For example, the expression ${customer.name} indicates the name property of the customer scoped variable.
  • The bracket operator ([]) can be used to retrieve a named property, as in ${customer["name"]}. The bracket operator can also be used as ${customers[0]} to refer to the first item in the customers collection.

The expression language unifies the treatment of dot (.) and bracket ([]) operators. Therefore, ${customer.name} is equivalent to ${customer["name"]}. As you can see, all EL expressions must be enclosed between ${ and }.

The EL evaluates an identifier by looking up its value as an attribute using PageContext.findAttribute(String). If the attribute is not found, null is returned.

Operators

The EL supports arithmetic, relational, and logical operators to handle the most common data manipulations. In addition, a special operator for testing if an object is empty is provided. The operators are shown in Table 1. You can use the empty operator to determine whether a collection or a string is empty or null. For example, ${empty param.name} will be true only if the request parameter named param is not present. The empty operator can be combined with the ! operator, as in the expression ${!empty param.name}, which evaluates to true if the request parameter named param is present.

Table 1: Expression language operators
Operator Description
+ Addition
- Subtraction
* Multiplication
/ or div Division
% or mod Modulus (Remainder)
== or Equality
!= or != Inequality
< or lt Less than
> or gt Greater than
<= or le Less than or equal to
>= or ge Greater than or equal to
&& or and Logical AND
|| or or Logical OR
! or not Boolean complement
empty Check for empty value

Implicit Objects

In addition to operators, the EL defines implicit objects to support access to application data that is of interest to page authors. The implicit objects defined by the EL are shown in Table 2. An example of how to use some of these implicit objects is provided later.

Table 2: Implicit objects provided by the expression language
Implicit Object Content
applicationScope A collection of scoped variables from page scope
cookie A collection of all cookies
header HTTP request headers as strings
headerValues HTTP request headers as collections of strings
initParam A collection of all application parameter names
pageContext The javax.servlet.jspPageContext object for the current page
pageScope A collection of all page scope objects
param A collection of all request parameters as strings
paramValues All request parameters as collections of strings
requestScope A collection of all request scope objects
sessionScope A collection of all session scope objects

Twin Tag Libraries

For JSTL to support both the scripting and expression-language worlds, its designers came up with the concept of twin tag libraries. In other words, the JSTL tag library comes in two flavors that differ only in the way they support the use of runtime expressions for attribute values.

One library supports the request time expression values, and another supports the expression language. It is expected that most people will end up using the expression language (since it will be part of the JavaServer Pages 1.3 specification), but some may still prefer to use JSTL with scripting runtime (RT) expression values. The URIs of the RT-based tag libraries simply have the "_rt" suffix appended.

Table 3 lists each expression language-based tag library, with its recommended tag prefix and default URI, and Table 4 lists each runtime-based tag library with its recommended tag prefix and default URI.

Table 3: EL-based tag libraries
Functional Area URI Prefix
Core # c
XML Processing # x
Internationalization # fmt
Database Access # sql


Table 4: Runtime-based tag libraries
Functional Area URI Prefix
Core # c_rt
XML Processing # x_rt
Internationalization # fmt_rt
Database Access # sql_rt

Now, to use an EL-based JSTL library, you must declare the library using a taglib directive, similar to declaring a regular custom tag library:

<@ taglib prefix="c" uri="#">

Similarly, to use a runtime-based JSTL tag library, you must declare the library using a taglib directive:

<@ taglib prefix="c_rt" uri="#">

Once this is declared, you can use tags from that library with: <c:aTag>.

The Core Tag Library

The core tag library supports actions, including: output, manipulation of scoped variables, conditional logic, loops, URL manipulation, and error handling.

General Purpose Tags

Here are the general purpose tags for writing data, saving data to memory, deleting data, and handling errors: <c:out>, <c:set>, <c:remove>, and <c:catch>.

You can use <c:out> to write data, as in the following example:

The name of your city is: <c:out value="${customer.city}" default="unknown"/>

The <c:out> tag supports default values for cases where the EL expression is null. In this example, the value "unknown" will be displayed if the property city is not accessible.

Use <c:set> to set the value of a JSP scoped attribute as follows:

<c:set var="name" value="expression"/>

The <c:remove> tag is used to explicitly remove a scoped variable. For example:

<c:remove var="cache" scope="application/>

The <c:catch> tag allows page authors to recover gracefully from error conditions that they can control. See the next setion for an example.

Conditional Actions

The JSTL conditional actions support simple conditional execution (using <c:if>) and mutually exclusive conditional execution (using <c:choose>, <c:when>, and <c:otherwise>).

The <c:if> tag allows you to conditionally include a piece of the page, depending on runtime information. For example, the following snippet of code checks if a customer is based in Canada:

<c:if test="${customer.country == 'Canada'}">
   This customer is based in Canada.
</c:if>s

Here is another example that demonstrates the use of <c:if> with <c:catch>:

<c:catch var="exception">
  <!-- execution we can recover from. -->
  ...
</c:catch>
<c:if test="${exception != null}">
  Processing could not be performed. Here is why....
</c:if>

You can achieve the equivalent of an if/then/else statement with <c:choose>, <c:when>, and <c:otherwise>, as follows:

<c:choose>
  <c:when test="${customer.country == 'UK'}">
     UK has mild winters.
  </c:when>
  <c:when test="${customer.country == 'Canada'}">
     Canada has wild winters.
  </c:when>
  <c:when test="$customer.country == 'UAE'}">
     UAE has hot winters and good gold.
  </c:when>
  <c:otherwise>
     Country is unknown.
  </c:otherwise>
</c:choose>

Iteration Actions

Iterating over a collection of objects is a common task in JSP pages. The following snippet of code uses <c:forEach> to iterate over a list of customers:

<c:forEach var="customer" items="${customers}">
  Customer: <c:out value="${customer}"/>
</c:forEach>

The <c:forEach> tag allows iteration over a subset of the collection items. The begin and end indices can be specified for this, along with steps. Here is a simple example:

<c:forEach var="k" begin="1" end"100">
  <c:out value="${i % 2 == 0}"/>
</c:forEach>

As a more complete example, consider the following snippet of code, which prints all header parameters:

<%@ taglib prefix="c" uri="#" %>

<html>
<head>
  <title>JSTL Implicit Objects</title>
</head>
<body bgcolor="#FFFFCC">
<h3>Header info:</h3>

<c:forEach var="head" items="${headerValues}">
  param: <c:out value="${head.key}"/><br>
  values:
   <c:forEach var="val" items="${head.value}">
     <c:out value="${val}"/>
   </c:forEach>
   <p>
</c:forEach>

</body>
</html>

If you are, however, interested in a specific header (the User-Agent for example), you can retrieve that information using the following syntax: ${header['User-Agent']}.

URL Actions

The <jsp:include> action, in the JSP specification, provides for the inclusion of static and dynamic resources located in the same context as the current page. This action is widely used, but it doesn't allow page authors to include resources that are available remotely.

The JSTL provides a comprehensive set of actions for URL-related tasks. For example, you can use the <c:import> action to import local and remote resources. Here are some examples:

<c:import url="./copyright.html"/>
<c:import url="http://www.somewhere.com/hello.xml"/>

You can use the <c:url> action to take care of all URL rewriting tasks. It can be combined with the <c:param> action, which transparently encodes query-string parameters. Consider the following example, which rewrites and encodes a URL for user registration:

<c:url value="http://www.somewhere.com/customers/register" var="registrationURL">
  <c:param name="name" value="${param.name}"/>
  <c:param name="country" value="${param.country}"/>
</c:url>
<a href='<c:out value="${registrationURL}"/>'>Customer Registration>/a>

Finally, <c:redirect> (to support HTTP redirect) completes the list of URL-related actions. Here is an example:

<c:redirect url="http s://www.somewhere.com/register">

XML Tags

XML is becoming increasingly important to page authors, and the JSTL provides XML actions that address the basic needs of those developers. The XML actions can be divided into core, control flow, and transformation actions. The XML core actions are similar to those provided in the core actions discussed above, and include <x:out>, <x:set>, and <x:parse>. The main difference between the core actions discussed above and the XML core actions is that XML actions support XPath expressions, while the core actions do not. As a matter of fact, the XML actions are based on XPath expressions. If you're unfamiliar with XPath , it's a language for defining parts of an XML document; XPath uses path expressions to identify nodes in an XML document.

The XML control flow actions are the same as the core actions discussed above. They include: <x:if>, <x:choose>, <x:when>, <x:otherwise>, and <x:forEach>. The main difference is that you use the select attribute to specify XPath expressions. Here is an example:

<x:forEach select="$output/portfolio/stock">
  <x:out select="price"/>
</x:forEach>

Now, let's look at a set of examples that demonstrate the tags discussed so far. In Code Sample 1, xml-ex1.jsp uses the core and XML tag libraries to process an XML document. In this example, the XML document is embedded within the page and the <x:parse> tag is used to parse the document. Then, an XPath expression is used to select items from the document.

Code Sample 1: xml-ex1.jsp

<%@ taglib prefix="c" uri="#" %>
<%@ taglib prefix="x" uri="#" %>

<html>
<head>
  <title>JSTL Support for XML</title>
</head>
<body bgcolor="#FFFFCC">
<h3>Books Info:</h3>

<c:set var="xmltext">
  <books>
    <book>
      <title>Book Title A</title>
      <author>A. B. C.</author>
      <price>17.95</price>
    </book>
    <book>
      <title>Book Title B</title>
      <author>X. Y. Z.</author>
      <price>24.99</price>
    </book>
  </books>

</c:set>

<x:parse xml="${xmltext}" var="output"/>
<b>The title of the first book is</b>: 
<x:out select="$output/books/book[1]/title"/>
<br>
<b>The price of the second book</b>: 
<x:out select="$output/books/book[2]/price"/>
</body>
</html>

If you request xml-ex1.jsp, you'll see something like Figure 1.

 


Figure 1: JSTL support for XML

In the above example, the XML text is included within the JSP page. In a real application, however, the XML document would be hosted on a local or remote web server. You can import a remote resource by using the <c:import> tag. Consider the XML document shown in Code Sample 2, which is located at http://www.javacourses.com/stocks.xml.

Note: If you'd like to see how JSP pages can be used (and the amount of code involved) in processing stocks.xml, take a look at Web Application Development with JSP pages and XML.

Code Sample 2: stocks.xml

<?xml version="1.0" encoding="UTF-8"?>
<portfolio>
  <stock>
    <symbol>SUNW</symbol>
    <name>Sun Microsystems</name>
    <price>17.1</price>
  </stock>
  <stock>
    <symbol>AOL</symbol>
    <name>America Online</name>
    <price>51.05</price>
  </stock>
  <stock>
    <symbol>IBM</symbol>
    <name>International Business Machines</name>
    <price>116.10</price>
  </stock>
  <stock>
    <symbol>MOT</symbol>
    <name>Motorola</name>
    <price>15.20</price>
  </stock>
</portfolio>

This document can be imported using the following snippet of code:

<c:import url="http://www.javacourses.com/stocks.xml" var="xmldoc"/>

XML Conditional Logic

The conditional logic in the XML tag library is the same as the one in the core tag library. As an example, the following snippet of code parses an XML document, then selects (using an XPath expression) the stock with the symbol SUNW.

<x:parse xml="${xmldoc}" var="output"/>
<x:if select="$output/portfolio/stock[symbol = 'SUNW']">
   You still have Microsystems Stocks!
</x:if>

if/then/else

You can implement an if/then/else clause using the <x:choose> action, which selects one among a number of possible alternatives. It consists of a sequence of <x:when> elements, followed by an optional <x:otherwise>. Each <x:when> element has a single attribute, select, that specifies an XPath expression. When a <x:choose> element is processed, each of the <x:when> elements has its expressions evaluated in turn. Only the body of the first <x:when> element (whose result is true) is rendered. If none of the test conditions of nested tags evaluates to true, the body of the <x:otherwise> tag is evaluated, if present.

Here is an example:

<x:parse xml="${xmldoc}" var="output"/>

<x:choose>
  <x:when select="$output/portfolio/stock[price > '70']">
    You still have stocks worth over $70.
  </x:when>
  <x:otherwise>
    You have no stocks worth over $70.
  </x:otherwise>
</x:choose>

Iteration

The <x:forEach> action evaluates the given XPath expression, and iterates over the result. The example shown in Code Sample 3, xml-ex2.jsp, shows how to print stock information from an XML document.

Code Sample 3: xml-ex2.jsp

<%@ taglib prefix="c" uri="#" %>
<%@ taglib prefix="x" uri="#" %>

<html>
<head>
  <title>JSTL Support for XML</title>
</head>
<body bgcolor="#FFFFCC">
<h3>Portfolio</h3>

<c:import url="http://www.javacourses.com/stocks.xml" var="xmldoc"/>
<x:parse xml="${xmldoc}" var="output"/>

<p>

<table border="2" width="50%">
 <tr>
 <th>Stock Symbol</th>
 <th>Company Name</th>
 <th>Price</th>
 </tr>
 <tr>

<x:forEach select="$output/portfolio/stock" var="item">
  <td><x:out select="symbol"/></td>
  <td><x:out select="name"/></td>
  <td><x:out select="price"/></td></tr>
</x:forEach>
</table>

</body>
</html>

When you request this page, you will see something similar to Figure 2.


Figure 2: Importing and parsing an XML document, then iterating over its nodes

Transforming XML

Many web applications use XSLT stylesheets to transform XML within JSP pages, and the JSTL supports this. The XML document to be transformed, as well as the XSLT stylesheet to be used, can be retrieved from a relative, absolute, or remote URL. The result of the transformation is written to the page. As an example, the stocks.xml document shown in Code Sample 2 (which is located at a remote web server) is transformed using the XSLT stylesheet ( stocks.xsl) shown in Code Sample 4 but fetched from a local web server:

Code Sample 4: stocks.xsl

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl=
"http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="html" indent="yes"/>

<xsl:template match="/">
  <html>
  <body>
   <xsl:apply-templates/>
  </body>
  </html>
</xsl:template>

<xsl:template match="portfolio">
  <table border="2" width="50%">
    <xsl:for-each select="stock">
      <tr>
        <td>
          <i><xsl:value-of select="symbol"/></i>
        </td>
        <td>
          <xsl:value-of select="name"/>
        </td>
        <td>
          <xsl:value-of select="price"/>
        </td>
      </tr>
    </xsl:for-each>
  </table>
</xsl:template>
</xsl:stylesheet>

The following example, xml-ex3.jsp (shown in Code Sample 5) demonstrates how to transform an XML document located on a remote web server using the stocks.xsl stylesheet shown in Code Sample 4.

Code Sample 5: xml-ex3.jsp

<%@ taglib prefix="c" uri="#" %>
<%@ taglib prefix="x" uri="#" %>

<html>
<head>
  <title>JSTL: Importing XML Document</title>
</head>
<body bgcolor="#FFFFCC">
<h3>Transforming stocks.xml into HTML using stocks.xsl</h3>

<c:import url="http://www.javacourses.com/stocks.xml" var="xmldocument"/>
<c:import url="./stocks.xsl" var="xslt"/>
<x:transform xml="${xmldocument}" xslt="${xslt}"/>

</body>
</html>

When you load xml-ex3.jsp, you should see something in the browser similar to Figure 3.


Figure 3: Transforming an XML document using an XSLT stylesheet

Conclusion

The JavaServer Pages Standard Tag Library (JSTL) satisfies the demand for a set of standard JSP custom tags to handle common tasks needed by all JSP pages, including conditional processing, XML processing, internationalization, and database access. As you can see from this article, JSTL is easy to work with, and its reusable standard custom tags lead to faster development of web applications.

Now that you know the basics of the JSTL, you can explore the rest of the tag libraries on your own. Have fun!

For More Information

JavaServer Pages

JavaServer Pages Standard Tag Library

JSTL 1.0 Specification (JSR-52)

JSTL 1.0 Implementation

Acknowledgments

Special thanks to Pierre Delisle (Editor and Co-Lead of the JSTL Specification) at Sun Microsystems for his contributions to this article.

About the Author

Qusay H. Mahmoud provides Java consulting and training services. He has published dozens of articles on Java, and is the author of Distributed Programming with Java (Manning Publications, 1999) and Learning Wireless Java (O'Reilly, 2002).