Sunteți pe pagina 1din 46

A JSTL primer, Part 1: The expression language

Summary: The JSP Standard Tag Library (JSTL) is a collection of custom tag libraries that implement general-purpose functionality common to Web applications, including iteration and conditionalization, data management formatting, manipulation of XML, and database access. In this first installment of his new series on developerWorks, software engineer Mark Kolb shows you how to use JSTL tags to avoid using scripting elements in your JSP pages. You'll also learn how to simplify software maintenance by removing source code from the presentation layer. Finally, you'll learn about JSTL's simplified expression language, which allows dynamic attribute values to be specified for JSTL actions without having to use a full-blown programming language. JavaServer Pages (JSP) technology is the standard presentation-layer technology for the J2EE platform. JSP technology provides both scripting elements and actions for performing computations intended to generate page content dynamically. Scripting elements allow program source code to be included in a JSP page for execution when the page is rendered in response to a user request. Actions encapsulate computational operations into tags that more closely resemble the HTML or XML markup that typically comprises the template text of a JSP page. There are only a handful of actions defined as standard by the JSP specification, but starting with JSP 1.1, developers have been able to create their own actions in the form of custom tag libraries. The JSP Standard Tag Library (JSTL) is a collection of JSP 1.2 custom tag libraries that implement basic functionality common to a wide range of server-side Java applications. By providing standard implementations for typical presentation-layer tasks such as data formatting and iterative or conditional content, JSTL allows JSP authors to focus on application-specific development needs, rather than "reinventing the wheel" for these generic operations. Of course, you could implement such tasks using the JSP scripting elements: scriptlets, expressions, and declarations. Conditional content, for example, can be implemented using three scriptlets, highlighted in Listing 1. Because they rely on embedding program source code (typically Java code) within the page, though, scripting elements tend to complicate the software maintenance task significantly for JSP pages that use them. The scriptlet example in Listing 1, for instance, is critically dependent upon proper matching of braces. Nesting additional scriptlets within the conditionalized content can wreak havoc if a syntax error is inadvertently introduced, and it can be quite a challenge to make sense of the resulting error message when the page is compiled by the JSP container.

Listing 1. Implementing conditional content through scriptlets


<% if (user.getRole() == "member")) { %> <p>Welcome, member!</p> <% } else { %> <p>Welcome, guest!</p> <% } %>

Fixing such problems typically requires a fair bit of programming experience. Whereas the markup in a JSP page might typically be developed and maintained by a designer well-versed in page layout and graphic design, the scripting elements in that same page require the intervention of a programmer when problems arise. This shared responsibility for the code within a single file makes developing, debugging, and enhancing such JSP pages a cumbersome task. By packaging common functionality into a standardized set of custom tag libraries, JSTL allows JSP authors to reduce or eliminate the need for scripting elements and avoid the associated maintenance costs.

JSTL 1.0
Released in June 2002, JSTL 1.0 consists of four custom tag libraries (core, format, xml, and sql) and a pair of general-purpose tag library validators (ScriptFreeTLV and PermittedTaglibsTLV). The core tag library provides custom actions to manage data through scoped variables, as well as to perform iteration and conditionalization of page content. It also provides tags to generate and operate on

URLs. The format tag library, as its name suggests, defines actions to format data, specifically numbers and dates. It also provides support for internationalizing JSP pages using localized resource bundles. The xml library includes tags to manipulate data represented through XML, while the sql library defines actions to query relational databases. The two JSTL tag library validators allow developers to enforce coding standards within their JSP applications. You can configure the ScriptFreeTLV validator to prohibit the use of the various types of JSP scripting elements -- scriptlets, expressions, and declarations -- within a JSP page. Similarly, the PermittedTaglibsTLV validator can be used to restrict the set of custom tag libraries (including the JSTL tag libraries) that may be accessed by an application's JSP pages. While JSTL will eventually be a required component of the J2EE platform, only a small number of application servers include it today. The reference implementation for JSTL 1.0 is available as part of the Apache Software Foundation's Jakarta Taglibs project (see Resources). The custom tag libraries in the reference implementation can be incorporated into any application server supporting the JSP 1.2 and Servlet 2.3 specifications in order to add JSTL support. Back to top

Expression language
In JSP 1.2, the attributes of JSP actions are specified using either static character strings or, where permitted, expressions. In Listing 2, for example, static values are specified for the name and property attributes of this <jsp:setProperty> action, while an expression is used to specify its value attribute. This action has the effect of assigning the current value of a request parameter to the named bean property. Expressions used in this fashion are called request-time attribute values and are the only mechanism built into the JSP specification for specifying attribute values dynamically.

Listing 2. A JSP action incorporating a request-time attribute value


<jsp:setProperty name="user" property="timezonePref" value='<%= request.getParameter("timezone") %>'/>

Because request-time attribute values are specified using expressions, they are prone to the same software maintenance issues as other scripting elements. For this reason, the JSTL custom tags support an alternate mechanism for specifying dynamic attribute values. Rather than using full-blown JSP expressions, attribute values for JSTL actions can be specified using a simplified expression language (EL). The EL provides identifiers, accessors, and operators for retrieving and manipulating data resident in the JSP container. The EL is loosely based on EcmaScript (see Resources) and the XML Path Language (XPath), so its syntax should be familiar to both page designers and programmers. The EL is geared toward looking up objects and their properties, and performing simple operations on them; it is not a programming language, or even a scripting language. When combined with the JSTL tags, however, it enables complex behavior to be represented using a simple and convenient notation. EL expressions are delimited using a leading dollar sign ($) and both leading and trailing braces ({}), as highlighted in Listing 3.

Listing 3. A JSTL action illustrating the EL expression delimiters


<c:out value="${user.firstName}"/>

In addition, you can combine multiple expressions with static text to construct a dynamic attribute value through string concatenation, as highlighted in Listing 4. Individual expressions are comprised of identifiers, accessors, literals, and operators. Identifiers are used to reference data objects stored in the data center. The EL has 11 reserved identifiers, corresponding to 11 EL implicit objects. All other identifiers are assumed to refer to scoped variables. Accessors are used to retrieve the properties of an object or the elements of a collection. Literals represent fixed values -- numbers, character strings, booleans, or nulls. Operators allow data and literals to be combined and compared.

Listing 4. Combining static text and multiple EL expressions to specify a dynamic attribute value
<c:out value="Hello ${user.firstName} ${user.lastName}"/>

Back to top

Scoped variables
The JSP API, through the <jsp:useBean> action, allows data to be stored and retrieved from four different scopes within the JSP container. JSTL extends this capability by providing additional actions for assigning and removing objects within these scopes. Furthermore, the EL provides built-in support for retrieving these objects as scoped variables. In particular, any identifier appearing in an EL expression that does not correspond to one of the EL's implicit objects is automatically assumed to reference an object stored in one of the four JSP scopes: y Page scope y Request scope y Session scope y Application scope As you may recall, objects stored in page scope can only be retrieved during the processing of that page for a specific request. Objects stored in request scope can be retrieved during the processing of all pages taking part in the processing of a request (such as if the processing of a request encounters one or more <jsp:include> or <jsp:forward> actions). If an object is stored in session scope, it can be retrieved by any pages accessed by a user during a single interactive session with the Web application (that is, until the HttpSession object associated with that user's interaction is invalidated). An object stored in application scope is accessible from all pages and for all users, until the Web application itself is unloaded (typically as a result of the JSP container being shut down). An object is stored in a scope by mapping a character string to the object within the desired scope. You can then retrieve the object from the scope by providing the same character string. The string is looked up in the scope's mapping, and the mapped object is returned. Within the Servlet API, such objects are referred to as attributes of the corresponding scope. In the context of the EL, however, the character string associated with an attribute can also be thought of as the name of a variable, which is bound to a particular value by means of the attribute mappings. In the EL, identifiers not associated with implicit objects are assumed to name objects stored in the four JSP scopes. Any such identifier is first checked against page scope, then request scope, then session scope, and finally application scope, successively testing whether the name of the identifier matches the name of an object stored in that scope. The first such match is returned as the value of the EL identifier. It is in this way that EL identifiers can be thought of as referencing scoped variables. In more technical terms, identifiers that do not map to implicit objects are evaluated using the findAttribute() method of thePageContext instance representing the processing of the page on which the expression occurs for the request currently being handled. The name of the identifier is passed as the argument to this method, which searches each of the four scopes in turn for an attribute with the same name. The first match found is returned as the value of the findAttribute() method. If no such attribute is located in any of the four scopes, null is returned. Ultimately, then, scoped variables are attributes of the four JSP scopes that have names that can be used as EL identifiers. As long as they are assigned alphanumeric names, scoped variables can be created by any of the mechanisms present in JSP for setting attributes. This includes the builtin <jsp:useBean> action, as well as the setAttribute() method defined by several of the classes in the Servlet API. In addition, many of the custom tags defined in the four JSTL libraries are themselves capable of setting attribute values for use as scoped variables. Back to top

Implicit objects
The identifiers for the 11 EL implicit objects are listed in Table 1. Don't confuse these with the JSP implicit objects (of which there are only nine), as only one object is common to both. Table 1. The EL implicit objects

Category

Identifier

Description

JSP

pageContext

The PageContext instance corresponding to the processing of the current page

Scopes

pageScope

A Map associating the names and values of page-scoped attributes

requestScope

A Map associating the names and values of requestscoped attributes

sessionScope

A Map associating the names and values of sessionscoped attributes

applicationScope A Map associating the names and values of applicationscoped attributes

Request parameters

param

A Map storing the primary values of the request parameters by name

paramValues

A Map storing all values of the request parameters as String arrays

Request headers

header

A Map storing the primary values of the request headers by name

headerValues

A Map storing all values of the request headers as String arrays

Cookies

cookie

A Map storing the cookies accompanying the request by name

Initialization parameters

initParam

A Map storing the context initialization parameters of the Web application by name

While JSP and EL implicit objects have only one object in common (pageContext), other JSP implicit objects are still accessible from the EL. The reason is that pageContext has properties for accessing all of the other eight JSP implicit objects. Indeed, this is the primary reason for including it among the EL implicit objects. All of the remaining EL implicit objects are maps, which may be used to look up objects corresponding to a name. The first four maps represent the various attribute scopes discussed previously. They can be used to

look up identifiers in specific scopes, rather than relying on the sequential lookup process that the EL uses by default. The next four maps are for fetching the values of request parameters and headers. Since the HTTP protocol allows both request parameters and headers to be multi-valued, there is a pair of maps for each. The first map in each pair simply returns the primary value for the request parameter or header, typically whichever value happens to have been specified first in the actual request. The second map in each pair allows all of a parameter's or header's values to be retrieved. The keys in these maps are the names of the parameters or headers, while the values are arrays of String objects, each element of which is a single parameter or header value. The cookie implicit object provides access to the cookies set by a request. This object maps the names of all the cookies associated with a request to Cookie objects representing the properties of those cookies. The final EL implicit object, initParam, is a map storing the names and values of any context initialization parameters associated with the Web application. Initialization parameters are specified through the web.xml deployment descriptor file that appears in the application's WEB-INF directory. Back to top

Accessors
Since EL identifiers are resolved either as implicit objects or as scoped variables (which are implemented through attributes), they will by necessity evaluate to Java objects. The EL can automatically wrap and unwrap primitives in their corresponding Java classes (for instance, int can be coerced into an Integer class behind the scenes, and vice versa), but identifiers for the most part will be pointers to full-blown Java objects. As a result, it's often desirable to access the properties of these objects or, in the case of arrays and collections, their elements. The EL provides two different accessors for just this purpose -- the dot operator (.) and the bracket operator ([]) -- enabling properties and elements to be operated upon through the EL, as well. The dot operator is typically used for accessing the properties of an object. In the expression ${user.firstName}, for example, the dot operator is used to access the property named firstName of the object referenced by the user identifier. The EL accesses object properties using the Java beans conventions, so a getter for this property (typically a method namedgetFirstName()) must be defined in order for this expression to evaluate correctly. When the property being accessed is itself an object, the dot operator can be applied recursively. For instance, if our hypothetical user object has an address property that is implemented as a Java object, then the dot operator can also be used to access the properties of this object. The expression${user.address.city}, for example, will return the nested city property of this address object. The bracket operator is used to retrieve elements of arrays and collections. In the case of arrays and ordered collections (that is, collections implementing the java.util.List interface), the index of the element to be retrieved appears inside the brackets. For example, the expression ${urls[3]} returns the fourth element of the array or collection referenced by the urls identifier (indices are zero-based in the EL, just as in the Java language and JavaScript). For collections implementing the java.util.Map interface, the bracket operator looks up a value stored in the map using the associated key. The key is specified inside the brackets, and the corresponding value is returned as the value of the expression. For example, the expression ${commands["dir"]} returns the value associated with the "dir" key in the Map referenced by thecommands identifier. In either case, it is permissible for an expression to appear inside the brackets. The result of evaluating the nested expression will serve as the index or key for retrieving the appropriate element of the collection or array. As was true of the dot operator, the bracket operator can be applied recursively. This allows the EL to retrieve elements from multi-dimensional arrays, nested collections, or any combination of the two. Furthermore, the dot operator and the bracket operator are interoperable. For example, if the elements of an array are themselves objects, the bracket operator can be used to retrieve an element of the array and be combined with the dot operator to retrieve one of the element's properties (for instance, ${urls[3].protocol}). Given the EL's role as a simplified language for specifying dynamic attribute values, one interesting feature of the EL accessors is that, unlike the Java language's accessors, they do not throw exceptions when applied to null. If the object to which an EL accessor is applied (for instance, the foo identifier in both ${foo.bar} and ${foo["bar"]}) is null, then the result of applying the accessor will also be null. This turns out to be rather helpful behavior under most circumstances, as you'll see shortly. Finally, the dot operator and the bracket operator are somewhat interchangeable. For example, ${user["firstName"]} could also be used to retrieve the firstName property of

the user object, just as ${commands.dir} could be used to fetch the value associated with the "dir" key in the commands map. Back to top

Operators
Using identifiers and accessors, then, the EL is able to traverse object hierarchies containing either application data (exposed through scoped variables) or information about the environment (through the EL implicit objects). Simply accessing such data, however, is often inadequate for implementing the presentation logic needed by many JSP applications. To this end, the EL also includes several operators to manipulate and compare data accessed by EL expressions. These operators are summarized in Table 2. Table 2. The EL operators

Category

Operators

Arithmetic

+, -, *, / (or div), % (or mod)

Relational

== (or eq), != (or ne), < (or lt), > (or gt), <= (or le), >= (or ge)

Logical

&& (or and), || (or or), ! (or not)

Validation

empty

The arithmetic operators support addition, subtraction, multiplication, and division of numeric values. A remainder operator is also provided. Note that the division and remainder operators have alternate, nonsymbolic names (in order to be consistent with XPath). An example expression demonstrating the use of the arithmetic operators is shown in Listing 5. The result of applying an arithmetic operator to a pair of EL expressions is the result of applying that operator to the numeric values returned by those expressions.

Listing 5. An EL expression utilizing arithmetic operators


${item.price * (1 + taxRate[user.address.zipcode])}

The relational operators allow you to compare either numeric or textual data. The result of the comparison is returned as a boolean value. The logical operators allow boolean values to be combined, returning a new boolean value. The EL logical operators can therefore be applied to the results of nested relational or logical operators, as demonstrated in Listing 6.

Listing 6. An EL expression utilizing relational and logical operators


${(x >= min) && (x <= max)}

The final EL operator is empty, which is particularly useful for validating data. The empty operator takes a single expression as its argument (that is, ${empty input}), and returns a boolean value indicating whether or not the expression evaluates to an "empty" value. Expressions that evaluate to null are

considered empty, as are collections or arrays with no elements. Theempty operator will also return true if its argument evaluates to a String of zero length. Operator precedence for the EL operators is shown in Table 3. As suggested in Listings 5 and 6, parentheses may be used to group expressions and override the normal precedence rules. Table 3. EL operator precedence (top to bottom, left to right)

[], .

()

unary -, not, !, empty

*, /, div, %, mod

+, binary -

() <, >, <=, >=, lt, gt, le, ge

==, !=, eq, ne

&&, and

||, or
Back to top

Literals
Numbers, character strings, booleans, and nulls can all be specified as literal values in EL expressions. Character strings are delimited by either single or double quotes. Boolean values are designated by true and false. Back to top

Taglib directives
As we discussed earlier, JSTL 1.0 includes four custom tag libraries. To illustrate the interaction of JSTL tags with the expression language, we will look at several of the tags from the JSTL core library. As is true with any JSP custom tag library, ataglib directive must be included in any page that you want to be able to use this library's tags. The directive for this specific library appears in Listing 7.

Listing 7. The taglib directive for the EL version of the JSTL core library
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>

Actually, there are two taglib directives that correspond to the JSTL core library because in JSTL 1.0 the EL is optional. All four of the JSTL 1.0 custom tag libraries have alternate versions that use JSP

expressions rather than the EL for specifying dynamic attribute values. Because these alternate libraries rely on JSP's more traditional request-time attribute values, they are referred to as the RT libraries, whereas those using the expression language are referred to as the EL libraries. Developers distinguish between the two versions of each library using alternate taglib directives. The directive for using the RT version of the core library is shown in Listing 8. Given our current focus on the EL, however, it is the first of these directives that is needed.

Listing 8. The taglib directive for the RT version of the JSTL core library
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c_rt" %>

Back to top

Variable tags
The first JSTL custom tag we will consider is the <c:set> action. As already indicated, scoped variables play a key role in JSTL, and the <c:set> action provides a tag-based mechanism for creating and setting scoped variables. The syntax for this action is shown in Listing 9, where the var attribute specifies the name of the scoped variable, the scope attribute indicates which scope the variable resides in, and the value attribute specifies the value to be bound to the variable. If the specified variable already exists, it will simply be assigned the indicated value. If not, a new scoped variable is created and initialized to that value.

Listing 9. Syntax for the <c:set> action


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

The scope attribute is optional and defaults to page. Two examples of the <c:set> are presented in Listing 10. In the first example, a session-scoped variable is set to a Stringvalue. In the second, an expression is used to set a numeric value: a page-scoped variable named square is assigned the result of multiplying the value of a request parameter named x by itself.

Listing 10. Examples of the <c:set> action


<c:set var="timezone" scope="session" value="CST"/> <c:set var="square" value="${param['x'] * param['x']}"/>

Rather than using an attribute, you can also specify the value for the scoped variable as the body content of the <c:set> action. Using this approach, you could rewrite the first example in Listing 10 as shown in Listing 11. Furthermore, as we will see momentarily, it's acceptable for the body content of the <c:set> tag to employ custom tags itself. All content generated within the body of <c:set> will be assigned to the specified variable as a String value.

Listing 11. Specifying the value for the <c:set> action through body content
<c:set var="timezone" scope="session">CST</c:set>

The JSTL core library includes a second tag for managing scoped variables, <c:remove>. As its name suggests, the<c:remove> action is used to delete a scoped variable, and takes two attributes. The var attribute names the variable to be removed, and the optional scope attribute indicates the scope from which it should be removed and defaults to page, as shown in Listing 12.

Listing 12. An example of the <c:remove> action


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

Back to top

Output
While the <c:set> action allows the result of an expression to be assigned to a scoped variable, a developer will often want to simply display the value of an expression, rather than store it. This is the role of JSTL's <c:out> custom tag, the syntax of which appears in Listing 13. This tag evaluates the expression specified by its value attribute, then prints the result. If the optionaldefault attribute is specified, the <c:out> action will instead print its value if the value attribute's expression evaluates either to null or an empty String.

Listing 13. Syntax for the <c:out> action


<c:out value="expression" default="expression" escapeXml="boolean"/>

The escapeXml attribute is also optional. It controls whether or not characters such as "<", ">", and "&", which have special meanings in both HTML and XML, should be escaped when output by the <c:out> tag. If escapeXml is set to true, then these characters will automatically be translated into the corresponding XML entities (<, >, and &, respectively, for the characters mentioned here). For instance, suppose there is a session-scoped variable named user that is an instance of a class that defines two properties for users, username and company. This object is automatically assigned to the session whenever a user accesses the site, but the two properties are not set until the user actually logs in. Given this scenario, consider the JSP fragment shown in Listing 14. Once the user has logged in, this fragment will display the word "Hello," followed by his or her username and an exclamation point. Before the user has logged in, however, the content generated by this fragment will instead be the phrase, "Hello Guest!" In this case, because the username property has yet to be initialized, the <c:out> tag will instead print out the value of itsdefault attribute (that is, the character string, "Guest").

Listing 14. An example of the <c:out> action with default content


Hello <c:out value="${user.username}" default="Guest"/>!

Next, consider Listing 15, which uses the <c:out> tag's escapeXml attribute. If the company property has in this case been set to the Java String value "Flynn & Sons", then the content generated by this action will, in fact, be Flynn & Sons. If this action is part of a JSP page generating HTML or XML

content, then the ampersand in the middle of this string of characters may end up being interpreted as an HTML or XML control character and interrupt the rendering or parsing of this content. If the value of theescapeXml attribute is instead set to true, however, the generated content will instead be Flynn & Sons. A browser or parser encountering this content should have no problems with its interpretation. Given that HTML and XML are the most common content types in JSP applications, it should come as little surprise that the default value for the escapeXml attribute is true.

Listing 15. An example of the <c:out> action with escaping disabled


<c:out value="${user.company}" escapeXml="false"/>

Back to top

Setting variables with default values


In addition to simplifying the display of dynamic data, the ability of <c:out> to specify a default value is also useful when setting variable values through <c:set>. As highlighted in Listing 11, the value to be assigned to a scoped variable can be specified as the body content of the <c:set> tag, as well as through its value attribute. By nesting a <c:out> action in the body content of a<c:set> tag, the variable assignment can leverage its default value capability. This approach is illustrated in Listing 16. The behavior of the outer <c:set> tag is straightforward enough: it sets the value of the session-scope timezone variable based on its body content. In this case, however, that body content is generated through a<c:out> action. The value attribute of this nested action is the expression ${cookie['tzPref'].value}, which attempts to return the value of a cookie named tzPref by means of the cookie implicit object. (The cookie implicit object maps cookie names to corresponding Cookie instances, which means you must use the dot operator to retrieve the actual data stored in the cookie through the object's value property.)

Listing 16. Combining <c:set> and <c:out> to provide default variable values
<c:set var="timezone" scope=="session"> <c:out value="${cookie['tzPref'].value}" default="CST"/> </c:set>

Consider the case, however, in which this is the user's first experience with the Web application using this code. As a result, there is no cookie named tzPref provided in the request. This means the lookup using the implicit object will return null, in which case the expression as a whole will return null. Since the result of evaluating its value attribute is null, the <c:out> tag will instead output the result of evaluating its default attribute. Here, this is the character string CST. The net effect, then, is that the timezone scoped variable will be set to the time zone stored in the user's tzPref cookie or, if none is present, use a default time zone of CST.

The EL and JSP 2.0

For now, the expression language is only available for specifying dynamic attribute values in JSTL custom tags. An extension of the JSTL 1.0 expression language has been proposed, however, for inclusion in the JSP 2.0 specification, now undergoing final review. This extension will allow developers to leverage the EL with their own custom tags. Page authors will be able to use EL expressions anywhere they are currently allowed to use JSP expressions, such as to insert dynamic values into template text:
This JSP 2.0 feature will, like JSTL itself, enable page authors to further reduce their dependence on JSP scripting elements, leading to improved maintainability for JSP applications.

Back to top

Summary
The EL, in concert with the actions provided by the four JSTL custom tag libraries, allows page authors to implement presentation-layer logic without resorting to scripting elements. Contrast, for example, the JSP code in Listing 1 at the beginning of this article with the same functionality as implemented through the JSTL highlighted in Listing 17. (The remaining tags in the JSTL core library, including <c:choose> and its children will be covered in the next article in this series.) Although it is still clear that conditional logic is being performed, the JSTL version has no Java language source code in it, and the relationships between the tags -- particularly with respect to nesting requirements -- should be familiar to anyone comfortable with HTML syntax.

Listing 17. Implementing conditional content via JSTL


<c:choose><c:when test="${user.role == 'member'}"> <p>Welcome, member!</p> </c:when><c:otherwise> <p>Welcome, guest!</p> </c:otherwise></c:choose>

By providing standard implementations of functionality common to most Web applications, JSTL helps accelerate the development cycle. In concert with the EL, JSTL can remove the need for program code in the presentation layer, greatly simplifying the maintenance of JSP applications.

A JSTL primer, Part 2: Getting down to the core


In the initial article of this series, you got your first look at JSTL. We described the use of its expression language (EL) to access data and operate on it. As you learned, the EL is used to assign dynamic values to the attributes of JSTL custom tags, and thus plays the same role as JSP expressions for specifying requesttime attribute values for the built-in actions and other custom tag libraries. To demonstrate the use of the EL, we introduced three tags from the core library: <c:set>, <c:remove>, and <c:out>.<c:set> and <c:remove> are used for managing scoped variables; <c:out> is for displaying data, particularly values computed using the EL. Based on this groundwork, then, we will focus our attention in this article on the remaining tags in thecore library, which can be broadly grouped into two major categories: flow control and URL management.

Example application
To demonstrate the JSTL tags, we'll use examples from a working application for the remaining articles in this series. Because of their growing popularity and familiarity, we'll use a simple Java-based Weblog for this purpose; see Resources to download the JSP pages and source code for this application. A Weblog (also known as a blog) is a Web-based journal of short commentaries on topics of interest to the Weblog's author, typically with links to related articles or discussions elsewhere on the Web. A screenshot of the running application is shown in Figure 1.

Figure 1. The Weblog application XML error: The image is not displayed because the width is greater than the maximum of 580 pixels. Please decrease the image width.

Although a couple dozen Java classes are required for the full implementation, only two of the Weblog application's classes,Entry and UserBean, are referenced in the presentation layer. To understand the JSTL examples, then, only these two classes are important. A class diagram for Entry and UserBean is shown in Figure 2.

Figure 2. Class diagram for the Weblog application

The Entry class represents a dated entry within a Weblog. Its id attribute is used to store and retrieve the entry in a database, while the title and text attributes represent the entry's actual content. Two instances of the Java language's Date class are referenced by the created and lastModified attributes, representing when the entry was first created and last edited. Theauthor attribute references a UserBean instance identifying the person who created the entry. The UserBean class stores information about the application's authenticated users, such as user name, full name, and e-mail address. This class also includes an id attribute for interacting with an associated database. Its final attribute, roles, references a list of String values identifying the application-specific roles associated with the corresponding user. For the Weblog application, the relevant roles are "User" (the default role common to all application users) and "Author" (the role that designates users who are allowed to create and edit Weblog entries). Back to top

Flow control
Because the EL can be used in place of JSP expressions to specify dynamic attribute values, it reduces the need for page authors to use scripting elements. Because scripting elements can be a significant source of maintenance problems in JSP pages, providing simple (and standard) alternatives to their use is a major advantage of JSTL. The EL retrieves data from the JSP container, traverses object hierarchies, and performs simple operations on the results. In addition to accessing and manipulating data, however, another common use of JSP scripting elements is flow control. In particular, it is fairly common for page authors to resort to scriptlets to implement iterative or conditional content. However, because such operations are beyond the capabilities of the EL, the core library instead provides several custom actions to manage flow control in the form of iteration, conditionalization, and exception handling.

Iteration
In the context of Web applications, iteration is primarily used to fetch and display collections of data, typically in the form of a list or sequence of rows in a table. The primary JSTL action for implementing iterative content is the <c:forEach> custom tag. This tag supports two different styles of iteration: iteration over an integer range (like the Java language's for statement) and iteration over a collection (like the Java language's Iterator and Enumeration classes). To iterate over a range of integers, the syntax of the <c:forEach> tag shown in Listing 1 is used. The begin and end attributes should be either static integer values or expressions evaluating to integer values. They specify the initial value of the index for the iteration and the index value at which iteration should cease, respectively. When iterating over a range of integers using<c:forEach>, these two attributes are required and all others are optional.

Listing 1. Syntax for numerical iteration through the <c:forEach> action


<c:forEach var="name" varStatus="name" begin="expression" end="expression" step="expression"> body content </c:forEach>

The step attribute, when present, must also have an integer value. It specifies the amount to be added to the index after each iteration. The index of the iteration thus starts at the value of the begin attribute, is incremented by the value of the step attribute, and halts iteration when it exceeds the value of the end attribute. Note that if the step attribute is omitted, the step size defaults to 1. If the var attribute is specified, then a scoped variable with the indicated name will be created and assigned the current value of the index for each pass through the iteration. This scoped variable has nested visibility -it can only be accessed within the body of the <c:forEach> tag. (We'll discuss the use of the optional varStatus attribute shortly.) Listing 2 shows an example of the<c:forEach> action for iterating over a fixed set of integer values.

Listing 2. Using the <c:forEach> tag to generate tabular data corresponding to a range of numeric values
<table> <tr><th>Value</th> <th>Square</th></tr> <c:forEach var="x" begin="0" end="10" step="2"> <tr><td><c:out value="${x}"/></td> <td><c:out value="${x * x}"/></td></tr> </c:forEach> </table>

This example code generates a table of the squares of the first five even numbers, as shown in Figure 3. This is accomplished by specifying a value of two for both the begin and step attributes, and a value of ten for the end attribute. In addition, the varattribute is used to create a scoped variable for storing the index value, which is referenced within the body of the <c:forEach>tag. Specifically, a pair of <c:out> actions are used to display the index and its square, the latter of which is computed using a simple expression.

Figure 3. Output of Listing 2

When iterating over the members of a collection, one additional attribute of the <c:forEach> tag is used: the items attribute, which is shown in Listing 3. When you use this form of the <c:forEach> tag, the items attribute is the only required attribute. The value of the items attribute should be the collection over whose members the iteration is to occur, and is typically specified using an EL expression. If a variable name is specified through the <c:forEach> tag's item attribute, then the named variable will be bound to successive elements of the collection for each iteration pass.

Listing 3. Syntax for iterating through a collection through the <c:forEach> action
<c:forEach var="name" items="expression" varStatus="name" begin="expression" end="expression" step="expression"> body content </c:forEach>

All of the standard collection types provided by the Java platform are supported by the <c:forEach> tag. In addition, you can use this action to iterate through the elements of an array, including arrays of primitives. Table 1 contains a complete list of the values supported by the items attribute. As the final row of the table indicates, JSTL defines its own interface,javax.servlet.jsp.jstl.sql.Result, for iterating through the result of an SQL query. (We'll present further details on this capability in a later article in this series.) Table 1. Collections supported by the items attribute of the <c:forEach> tag

Value for items

Resulting item values Elements from call to iterator() Instances of java.util.Map.Entry Iterator elements Enumeration elements Array elements Wrapped array elements Substrings Rows from an SQL query

java.util.Collection java.util.Map java.util.Iterator java.util.Enumeration


Array of Object instances Array of primitive values Comma-delimited String

javax.servlet.jsp.jstl.sql.Result

You can use the begin, end, and step attributes to restrict which elements of the collection are included in the iteration. As was the case for numerical iteration through <c:forEach>, an iteration index is also maintained when iterating through the elements of a collection. Only those elements that correspond to index values matching the specified begin, end, and step values will actually be processed by the <c:forEach> tag. Listing 4 shows the <c:forEach> tag being used to iterate through a collection. For this JSP fragment, a scoped variable named entryList has been set to a list (specifically, an ArrayList) of Entry objects. The <c:forEach> tag processes each element of this list in turn, assigning it to a scoped variable named blogEntry, and generating two table rows -- one for the Weblog entry's title and a second for its text. These properties are retrieved from the blogEntry variable through a pair of<c:out> actions with corresponding EL expressions. Note that, because both the title and text of a Weblog entry might contain HTML markup, the escapeXml attribute of both <c:out> tags is set to false. Figure 4 shows the result.

Listing 4. Displaying the Weblog entries for a given date using the <c:forEach> tag
<table> <c:forEach items="${entryList}" var="blogEntry"> <tr><td align="left" class="blogTitle"> <c:out value="${blogEntry.title}" escapeXml="false"/> </td></tr> <tr><td align="left" class="blogText">

<c:out value="${blogEntry.text}" escapeXml="false"/> </td></tr> </c:forEach> </table>

Figure 4. Output of Listing 4 XML error: The image is not displayed because the width is greater than the maximum of 580 pixels. Please decrease the image width.

The remaining <c:forEach> attribute, varStatus, plays the same role whether iterating over integers or collections. Like thevar attribute, varStatus is used to create a scoped variable. Instead of storing the current index value or the current element, however, the variable named by the varStatus attribute is assigned an instance of thejavax.servlet.jsp.jstl.core.LoopTagStatus class. This class defines a set of properties, listed in Table 2, that describe the current state of an iteration. Table 2. Properties of the LoopTagStatus object

Property Getter current index count first

Description

getCurrent() The item (from the collection) for the current round of iteration getIndex() getCount() isFirst()
The zero-based index for the current round of iteration The one-based count for the current round of iteration Flag indicating whether the current round is the first pass through the iteration Flag indicating whether the current round is the last pass through the iteration The value of the begin attribute The value of the end attribute The value of the step attribute

last

isLast()

begin end step

getBegin() getEnd() getStep()

Listing 5 shows an example of how the varStatus attribute is used. It modifies the code in Listing 4 to add numbering of the Weblog entries to the table rows displaying their titles. This is done by specifying a value for the varStatus attribute and then accessing the count property of the resulting scoped variable. The results appear in Figure 5.

Listing 5. Using the varStatus attribute to display a count of Weblog entries


<table> <c:forEach items= "${entryList}" var="blogEntry" varStatus="status"> <tr><td align="left" class="blogTitle"> <c:out value="${status.count}"/>. <c:out value="${blogEntry.title}" escapeXml="false"/> </td></tr> <tr><td align="left" class="blogText"> <c:out value="${blogEntry.text}" escapeXml="false"/> </td></tr> </c:forEach>

</table>

Figure 5. Output of Listing 5 XML error: The image is not displayed because the width is greater than the maximum of 580 pixels. Please decrease the image width.

In addition to <c:forEach>, the core library provides a second iteration tag: <c:forTokens>. This custom action is the JSTL analog of the Java language's StringTokenizer class. The <c:forTokens> tag, shown in Listing 6, has the same set of attributes as the collection-oriented version of <c:forEach>, with one addition. For <c:forTokens>, the string to be tokenized is specified through the items attribute, while the set of delimiters used to generate the tokens is provided through the delimsattribute. As was the case for <c:forEach>, you can use the begin, end, and step attributes to restrict the tokens to be processed to those matching the corresponding index values.

Listing 6. Syntax for iterating through a string's tokens with the <c:forTokens> action
<c:forTokens var="name" items="expression" delims="expression" varStatus="name" begin="expression" end="expression" step="expression"> body content </c:forTokens>

Conditionalization
For Web pages containing dynamic content, you might want different categories of users to see different forms of content. In our Weblog, for instance, visitors should be able to read entries and perhaps submit feedback, but only authorized users should be able to post new entries or edit existing content. Both usability and software maintenance are often improved by implementing such features within the same JSP page and then using conditional logic to control what gets displayed on a per-request basis. The core library provides two different conditionalization tags -- <c:if> and <c:choose> -- to implement these features. The more straightforward of these two actions, <c:if>, simply evaluates a single test expression and then processes its body content only if that expression evaluates to true. If not, the tag's body content is ignored. As Listing 7 shows, <c:if> can optionally assign the result of the test to a scoped variable through its var and scope attributes (which play the same role here as they do for <c:set>). This capability is particularly useful if the test is expensive: the result can be cached in a scoped variable and retrieved in subsequent calls to <c:if> or other JSTL tags.

Listing 7. Syntax for the <c:if> conditional action


<c:if test="expression" var="name" scope="scope"> body content </c:if>

Listing 8 shows <c:if> used with the first property of a <c:forEach> tag's LoopTagStatus object. In this case, as shown in Figure 6, the creation date for a set of Weblog entries is displayed just above the first entry for that date, but is not repeated before any of the other entries.

Listing 8. Using <c:if> to display the date for Weblog entries

<table> <c:forEach items= "${entryList}" var="blogEntry" varStatus="status"> <c:if test="${status.first}"> <tr><td align="left" class="blogDate"> <c:out value="${blogEntry.created}"/> </td></tr> </c:if> <tr><td align="left" class="blogTitle"> <c:out value="${blogEntry.title}" escapeXml="false"/> </td></tr> <tr><td align="left" class="blogText"> <c:out value="${blogEntry.text}" escapeXml="false"/> </td></tr> </c:forEach> </table>

Figure 6. Output of Listing 8 XML error: The image is not displayed because the width is greater than the maximum of 580 pixels. Please decrease the image width.

As Listing 8 shows, the <c:if> tag provides a very compact notation for simple cases of conditionalized content. For cases in which mutually exclusive tests are required to determine what content should be displayed, the JSTL core library also provides the <c:choose> action. The syntax for <c:choose> is shown in Listing 9.

Listing 9. Syntax for the <c:choose> action


<c:choose> <c:when test="expression"> body content </c:when> ... <c:otherwise> body content </c:otherwise> </c:choose>

Each condition to be tested is represented by a corresponding <c:when> tag, of which there must be at least one. Only the body content of the first <c:when> tag whose test evaluates to true will be processed. If none of the <c:when> tests return true, then the body content of the <c:otherwise> tag will be processed. Note, though, that the <c:otherwise> tag is optional; a<c:choose> tag can have at most one nested <c:otherwise> tag. If all <c:when> tests are false and no <c:otherwise>action is present, then no <c:choose> body content will be processed. Listing 10 shows an example of the <c:choose> tag in action. Here, protocol information is retrieved from the request object (by means of the EL's pageContext implicit object) and tested using a simple string comparison. Based on the results of these tests, a corresponding text message is displayed.

Listing 10. Content conditionalization using <c:choose>


<c:choose> <c:when test="${pageContext.request.scheme eq 'http'}"> This is an insecure Web session. </c:when>

<c:when test="${pageContext.request.scheme eq 'https'}"> This is a secure Web session. </c:when> <c:otherwise> You are using an unrecognized Web protocol. How did this happen?! </c:otherwise> </c:choose>

Exception handling
The final flow-control tag is <c:catch>, which allows for rudimentary exception handling within a JSP page. More specifically, any exceptions raised within the body content of this tag will be caught and ignored (that is, the standard JSP error-handling mechanism will not be invoked). However, if an exception is raised and the <c:catch> tag's optional var attribute has been specified, the exception will be assigned to the specified variable (with page scope), enabling custom error handling within the page itself. Listing 11 shows the syntax of <c:catch> (an example appears later in Listing 18).

Listing 11. Syntax for the <c:catch> action


<c:catch var="name"> body content </c:catch>

Back to top

URL actions
The remaining tags in the JSTL core library focus on URLs. The first of these, the aptly named <c:url> tag, is used to generate URLs. In particular, <c:url> provides three elements of functionality that are particularly important when constructing URLs for J2EE Web applications: y Prepending the name of the current servlet context y URL re-writing for session management y URL encoding of request-parameter names and values Listing 12 shows the syntax for the <c:url> tag. The value attribute is used to specify a base URL, which the tag then transforms as necessary. If this base URL starts with a forward slash, then a servlet context name will be prepended. An explicit context name can be provided using the context attribute. If this attribute is omitted, then the name of the current servlet context will be used. This is particularly useful because servlet context names are decided during deployment, rather than during development. (If the base URL does not start with a forward slash, then it is assumed to be a relative URL, in which case the addition of a context name is unnecessary.)

Listing 12. Syntax for the <c:url> action


<c:url value="expression" context="expression" var="name" scope="scope"> <c:param name="expression" value="expression"/> ... </c:url>

URL rewriting is automatically performed by the <c:url> action. If the JSP container detects a cookie storing the user's current session ID, no rewriting is necessary. If no such cookie is present, however, all URLs generated by <c:url> will be rewritten to encode the session ID. Note that if an appropriate cookie is present in subsequent requests, <c:url> will stop rewriting URLs to include this ID. If a value is supplied for the var attribute (optionally accompanied by a corresponding value for the scope attribute), the generated URL will be assigned as the value of the specified scoped variable. Otherwise, the resulting URL will be output using the current JspWriter. This ability to directly output its result allows the <c:url> tag to appear as the value, for example, of thehref attribute of an HTML <a> tag, as shown in Listing 13.

Listing 13. Generating a URL as the attribute value for an HTML tag
<a href="<c:url value='/content/sitemap.jsp'/>">View sitemap</a>

Finally, if any request parameters are specified through nested <c:param> tags, then their names and values will be appended to the generated URL using the standard notation for HTTP GET requests. In addition, URL encoding is performed: any characters present in either the names or values of these parameters that must be transformed in order to yield a valid URL will be translated appropriately. Listing 14 illustrates the behavior of <c:url>.

Listing 14. Generating a URL with request parameters


<c:url value="/content/search.jsp"> <c:param name="keyword" value="${searchTerm}"/> <c:param name="month" value="02/2003"/> </c:url>

The JSP code in Listing 14 has been deployed to a servlet context named blog, and the value of the scoped variablesearchTerm has been set to "core library". If a session cookie has been detected, then the URL generated by Listing 14 will be like the one in Listing 15. Note that the context name has been prepended, and the request parameters have been appended. In addition, the space in the value of the keyword parameter and the forward slash in the value of the monthparameter have been encoded as required for HTTP GET parameters (specifically, the space has been translated into a + and the slash has been translated into the sequence %2F).

Listing 15. URL generated in the presence of a session cookie


/blog/content/search.jsp?keyword=foo+bar&month=02%2F2003

When no session cookie is present, the URL in Listing 16 is the result. Again, the servlet context has been prepended and the URL-encoded request parameters have been appended. In addition, however, the base URL has been rewritten to include specification of a session ID. When a browser sends a request for a URL that has been rewritten in this manner, the JSP container automatically extracts the session ID and associates the request with the corresponding session. In this way, a J2EE application that requires session management doesn't need to rely on cookies being enabled by users of the application.

Listing 16. URL generated in the absence of a session cookie


/blog/content/search.jsp;jsessionid=233379C7CD2D0ED2E9F3963906DB4290 ?keyword=foo+bar&month=02%2F2003

Back to top

Importing content
JSP has two built-in mechanisms to incorporate content from a different URL into a JSP page: the include directive and the<jsp:include> action. In both cases, however, the content to be included must be part of the same Web application (or servlet context) as the page itself. The major distinction between these two tags is that the include directive incorporates the included content during page compilation, while the <jsp:include> action operates during request-time processing of JSP pages. The core library's <c:import> action is essentially a more generic, more powerful version of <jsp:include> (sort of a<jsp:include> on steroids). Like <jsp:include>, <c:import> is a request-time action, and its basic task is to insert the content of some other Web resource into a JSP page. Its syntax is very similar to that of <c:url>, as shown in Listing 17.

Listing 17. Syntax for the <c:import> action


<c:import url="expression" context="expression" charEncoding="expression" var="name" scope="scope"> <c:param name="expression" value="expression"/> ... </c:import>

The URL for the content to be imported is specified through the url attribute, which is <c:import>'s only required attribute. Relative URLs are permitted and are resolved against the URL of the current page. If the value of the url attribute starts with a forward slash, however, it is interpreted as an absolute URL within the local JSP container. Without a value for the contextattribute, such an absolute URL is assumed to reference a resource in the current servlet context. If an explicit context is specified through the context attribute, then the absolute (local) URL is resolved against the named servlet context. The <c:import> action is not limited to accessing local content, however. Complete URIs, including protocol and host names, can also be specified as the value of the url attribute. In fact, the protocol is not even restricted to HTTP. Any protocol supported by the java.net.URL class may be used in the value for the url attribute of <c:import>. This capability is shown in Listing 18. Here, the <c:import> action is used to include the content of a document accessed through the FTP protocol. In addition, the<c:catch> action is employed to locally handle any errors that might occur during the FTP file transfer. This is accomplished by specifying a scoped variable for the exception using <c:catch>'s var attribute, and then checking its value using <c:if>. If an exception was raised, then assignment to the scoped variable will occur: as the EL expression in Listing 18 suggests, its value will not be empty. Since retrieval of the FTP document will have failed, an error message to that effect is displayed.

Listing 18. Example combining <c:import> and <c:catch>


<c:catch var="exception"> <c:import url="ftp://ftp.example.com/package/README"/> </c:catch> <c:if test="${not empty exception}"> Sorry, the remote content is not currently available. </c:if>

The final two (optional) attributes of the <c:import> action are var and scope. The var attribute causes the content fetched from the specified URL to be stored (as a String value) in a scoped variable, rather than included in the current JSP page. Thescope attribute controls the scoping of this variable, and defaults to page scope. As we will see in a later article, this ability of<c:import> to store an entire document in a scoped variable is leveraged by the tags in the JSTL xml library. Note also that (optional) nested <c:param> tags may be used to specify request parameters for the URL being imported. As was the case for <c:param> tags nested with <c:url>, parameter names and values are URL encoded as necessary. Back to top

Request redirection
The final core library tag is <c:redirect>. This action is used to send an HTTP redirect response to a user's browser, and is the JSTL equivalent of the sendRedirect() method of javax.servlet.http.HttpServletResponse. The behavior of this tag's url and context attributes, shown in Listing 19, is identical to the behavior of <c:import>'s url and context attributes, as is the effect of any nested <c:param> tags.

Listing 19. Syntax for the <c:redirect>action


<c:redirect url="expression" context="expression"> <c:param name="expression" value="expression"/>

... </c:redirect>

Listing 20 shows the <c:redirect> action, which replaces the error message in Listing 18 with a redirect to a designated error page. In this example, the <c:redirect> tag is used in a similar way as the standard <jsp:forward> action. Recall, however, that forwarding through a request dispatcher is implemented on the server side, while redirects are performed by the browser. From the developer's perspective, forwarding is more efficient than redirecting, but the <c:redirect> action is a bit more flexible because <jsp:forward> can only dispatch to other JSP pages within the current servlet context.

Listing 20. Redirecting in response to an exception


<c:catch var="exception"> <c:import url="ftp://ftp.example.com/package/README"/> </c:catch> <c:if test="${not empty exception}"> <c:redirect url="/errors/remote.jsp"/> </c:if>

The main difference from the user's perspective is that a redirect will update the URL displayed by the browser and will therefore affect the setting of bookmarks. Forwarding, on the other hand, is transparent to the end user. The choice between<c:redirect> and <jsp:forward>, then, also depends upon the desired user experience. Back to top

Summary
The JSTL core library contains a variety of general-purpose custom tags that should be of use to a wide spectrum of JSP developers. The URL and exception-handling tags, for example, nicely complement existing JSP functionality, such as the<jsp:include> and <jsp:forward> actions, the include directive, and the errorpage attribute of the page directive. The iteration and conditional actions enable complex presentation logic to be implemented without the need for scripting elements, particularly in combination with the variable tags (<c:set> and <c:remove>) and the EL.

A JSTL primer, Part 3: Presentation is everything


In the previous articles in this series, we discussed the JSTL and its expression language (EL). We also examined the custom tags defined by the core library. Specifically, in "The expression language" we said the EL provides a simplified language for accessing and manipulating data within a JSP application and making that data available to JSTL custom tags as dynamic attribute values. The core library, which includes custom tags for managing scoped variables, displaying EL values, implementing iterative and conditional content, and interacting with URLs, was the topic of "Getting down to the core." The next JSTL library we'll discuss is the fmt library. The custom tags in the fmt library support localizing textual content through resource bundles and the display and parsing of numbers and dates. These tags leverage the Java language's internationalization API as realized in the java.util and java.text packages, so if you're already familiar with classes such as ResourceBundle, Locale, MessageFormat, and DateFormat, you'll find much to appreciate in the fmt library. If not, the fmtlibrary's tags encapsulate the internationalization API in an intuitive manner that makes it easy to incorporate localization features into your JSP applications.

Localization
Within the Java language internationalization API, there are two major factors that influence how data is localized. One is the user's locale, the other is the user's time zone. A locale represents the linguistic

conventions of a particular region or culture, including the formatting of dates, numbers, and currency amounts. A locale will always have an associated language, which in many cases is a dialect of a language shared by multiple locales. For example, there are different locales for the American, British, Australian, and Canadian dialects of the English language, and for the French, Belgian, Swiss, and Canadian dialects of the French language. Time zone is the second factor in the localization of data, simply because some locales span very large geographic regions. When you display time-of-day information for a continent-spanning locale such as Australian English, customizing the data for a user's time zone is just as important as formatting it properly. This begs the question, though: How does an application determine a user's locale and time zone? In the case of Java applications, the JVM is able to set a default locale and time zone by interacting with the local operating system. While this approach works fine for desktop applications, it's not really appropriate for a server-side Java application that is handling requests from locations that may be halfway around the world from the server the application resides on. Fortunately, the HTTP protocol includes provisions for relaying localization information from the browser to the server by means of the Accept-Language request header. Many Web browsers allow users to customize their language preferences, as illustrated in Figure 1. Typically, those browsers that don't provide explicit settings for one or more preferred locales will instead interrogate the operating system to determine what value (or values) to send in the Accept-Language header. The servlet specification automatically takes advantage of this feature of the HTTP protocol through the getLocale() and getLocales()methods of the javax.servlet.ServletRequest class. The custom tags in the JSTL fmt library in turn leverage these methods to automatically determine a user's locale and adjust their output accordingly.

Figure 1. Selecting locales by setting language preferences for a browser

Unfortunately, however, no standard HTTP request headers exist for transmitting a user's time zone from the browser to the server. As a result, users who want their Web applications to localize time data will need to implement their own mechanisms for determining and keeping track of user-specific time zones. For example, the Weblog application introduced in Part 2 of this series, "Getting down to the core," includes a form that stores a user's time zone preference in a cookie. Back to top

The fmt library


The custom tags in the JSTL fmt library fall into four major groupings. The first set allows you to set the localization context in which the other tags operate. In other words, this group of tags allows the page author to explicitly set the locale and time zone that the other fmt tags will use when formatting data. The second and third sets of tags support the formatting and parsing of dates and numbers, respectively. The final group of tags is focused on localizing text messages. Now that we've set the stage, let's focus our attention on each of these four sets of tags in turn, and demonstrate their use.

Localization context tags


As we already discussed, the locale used by the JSTL tags when formatting data is normally determined by examining theAccept-Language header sent by a user's browser as part of each HTTP request. If no such header is present, then JSTL provides a set of JSP configuration variables you can set to specify a default locale. If these configuration variables have not been set, then the JVM's default locale is used, which is obtained from the operating system the JSP container is running on. The fmt library provides its own custom tag for overriding this process of determining a user's locale: <fmt:setLocale>. As the following snippet shows, the <fmt:setLocale> action supports three attributes:
<fmt:setLocale value="expression" scope="scope" variant="expression"/>

Only one of the attributes, the value attribute, is required. The value of this attribute should be either a string naming a locale, or an instance of the java.util.Locale class. A locale name is constructed from a two-letter lowercase ISO country code, optionally followed by an underscore or hyphen and a twoletter uppercase ISO language code. For example, en is the language code for English and US is the country code for the United States, so en_US (or en-US) would be the locale name for American English. Similarly, fr is the language code for French and CA is the country code for Canada, sofr_CA (or fr_CA) is the locale name for Canadian French. (See Resources for links to all the valid ISO language and country codes.) Of course, because the country codes are optional, en and fr are themselves valid locale names and would be appropriate for applications that do not distinguish between specific dialects of the corresponding languages. The optional scope attribute of <fmt:setLocale> is used to specify the scope of the locale. The page scope indicates that the setting is only applicable over the current page, while the request scope applies it to all JSP pages accessed during a request. If the scope attribute is set to session, then the specified locale is used for all JSP pages accessed over the course of the user's session. A value of application indicates that the locale is applied to all requests for all of the Web application's JSP pages and for all users of that application. The variant attribute (also optional) allows you to further customize the locale to a specific Web browser platform or vendor. For example, MAC and WIN are variant names for the Apple Macintosh and Microsoft Windows platforms, respectively. The following snippet shows how the <fmt:setLocale> tag is used to explicitly specify the locale setting for a user's session:
<fmt:setLocale value="fr_CA" scope="session"/>

After the JSP container processes this JSP fragment, the language preferences as specified in the user's browser settings will be ignored. The <fmt:setTimeZone> action, like <fmt:setLocale>, may be used to set the default time zone value for use by the otherfmt custom tags. Its syntax is shown here:
<fmt:setTimeZone value="expression"

var="name" scope="scope"/>

Like the <fmt:setLocale>, only the value attribute is required, though in this case it should be either the name of a time zone or an instance of the java.util.TimeZone class. Unfortunately, there aren't any widely accepted standards for naming time zones. Time zone names you may use for the valueattribute of the <fmt:setTimezone> tag are therefore Java platform-specific. You can retrieve a list of valid time zone names by calling the getAvailableIDs() static method of the java.util.TimeZone class. Examples include US/Eastern, GMT+8, andPacific/Guam. As was the case for <fmt:setLocale>, you can use the optional scope attribute to indicate the scope of the time zone setting. The code below shows the use of <fmt:setTimeZone> to specify the time zone to be applied to an individual user's session:
<fmt:setTimeZone value="Australia/Brisbane" scope="session"/>

You can also use the <fmt:setTimeZone> action to store the value of a TimeZone instance in a scoped variable. In this case, you use the var attribute to name the scoped variable and the scope attribute specifies the variable's scope (just as these two attributes are used in the <c:set> and <c:if> actions, for example). Note that when you use the <fmt:setTimeZone> action in this manner, its only side effect is setting the specified variable. When the var attribute is specified, no change is made to the JSP environment with respect to what time zone is used by any other JSTL tags. The final tag in this group is the <fmt:timeZone> action:
<fmt:timeZone value="expression"> body content </fmt:timeZone>

Like <fmt:setTimeZone>, you use this tag to specify the time zone to be used by other JSTL tags. The scope of the<fmt:timeZone> action, however, is limited to its body content. Within the body of an <fmt:timeZone> tag, the time zone specified by the tag's value attribute overrides any other time zone setting present in the JSP environment. As was the case for <fmt:setTimeZone>, the value attribute of the <fmt:timeZone> tag should be either the name of a time zone or an instance of java.util.TimeZone. An example of how to use <fmt:timeZone> appears later in Listing 1.

Date tags
The fmt library includes two tags for interacting with dates and time: <fmt:formatDate> and <fmt:parseDate>. As their names suggest, <fmt:formatDate> is used to format and display dates and times (data output), while <fmt:parseDate> is used to parse date and time values (data input). The syntax for <fmt:formatDate> is shown here:
<fmt:formatDate value="expression" timeZone="expression" type="field" dateStyle="style" timeStyle="style" pattern="expression" var="name" scope="scope"/>

Only the value attribute is required. Its value should be an instance of the java.util.Date class, specifying the date and/or time data to be formatted and displayed. The optional timeZone attribute indicates the time zone in which the date and/or time are to be displayed. If no timeZoneattribute is specified explicitly, then the time zone specified by any surrounding <fmt:timeZone> tag is used. If the<fmt:formatDate> action is not enclosed in the

body of an <fmt:timeZone> tag, then the time zone set by any applicable<fmt:setTimeZone> action is used. If there is no relevant <fmt:setTimeZone> action, then the JVM's default time zone is used (that is, the time zone setting specified for the local operating system). The type attribute indicates which fields of the specified Date instance are to be displayed, and should be either time, date, orboth. The default value for this attribute is date, so if no type attribute is present, the <fmt:formatDate> tag -- true to its name -- will only display the date information associated with the Date instance, specified using the tag's value attribute. The dateStyle and timeStyle attributes indicate how the date and time information should be formatted, respectively. Valid styles are default, short, medium, long, and full. The default value is, naturally, default, indicating that a locale-specific style should be used. The semantics for the other four style values are as defined by the java.text.DateFormat class. Rather than relying on the built-in styles, you can use the pattern attribute to specify a custom style. When present, the value of the pattern attribute should be a pattern string following the conventions of the java.text.SimpleDateFormat class. These patterns are based on replacing designated characters within the pattern with corresponding date and time fields. For example, the pattern MM/dd/yyyy indicates that two-digit month and date values and a four-digit year value should be displayed, separated by forward slashes. If the var attribute is specified, then a String value containing the formatted date is assigned to the named variable. Otherwise, the <fmt:formatDate> tag will write out the formatting results. When the var attribute is present, the scope attribute specifies the scope of the resulting variable. Listing 1 (which is an extension of Listing 8 from Part 2 of this series) includes two uses of the <fmt:formatDate> tag. In the first usage, <fmt:formatDate> is used to display only the date portion of the creation timestamp for the first weblog entry. In addition, a value of full is specified for the dateStyle attribute, so that all date fields will be displayed in a locale-specific format.

Listing 1. Using the <fmt:formatDate> tag to display date and time values
<table> <fmt:timeZone value="US/Eastern"> <c:forEach items="${entryList}" var="blogEntry" varStatus="status"> <c:if test="${status.first}"> <tr><td align="left" class="blogDate"> <fmt:formatDate value= "${blogEntry.created}" dateStyle="full"/> </td></tr> </c:if> <tr><td align="left" class="blogTitle"> <c:out value="${blogEntry.title}" escapeXml="false"/> </td></tr> <tr><td align="left" class="blogText"> <c:out value="${blogEntry.text}" escapeXml="false"/> <font class="blogPosted"> [Posted <fmt:formatDate value="${blogEntry.created}" pattern="h:mm a zz"/>] </font> </td></tr> </c:forEach> </fmt:timeZone> </table>

Within the body of the <c:forEach> loop, a second <fmt:formatDate> action is used to display only the time portion of each entry's creation date. In this case, the pattern attribute is used to control the formatting of the time value, specifying a single-digit hour display (when possible), a twelve-hour clock, and output of an abbreviated time zone. The output is shown in Figure 2:

Figure 2. Output of the en_US locale from Listing 1

To be more precise, the output shown in Figure 2 results when the user's browser settings indicate a preference for the English language. Because <fmt:formatDate> is sensitive to a user's locale, however, a change in browser preferences will cause different content to be generated. For example, when a French-language locale is given precedence, the results will instead be like those shown in Figure 3:

Figure 3. Output of the fr_CA locale from Listing 1

Whereas <fmt:formatDate> generates a localized character-string representation of a java.util.Date instance, the<fmt:parseDate> action performs the inverse operation: Given a character string representing a date and/or time, it generates the corresponding Date object. There are two forms of the <fmt:parseDate> action, as shown here:
<fmt:parseDate value="expression" type="field" dateStyle="style" timeStyle="style" pattern="expression" timeZone="expression" parseLocale="expression" var="name" scope="scope"/> <fmt:parseDate type="field" dateStyle="style" timeStyle="style" pattern="expression" timeZone="expression" parseLocale="expression" var="name" scope="scope"> body content </fmt:parseDate>

For the first form, only the value attribute is required, and its value should be a character string specifying a date, time, or combination of the two. For the second form, there are no required attributes, and the character string representing the value to be parsed is specified as the required body content of the <fmt:parseDate> tag. The type, dateStyle, timeStyle, pattern, and timeZone attributes play the same role for <fmt:parseDate> as they do for<fmt:formatDate>, except that they control the parsing of a date value, rather than its display. The parseLocale attribute is used to specify a locale that the tag's value is to be parsed against, and should be either the name of a locale or an instance of the Locale class. The var and scope attributes are used to specify a scoped variable that -- as a result of <fmt:parseDate> -- the Date object is assigned to. If the var attribute is not present, the result is

written to the JSP page using the Date class's toString() method. Listing 2 shows an example of the <fmt:parseDate> action:

Listing 2. Using the <fmt:parseDate> tag to parse dates and times


<c:set var="usDateString">4/1/03 7:03 PM</c:set> <fmt:parseDate value="${usDateString}" parseLocale="en_US" type="both" dateStyle="short" timeStyle="short" var="usDate"/> <c:set var="gbDateString">4/1/03 19:03</c:set> <fmt:parseDate value="${gbDateString}" parseLocale="en_GB" type="both" dateStyle="short" timeStyle="short" var="gbDate"/> <ul> <li> Parsing <c:out value="${usDateString}"/> against the U.S. English locale yields a date of <c:out value="${usDate}"/>.</li> <li> Parsing <c:out value="${gbDateString}"/> against the British English locale yields a date of <c:out value="${gbDate}"/>.</li> </ul>

The output of Listing 2 is shown in Figure 4.

Figure 4. Output of Listing 2

It is important to note that the parsing performed by <fmt:parseDate> is not at all lenient. As Listing 2 suggests, the value to be parsed must strictly adhere to the specified (locale-specific) styles or pattern. This is, of course, rather limiting. On the other hand, the parsing of data is not a task well-suited to the presentation layer. For production code, validating and transforming textual input is better handled by backend code (a servlet, for example), rather than by means of JSP custom tags.

Number tags
Just as the <fmt:formatDate> and <fmt:parseDate> tags are used for formatting and parsing dates, the<fmt:formatNumber> and <fmt:parseNumber> tags perform similar functions for numeric data. The <fmt:formatNumber> tag is used to display numeric data, including currencies and percentages, in a locale-specific manner. The <fmt:formatNumber> action determines from the locale, for example, whether to use a period or a comma for delimiting the integer and decimal portions of a number. Here is its syntax:

<fmt:formatNumber value="expression" type="type" pattern="expression" currencyCode="expression" currencySymbol="expression" maxIntegerDigits="expression" minIntegerDigits="expression" maxFractionDigits="expression" minFractionDigits="expression" groupingUsed="expression" var="name" scope="scope"/>

As was the case for <fmt:formatDate>, only the value attribute is required. It is used to specify the numeric value that is to be formatted. The var and scope attributes also play the same role for the <fmt:formatNumber> action as they do for<fmt:formatDate>. The value of the type attribute should be either number, currency, or percentage, and indicates what type of numeric value is being formatted. The default value for this attribute is number. The pattern attribute takes precedence over the type attribute and allows more precise formatting of numeric values following the pattern conventions of the java.text.DecimalFormatclass. When the type attribute has a value of currency, the currencyCode attribute can be used to explicitly specify the currency for the numerical value being displayed. As with language and country codes, currency codes are governed by an ISO standard. (See Resources for links to all the valid ISO currency codes.) This code is used to determine the currency symbol to display as part of the formatted value. Alternatively, you can use the currencySymbol attribute to explicitly specify the currency symbol. Note that as of JDK 1.4 and the associated introduction of the java.util.Currency class, the currencyCode attribute of the <fmt:formatNumber> action takes precedence over the currencySymbol attribute. For earlier versions of the JDK, however, the currencySymbol attribute takes precedence. The maxIntegerDigits, minIntegerDigits, maxFractionDigits, and minFractionDigits attributes are used to control the number of significant digits displayed before and after the decimal point. These attributes require integer values. The groupingUsed attribute takes a Boolean value and controls whether digits before the decimal point are grouped. For example, in English-language locales, large numbers have their digits grouped by threes, with each set of three delimited by a comma. Other locales delimit such groupings with a period or a space. The default value for this attribute is true. Listing 3 shows a simple currency example, which is itself an extension of Listing 1. In this case, neither the currencyCode nor the currencySymbol attributes are specified. The currency is instead determined from the locale setting.

Listing 3. Using the <fmt:formatNumber> tag to display currency values


<table> <fmt:timeZone value="US/Eastern"> <c:forEach items="${entryList}" var="blogEntry" varStatus="status"> <c:if test="${status.first}"> <tr><td align="left" class="blogDate"> <fmt:formatDate value= "${blogEntry.created}" dateStyle="full"/> </td></tr> </c:if> <tr><td align="left" class="blogTitle"> <c:out value="${blogEntry.title}" escapeXml="false"/> </td></tr> <tr><td align="left" class="blogText"> <c:out value="${blogEntry.text}" escapeXml="false"/> <font class="blogPosted"> [My <fmt:formatNumber value="0.02" type="currency"/> posted at <fmt:formatDate value="${blogEntry.created}" pattern="h:mm a zz"/>] </font> </td></tr> </c:forEach> </fmt:timeZone>

</table>

The output for the en_US locale is shown in Figure 5:

Figure 5. Output of the en_US locale from Listing 3

The output for the fr_CA locale is shown in Figure 6:

Figure 6. Output of the fr_CA locale from Listing 3

The <fmt:parseNumber> action, shown below, parses a numerical value provided through either its value attribute or its body content in a locale-specific manner, and returns the result as an instance of the java.lang.Number class. The type andpattern attributes play the same role for <fmt:parseNumber> as they do for <fmt:formatNumber>. Likewise, theparseLocale, var, and scope attributes play the same role for <fmt:parseNumber> as they do for <fmt:parseDate>.
<fmt:parseNumber value="expression" type="type" pattern="expression" parseLocale="expression" integerOnly="expression" var="name" scope="scope"/> <fmt:parseNumber type="type" pattern="expression" parseLocale="expression" integerOnly="expression" var="name" scope="scope"> body content </fmt:parseNumber>

The comment made earlier regarding <fmt:parseDate> is equally applicable to <fmt:parseNumber>: Parsing data is not a task well-suited to the presentation layer. Software maintenance will be simplified if parsing and validating data are implemented as part of the application's business logic. For this reason, it is generally advisable to avoid the use of both<fmt:parseDate> and <fmt:parseNumber> in production JSP pages. Only the integerOnly attribute is unique to <fmt:parseNumber>. This attribute takes a Boolean value indicating whether only the integer portion of the provided value should be parsed. If this attribute's value is true, any digits following the decimal point within the character string being parsed are ignored. The default value for this attribute is false.

Message tags

Localizing text in JSTL is accomplished with the <fmt:message> tag. This tag allows you to retrieve text messages from a locale-specific resource bundle and display it on a JSP page. Furthermore, because this action leverages the capabilities provided by the java.text.MessageFormat class, parameterized values can be substituted into such text messages to customize localized content dynamically. Resource bundles for storing locale-specific messages take the form of classes or property files that adhere to a standard naming convention, in which a basename is combined with a locale name. Consider, for example, a property file namedGreeting.properties that resides in our weblog application's classpath in the subdirectory corresponding to thecom.taglib.weblog package. You could localize the resource bundle represented by this property file for the English and French languages by specifying two new property files in the same directory, named by appending the appropriate language codes. Specifically, these two files would be named Greeting_en.properties and Greeting_fr.properties, respectively. If additional localization for the Canadian dialect of the French language were desired, you could introduce a third property file that includes the appropriate country code in its name (such as Greeting_fr_CA.properties). Each of these files would define the same properties, but the values for those properties would be customized to the corresponding language or dialect. This approach is shown in Listings 4 and 5, which provide sample contents for theGreeting_en.properties and Greeting_fr.properties files. In these examples, two localized messages are defined. They are identified by the com.taglib.weblog.Greeting.greeting and com.taglib.weblog.Greeting.retu rn keys. The values associated with these keys, however, have been localized for the language identified in the file's name. Note that the {0}pattern appearing in both values for the com.taglib.weblog.Greeting.greeting message enables a parameterized value to be dynamically inserted into the message during content generation.

Listing 4. Contents of the Greeting_en.properties localized resource bundle


com.taglib.weblog.Greeting.greeting=Hello {0}, and welcome to the JSTL Blog. com.taglib.weblog.Greeting.return=Return

Listing 5. Contents of the Greeting_fr.properties localized resource bundle


com.taglib.weblog.Greeting.greeting=Bonjour {0}, et bienvenue au JSTL Blog. com.taglib.weblog.Greeting.return=Retournez

The first step in displaying such localized content with JSTL is to specify the resource bundle. The fmt library provides two custom tags for accomplishing this -<fmt:setBundle> and <fmt:bundle> -- which are analogous in their behavior to the<fmt:setTimeZone> and <fmt:timeZone> tags introduced earlier. The <fmt:setBundle> action sets a default resource bundle for use by <fmt:message> tags within a particular scope, whereas <fmt:bundle> specifies the resource bundle for use by any and all <fmt:message> actions nested within its body content. The code snippet below shows the syntax for the <fmt:setBundle> tag. The basename attribute is required, and identifies the resource bundle to be set as the default. Note that the value for the basename attribute should not include any localization suffixes or filename extensions. The basename for the example resource bundle presented in Listings 4 and 5 iscom.taglib.weblog.Greeting.
<fmt:setBundle basename="expression" var="name" scope="scope"/>

The optional scope attribute indicates the JSP scope that the setting of the default resource bundle applies to. If this attribute is not explicitly specified, page scope is assumed.

If the optional var attribute is specified, then the resource bundle identified by the basename attribute will be assigned to the variable named by this attribute's value. In this case, the scope attribute specifies the variable's scope; no default resource bundle is assigned to the corresponding JSP scope. You use the <fmt:bundle> tag, whose syntax is shown below, to set the default resource bundle within the scope of its body content. Like <fmt:setBundle>, only the basename attribute is required. You use the optional prefix attribute to specify a default prefix for the key values of any nested <fmt:message> actions.
<fmt:bundle basename="expression" prefix="expression"> body content </fmt:bundle>

Once the resource bundle has been set, it is the role of the <fmt:message> tag to actually display a localized message. Two different syntaxes are supported by this action, depending on whether any nested <fmt:param> tags are required:
<fmt:message key="expression" bundle="expression" var="name" scope="scope"/> <fmt:message key="expression" bundle="expression" var="name" scope="scope"> <fmt:param value="expression"/> ... </fmt:message>

For <fmt:message>, only the key attribute is required. The value of the key attribute is used to determine which of the messages defined in the resource bundle is to be displayed. You can use the bundle attribute to specify an explicit resource bundle for looking up the message identified by the key attribute. Note that the value of this attribute must be an actual resource bundle, such as is assigned by the <fmt:setBundle> action when its var attribute is specified. String values, such as the basename attribute of <fmt:bundle> and <fmt:setBundle>, are not supported by the bundle attribute of <fmt:message>. If the var attribute of <fmt:message> is specified, then the text message generated by the tag is assigned to the named variable, rather than written to the JSP page. As usual, the optional scope attribute is used to specify the scope for the variable named by the var attribute. You use the <fmt:param> tag to provide parameterized values for the text message, where needed, through the tag's valueattribute. Alternatively, the value can be specified as body content of the <fmt:param> tag, in which case the attribute is omitted. Values specified with the <fmt:param> tag are spliced into the message retrieved from the resource bundle wherever parameterized value patterns appear in the message text, in accordance with the behavior of the java.text.MessageFormatclass. Because parameterized values are identified by their indices, the order of the nested <fmt:param> tags is significant. The interaction of the <fmt:bundle>, <fmt:message>, and <fmt:param> tags is shown in Listing 6. Here, the <fmt:bundle>tag specifies the bundle localized messages are to be retrieved from by the two nested <fmt:message> tags. The first of these two <fmt:message> tags corresponds to a message with a single parameterized value, for which a corresponding<fmt:param> tag appears.

Listing 6. Using the <fmt:message> tag to display localized messages


<fmt:bundle basename="com.taglib.weblog.Greeting"> <fmt:message key="com.taglib.weblog.Greeting.greeting"> <fmt:param value="${user.fullName}"/> </fmt:message> <br> <br> <center>

<a href= "<c:url value='/index.jsp'/>"><fmt:message key="com.taglib.weblog.Greeting.return"/></a> </center> </fmt:bundle>

Listing 7 shows the use of <fmt:bundle>'s prefix attribute; the value provided for the prefix attribute is automatically prepended to all key values in the nested <fmt:message> actions. Listing 7 is therefore equivalent to Listing 6, but takes advantage of this convenience feature to enable the use of abbreviated key values in the two <fmt:message> tags.

Listing 7. Effect of the prefix attribute of <fmt:bundle> on the <fmt:message> tag


<fmt:bundle basename="com.taglib.weblog.Greeting" prefix="com.taglib.weblog.Greeting."> <fmt:message key="greeting"> <fmt:param value="${user.fullName}"/> </fmt:message> <br> <br> <center> <a href="<c:url value='/index.jsp'/>"><fmt:message key="return"/></a> </center> </fmt:bundle>

Figure 7 and Figure 8 show the fmt library's message-related tags in action, showing the output resulting from the code in Listing 7 and the localized resource bundles in Listing 4 and Listing 5. Figure 7 shows the results when the browser preferences reflect an English-language locale.

Figure 7. Output of the en_US locale from Listing 7

Figure 8 shows the output for a locale specifying the French language.

Figure 8. Output of the fr_CA locale from Listing 7

Back to top

Summary
The custom tags in the JSTL fmt library provide straightforward access to the Java platform's internationalization API for JSP developers. Text messages, numerical values, and dates can all be displayed in a locale-sensitive manner, while times can also be adjusted for specific time zones. The locale for a particular user can be determined automatically from the user's browser settings, or specified explicitly by the page author. Finally, in addition to providing actions for generating and displaying formatted data, the fmt library also includes custom tags for parsing numerical and time-oriented data.

A JSTL primer, Part 4: Accessing SQL and XML content


The stereotypical architecture for a Web-based application calls for three tiers: a Web server for handling requests, an application server for implementing business logic, and a database for managing persistent data. The linkage between the application and database tiers typically takes the form of SQL calls into a relational database. When the business logic is written in the Java language, JDBC is used to implement these calls. If the application calls for integration with additional servers (either local or remote), further mechanisms for exchanging data between the various subsystems will be required. An increasingly common approach to communicating data both within and between Web applications is the exchange of XML documents. So far in our tour of JSTL, we've examined the JSTL expression language (EL) and both the core and fmt tag libraries. In this final installment, we'll consider the sql and xml libraries that -- as their names suggest -- provide custom tags for accessing and manipulating data retrieved from SQL databases and XML documents.

The xml library


By design, XML provides a flexible means for representing structured data that is at the same time readily amenable to validation. As a result, it is particularly well suited for exchanging data between loosely coupled systems. This in turn makes it an attractive integration technology for Web-based applications. The first step in interacting with data represented as XML is to retrieve it as an XML document and parse it to yield a data structure for accessing the contents of the document. After the document has been parsed you can then optionally transform it to yield a new XML document, to which the same operations can again be applied. Finally, the data from the document can be extracted and then displayed or used as input for performing additional operations. These steps are mirrored in the JSTL tags used for manipulating XML. XML documents are retrieved using the <c:import> tag from the core library, as we discussed in Part 2, Getting down to the core. The <x:parse> tag is then used to parse the document, with support for standard XML parsing technologies such as the Document Object Model (DOM) and Simple API for XML (SAX). The <x:transform> tag is available for transforming XML documents and relies on the standard technology for transforming XML data: the Extensible Stylesheet Language (XSL). Finally, several tags are

provided for accessing and manipulating parsed XML data, all of which rely on yet another standard, the XML Path Language (XPath), for referencing the contents of parsed XML documents.

Parsing XML
The <x:parse> tag actually takes several forms, depending upon the type of parsing desired. The most basic form of this action uses the following syntax:
<x:parse xml="expression" var="name" scope="scope" filter="expression" systemId="expression"/>

Of these five attributes, only the xml attribute is required, and its value should be either a String containing the XML document to be parsed or an instance of java.io.Reader through which the document to be parsed can be read. Alternatively, you can specify the document to be parsed as the body content of the <x:parse> tag, using this syntax:
<x:parse var="name" scope="scope" filter="expression" systemId="expression"> body content </x:parse>

The var and scope attributes specify a scoped variable for storing the parsed document. This variable can then be used by the other tags in the xml library to perform additional operations. Note that when the var and scope attributes are present, the type of data structure used by JSTL to represent the parsed document is implementation-specific, allowing for vendor optimization. If your application needs to perform operations on the parsed document that is provided by JSTL, then an alternate form of<x:parse> can be used, which requires that the parsed document adhere to a standard interface. In this case the syntax for the tag is as follows:
<x:parse xml="expression" varDom="name" scopeDom="scope" filter="expression" systemId="expression"/>

When you use this version of <x:parse>, the object representing the parsed XML document must implement theorg.w3c.dom.Document interface. You can also use the varDom and scopeDom attributes in place of var and scope when the XML document is specified as the body content of <x:parse>, as follows:
<x:parse varDom="name" scopeDom="scope" filter="expression" systemId="expression"> body content </x:parse>

The remaining two attributes, filter and systemId, enable more fine-grained control of the parsing. The filter attribute specifies an instance of the org.xml.sax.XMLFilter class for filtering the document prior to parsing. This attribute is particularly useful if the document to be parsed is very large, but only a small subset is of interest for the task at hand. ThesystemId attribute indicates the URI for the document being parsed and resolves any relative paths present in the document. This attribute is required if the XML being parsed uses relative URLs to refer to other documents or resources that need to be accessed during the parsing process. Listing 1 demonstrates the use of the <x:parse> tag, including its interaction with <c:import>. Here, the <c:import> tag is used to retrieve the RDF Site Summary (RSS) feed for the well-known Slashdot

Web site. The XML document representing the RSS feed is then parsed by <x:parse>, and an implementation-specific data structure representing the parsed document is stored in a variable named rss with page scope.

Listing 1. Interaction of the <x:parse> and <c:import> actions


<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/> <x:parse var="rss" xml="${rssFeed}"/>

Transforming XML
XML is transformed by means of XSL stylesheets. JSTL supports this operation through use of the <x:transform> tag. As was the case for <x:parse>, the <x:transform> tag supports several different forms. The syntax for the most basic form of<x:transform> is:
<x:transform xml="expression" xslt="expression" var="name" scope="scope" xmlSystemId="expression" xsltSystemId="expression"> <x:param name="expression" value="expression"/> ... </x:transform>

Learning about RSS


RDF Site Summary (RSS) is an XML document format published by many news-oriented sites, which lists their current headlines and provides URLs for linking to the corresponding articles. As such, it provides a simple mechanism for syndicating news items over the Web. For further details on RSS, see Resources.

Here, the xml attribute specifies the document to be transformed, and the xslt attribute specifies the stylesheet defining that transformation. These two attributes are required; the others are optional. Like the xml attribute of <x:parse>, the value of the xml attribute of<x:transform> can be either a String containing an XML document or a Reader for accessing such a document. In addition, however, it can also take the form of an instance of either theorg.w3c.dom.Document class or thejavax.xml.transform.Source class. Finally, it can also be the value of a variable assigned using either the var or varDom attribute of the <x:parse> action. Alternatively, you can include the XML document to be transformed as the body content of the <x:transform> action. In this case, the syntax for <x:transform> is:
<x:transform xslt="expression" var="name" scope="scope" xmlSystemId="expression" xsltSystemId="expression"> body content <x:param name="expression" value="expression"/> ... </x:transform>

In both cases, the xslt attribute specifying the XSL stylesheet should be either a String, a Reader, or an instance ofjavax.xml.transform.Source. If the var attribute is present, the transformed XML document will be assigned to the corresponding scoped variable as an instance of the org.w3c.dom.Document class. As usual, the scope attribute specifies the scope for this variable assignment. The <x:transform> tag also supports storing the result of the transformation in an instance of thejavax.xml.transform.Result class, rather than as an instance of org.w3c.dom.Document. If the var and scope attributes are omitted and a Result object is

specified as the value of the result attribute, the <x:transform> tag will use that object to hold the results of applying the stylesheet. The two syntax variations for using the result attribute of <x:transform> appear in Listing 2:

Listing 2. Syntax variations for the <x:transform> action when using the result attribute to supply a javax.xml.transform.Result instance
<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>

When you employ either of these two forms of <x:transform>, the javax.xml.transform.Result object must be created independently from the custom tag. The object itself is supplied as the value of the result attribute. If neither the var attribute nor the result attribute is present, then the results of the transformation will simply be inserted into the JSP page as a result of processing the <x:transform> action. This is particularly useful when a stylesheet is being used to transform data from XML into HTML, as illustrated in Listing 3:

Listing 3. Directly displaying transformed XML data in a JSP page


<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}"/>

In this example, both the RSS feed and an appropriate stylesheet are read in using the <c:import> tag. The output of the stylesheet is HTML, which is directly displayed by omitting both the var and result attributes of <x:transform>. Figure 1 shows a sample result:

Figure 1. Output of Listing 3

Like the systemId attribute of <x:parse>, the xmlSystemId and xsltSystemId attributes of <x:transform> are used to resolve relative paths within XML documents. In this case, the xmlSystemId attribute applies to the document provided as the value of the tag's xml attribute, while the xsltSystemId attribute is used to resolve relative paths within the stylesheet specified by the tag's xslt attribute. If the stylesheet driving the document transformation takes parameters, they are specified using the <x:param> tag. When present, these tags must appear inside the body of the <x:transform> tag. If the XML document being transformed is also specified as body content, then it must precede any <x:param> tags. The <x:param> tag has two required attributes -- name and value -- just like the <c:param> and <fmt:param> tags discussed in Part 2 and Part 3 of this series.

Working with XML content


Parsing and transformation act upon XML documents in their entirety. After you've massaged the document into a usable form, however, often only certain elements of the data contained in the document will be of interest to a particular application. For this reason, the xml library includes several tags for accessing and manipulating individual pieces of content from XML documents. If you've read Part 2 of this series (Getting down to the core) then the names of these xml tags will be familiar. They are based on corresponding tags from the JSTL core library. Whereas these core library tags access data from the JSP container through their value attributes using EL expressions, their counterparts in the xml library access data from XML documents throughselect attributes using XPath expressions. XPath is a standardized notation for referencing the elements of XML documents and their attributes and body content. As its name suggests, this notation resembles file system paths in the sense that the components of an XPath statement are delimited by slashes. These components map to the nodes of an XML document, with successive components matching nested elements. In addition, asterisks can be used as wildcards to match multiple nodes, and bracketed expressions can be used to match attribute values and specify indices. There are several online references describing XPath and its use (see Resources). To display an element of data from an XML document, then, use the <x:out> action, which is the XML analog to the corelibrary's <c:out> tag. Whereas <c:out> has attributes named value and escapeXml, however, the attributes of <x:out> areselect and escapeXml:
<x:out select="XPathExpression" escapeXml="boolean"/>

The difference, of course, is that the value of the select attribute must be an XPath expression, while the value attribute of<c:out> must be an EL expression. The meaning of the escapeXml attribute is the same for both tags. Listing 4 demonstrates use of the <x:out> action. Note that the XPath expression specified for the select attribute is prefaced by an EL expression for a scoped variable, specifically $rss. This EL expression identifies the parsed XML document against which the XPath statement is to be evaluated. The statement here searches the document for elements named title whose parent nodes are named channel, selecting the first such element it finds (as specified by the [1] index at the end of the expression). The <x:out> action causes the body content of this element to be displayed, with XML character escaping turned off.

Listing 4. Using the <x:out> action to display the body content of an XML element
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/> <x:parse var="rss" xml="${rssFeed}"/> <x:out select="$rss//*[name()='channel']/*[name()='title'][1]" escapeXml="false"/>

In addition to <x:out>, the JSTL xml library includes the following tags for manipulating XML data: y <x:set> for assigning the value of an XPath expression to a JSTL scoped variable y <x:if> for conditionalizing content based on the boolean value of an XPath expression y <x:choose>, <x:when>, and <x:otherwise> for implementing mutually exclusive conditionalization based on XPath expressions y <x:forEach> for iterating over multiple elements matched by an XPath expression Each of these tags behaves similarly to the corresponding tag from the core library. Use of <x:forEach>, for example, is illustrated in Listing 5, in which the <x:forEach> action is used to iterate over all of the elements named item in an XML document representing an RSS feed. Note that the XPath expressions in the two <x:out> actions nested in the body content of<x:forEach> are relative to the nodes over which the <x:forEach> tag is iterating. They are used to retrieve the link andtitle child nodes of each item element.

Listing 5. Using the <x:out> and <x:forEach> actions to select and display XML data
<c:import var="rssFeed" url="http://slashdot.org/slashdot.rdf"/> <x:parse var="rss" xml="${rssFeed}"/> <a href="<x:out select="$rss//*[name()='channel']/*[name()='link'][1]"/>" ><x:out select="$rss//*[name()='channel']/*[name()='title'][1]" escapeXml="false"/></a> <x:forEach select="$rss//*[name()='item']"> <li> <a href="<x:out select="./*[name()='link']"/>" ><x:out select="./*[name()='title']" escapeXml="false"/></a> </x:forEach>

The output resulting from the JSP code in Listing 5 is identical to that of Listing 3, which appears in Figure 1. The xml library's XPath-oriented tags thus provide an alternative to stylesheets for transforming XML content, particularly in cases where the final output is HTML. Back to top

The sql library


The fourth and final set of JSTL actions is the sql custom tag library. As its name suggests, this library provides tags for interacting with relational databases. More specifically, the sql library defines tags for specifying datasources, issuing queries and updates, and grouping queries and updates into transactions.

Datasources
Datasources are factories for obtaining database connections. They often implement some form of connection pooling to minimize the overhead associated with the creating and initializing connections. Java 2 Enterprise Edition (J2EE) application servers typically provide built-in support for datasources, which are made available to J2EE applications through the Java Naming and Directory Interface (JNDI). JSTL's sql tags rely on datasources for obtaining connections. Several, in fact, include an optional dataSource attribute for explicitly specifying their connection factory, either as an instance of the javax.sql.DataSource interface or as a JNDI name. You can obtain instances of javax.sql.DataSource using the <sql:setDataSource> tag, which takes the two following forms:
<sql:setDataSource dataSource="expression" var="name" scope="scope"/> <sql:setDataSource url="expression" driver="expression" user="expression" password="expression" var="name" scope="scope"/>

For the first form, only the dataSource attribute is required. For the second, only the url attribute is required. Use the first form to access a datasource associated with a JNDI name, by providing that name as the value of the dataSourceattribute. The second form causes a new datasource to be created, using the JDBC URL provided as the value of the urlattribute. The optional driver attribute specifies the name of the class implementing the database driver, while the user andpassword attributes provide login credentials for accessing the database, if needed. For either of the two forms of <sql:setDataSource>, the optional var and scope attributes assign the specified datasource to a scoped variable. If the var attribute is not present, however, then the <sql:setDataSource> action has the effect of setting the default datasource for use by sql tags that don't specify an explicit datasource. You can also use the javax.servlet.jsp.jstl.sql.dataSource context parameter to configure the sql library's default datasource. In practice, placing an entry such as the one in Listing 6 in your application's web.xml file is the most convenient way to specify a default datasource. Using <sql:setDataSource> to do so requires the use of a JSP page to initialize the application, and therefore some way to run that page automatically.

Listing 6. Using a JNDI name to set JSTL's default datasource in the web.xml deployment descriptor
<context-param> <param-name>javax.servlet.jsp.jstl.sql.dataSource</param-name> <param-value>jdbc/blog</param-value> </context-param>

Submitting queries and updates


After access to a datasource is established, you can use the <sql:query> action to execute queries, while database updates are performed using the <sql:update> action. Queries and updates are specified as SQL statements, which may be parameterized using an approach based on

JDBC's java.sql.PreparedStatement interface. Parameter values are specified using nested <sql:param> and <sql:dateParam> tags. Three variations of the <sql:query> action are supported, as follows:
<sql:query sql="expression" dataSource="expression" var="name" scope="scope" maxRows="expression" startRow="expression"/> <sql:query sql="expression" dataSource="expression" var="name" scope="scope" maxRows="expression" startRow="expression"> <sql:param value="expression"/> ... </sql:query> <sql:query dataSource="expression" var="name" scope="scope" maxRows="expression" startRow="expression"> SQL statement <sql:param value="expression"/> ... </sql:query>

For the first two forms, only the sql and var attributes are required. For the third, only var is required. The var and scope attributes specify a scoped variable for storing the results of the query. The maxRows attribute can be used to limit the number of rows returned by the query, while the startRow attribute allows some initial number of rows to be ignored (such as being skipped over when the result set is being constructed by the database). After you execute the query, the result set is assigned to the scoped variable as an instance of thejavax.servlet.jsp.jstl.sql.Result interface. This object provides properties for accessing the rows, column names, and size of the query's result set, as summarized in Table 1: Table 1. Properties defined by the javax.servlet.jsp.jstl.sql.Result interface

Property

Description

rows

An array of SortedMap objects, each of which maps column names to a single row in the result set

rowsByIndex

An array of arrays, each corresponding to a single row in the result set

columnNames

An array of strings naming the columns in the result set, in the same order as used for the rowsByIndex property

rowCount

The total number of rows in the query result

limitedByMaxRows True if the query was limited by the value of the maxRows attribute
Of these properties, rows is particularly convenient, because you can use it to iterate through the result set and access the column data by name. This is demonstrated in Listing 7, where a query's results are assigned to a scoped variable namedqueryResults, the rows of which are then iterated over using the core library's <c:forEach> tag. Nested <c:out> tags take advantage of the EL's built-in support

for Map collections to look up row data corresponding to column names. (Recall from Part 1 that ${row.title} and ${row["title"]} are equivalent expressions.) Listing 7 also demonstrates the use of <sql:setDataSource> to associate a datasource with a scoped variable, which is subsequently accessed by the <sql:query> action through its dataSource attribute.

Listing 7. Using <sql:query> to query a database, and using <c:forEach> to iterate through the result set
<sql:setDataSource var="dataSrc" url="jdbc:mysql:///taglib" driver="org.gjt.mm.mysql.Driver" user="admin" password="secret"/> <sql:query var="queryResults" dataSource="${dataSrc}"> select * from blog group by created desc limit ? <sql:param value="${6}"/></sql:query> <table border="1"> <tr> <th>ID</th> <th>Created</th> <th>Title</th> <th>Author</th> </tr> <c:forEach var="row" items="${queryResults.rows}"> <tr> <td><c:out value="${row.id}"/></td> <td><c:out value="${row.created}"/></td> <td><c:out value="${row.title}"/></td> <td><c:out value="${row.author}"/></td> </tr> </c:forEach> </table>

Figure 2 shows sample page output corresponding to the JSTL code in Listing 7. Note also that the SQL statement appearing in the body of the <sql:query> action in Listing 7 is parameterized.

Figure 2. Output of Listing 7

Within an <sql:query> action, SQL statements specified either as body content or through the sql attribute can be parameterized using the ? character. For each such parameter in the SQL statement, there should be a corresponding<sql:param> or <sql:dateParam> action nested in the body of the <sql:query> tag. The <sql:param> tag takes a single attribute -- value -- for specifying the parameter value. Alternatively, when the value for the parameter should be a character string, you can omit the value attribute and provide the parameter value as the body content of the <sql:param> tag. Parameter values representing dates, times, or time stamps are specified using the <sql:dateParam> tag, using the following syntax:
<sql:dateParam value="expression" type="type"/>

For <sql:dateParam>, the expression for the value attribute must evaluate to an instance of the java.util.Date class, while the value of the type attribute must be either date, time, or timestamp, depending upon which of these three types of time-related values is required by the SQL statement. Like <sql:query>, the <sql:update> action supports three forms:
<sql:update sql="expression" dataSource="expression" var="name" scope="scope"/> <sql:update sql="expression" dataSource="expression" var="name" scope="scope"> <sql:param value="expression"/> ... </sql:update> <sql:update dataSource="expression" var="name" scope="scope"> SQL statement <sql:param value="expression"/> ... </sql:update>

The sql and dataSource attributes have the same semantics for <sql:update> as they do for <sql:query>. Similarly, thevar and scope attributes are again used to specify a scoped variable, but in this case the value assigned to the scoped variable will be an instance of java.lang.Integer indicating the number of rows that were changed as a result of executing the database update.

Managing transactions
Transactions are used to protect a sequence of database operations that must either succeed or fail as a group. Transaction support is built into JSTL's sql library, which makes it trivial to wrap a series of queries and updates into a transaction simply by nesting the corresponding <sql:query> and <sql:update> actions in the body content of a <sql:transaction> tag. The syntax for <sql:transaction> is as follows:
<sql:transaction dataSource="expression" isolation="isolationLevel"> <sql:query .../> or <sql:update .../> ...

The <sql:transaction> action has no required attributes. If you omit the dataSource attribute, then the JSTL default datasource is used. The isolation attribute is used to specify the isolation level for the transaction and may be eitherread_committed, read_uncommitted, repeatable_read, or serializable. If you do not specify this attribute, the transaction will use the datasource's default isolation level. As you might expect, all nested queries and updates must use the same datasource as the transaction itself. In fact, a<sql:query> or <sql:update> nested inside a <sql:transaction> action is not allowed to specify a dataSource attribute. It will automatically use the datasource associated (either explicitly or implicitly) with the surrounding <sql:transaction> tag. Listing 8 shows an example of how <sql:transaction> is used:

Listing 8. Using <sql:transaction> to combine database updates into a transaction


<sql:transaction> <sql:update sql="update blog set title = ? where id = ?"> <sql:param value="New Title"/> <sql:param value="${23}"/> </sql:update> <sql:update sql="update blog set last_modified = now() where id = ?"> <sql:param value="${23}"/> </sql:update> </sql:transaction>

Back to top

A word of caution
JSTL's xml and sql libraries enable complex functionality to be implemented in JSP pages using custom tags. At the same time, however, implementing this sort of functionality in your presentation layer may not necessarily be the best approach. For large applications being written by multiple developers over a long period of time, strict segregation between the user interface, the underlying business logic, and the data repository has proven to simplify software maintenance over the long term. The popular Model-View-Controller (MVC) design pattern is a formalization of this "best practice." In the domain of J2EE Web applications, the model is the business logic of an application, and the JSP pages comprising the presentation layer are the view. (The controllers are the

form handlers and other server-side mechanisms for enabling browser actions to initiate changes to the model and subsequently update the view.) MVC dictates that the three major elements of an application -model, view, and controller -- have minimal dependencies upon one another, restricting their interactions with each other to consistent, well-defined interfaces. An application's reliance on XML documents for data exchange and relational databases for data persistence are characteristics of the application's business logic (that is, its model). Adherence to the MVC design pattern would suggest, therefore, that these implementation details should not be reflected in the application's presentation layer (that is, its view). When JSP is used to implement the presentation layer, then, use of the xml and sql libraries would be a violation of MVC, because their use would mean exposing elements of the underlying business logic within the presentation layer. For this reason, the xml and sql libraries are best suited to small projects and prototyping efforts. Dynamic compilation of JSP pages by the application server also makes the custom tags in these libraries useful as debugging tools. Back to top

Summary
In this series, we have examined the capabilities of the four JSTL custom tag libraries and their usage. In Part 1 and Part 2, we saw how you can avoid JSP scripting elements in many common situations through use of the EL and the tags of the corelibrary. Part 3 focused on using the fmt library to localize Web content. In this final installment, we reviewed the functionality of the xml and sql libraries. If you're willing to accept the consequences of including business logic in the presentation layer, the tags in these two libraries make it very easy to incorporate content from XML documents and relational databases into JSP pages. These two libraries also demonstrate how the JSTL libraries build upon one another and interoperate when integrating <sql:query> and <c:forEach>, as well as the ability of the xml library to leverage the <c:import> action.

S-ar putea să vă placă și