Skip to main content

Practical JSTL, Part 2

November 27, 2003

{cs.r.title}






In part 1 of
this series, we took a look at the basic idea behind the JSP Standard Tag
Library (JSTL) and the powerful standard actions that are provided within it.
We had an overview of the functionality of the Core tag library, as well as how
you can use the Expression Language (EL). In part 2, we'll take a look at some
of the other functionality provided for us. We'll touch base on the available
standard actions contained within the JSTL in the XML, I18N, and SQL libraries.

The following sections are excerpted from various sections and chapters within JSTL: Practical Guide for JSP Programmers. You can find complete details all of the standard actions available in the JSTL, as well as a developer's quick reference guide, provided in the book. The book also has a free download available. The download demonstrates the use of each standard action.

Working with XML Actions

The XML tag library brings us to actions that deal with XML manipulations. I am hardput to think of any application that I've developed in the last few years
that didn't use XML to represent the data in the web tier. XML is the data
format of choice for exchanging information. Keeping this in mind, it's
relevant to discuss the number of actions that JSTL provides to help a page
author deal with XML. You will find a strong similarity between the XML core
actions and the actions provided in the Core tag library. But there is a
difference; the XML core actions use XPath for their expression language.

Using the Select Attribute

All of the XML actions of JSTL allow a way to specify XPath expressions. This is
accomplished by using the select attribute. The select attribute is always specified as a
string literal that is evaluated by the XPath engine. It was decided to have a
dedicated attribute for XPath expressions so as to avoid confusion. Since some
of the XML actions have similar functions to the Core actions, it was important
not to get the XPath expression confused with the JSTL expression language. The
select attribute is shown in this simple sample where the XPath expression specifies the title to be selected from the XML document and output to the JspWriter <x:out select="$catalog/book/title"/>

Accessing Resources

When using XML actions, obviously one of the first things we want to do is access some type of
resource, such as an existing XML document. This is done by importing resources
using the Core URL action <c:import>. The resource can then be used by
such XML actions as <x:parse> and <x:transform>. For example, we can import a URL resource and then export it into a variable named xml. This variable is then used as
the XML document to the parse action, as shown in the sample below.

<c:import
url="http://www.mkp.com/book?id=12345"
var="xml"/>
<x:parse xml="${xml}"
  var="doc"/>

Parsing XML Documents

The first step required before being able to access any of the information contained in
an XML document is that it must be parsed. Usually, there is an existing document that
you want to be working with. This document might be the result of some business
logic that was performed in the business tier of your application. We want now
to deal with it in the presentation tier so that we can display the results
appropriately. Using the <x:parse> action is how we get the
information from XML format into some format that can be used by XPath, and
XSLT. <x:parse> takes a source XML document,
parses it, and produces a scoped variable that holds the results. The variable
can be defined by either using the var or varDom attribute. There are two different types of attributes because there are a number of ways to represent XML documents. JSTL provides the
flexibility for the implementer of the specification to return an object of its
choosing in the var attribute.

Action

The <x:parse> action is used to parse an XML
document. The resulting object is then saved into a scoped variable as defined
by either the var or the varDom attribute. The varDom attribute is a String that holds the name of the scoped variable. The type of the scoped variable is an org.w3c.dom.Document. The type of the attribute depends on the implementation of the <x:parse> action, so you will need to consult the documentation for it. In the reference implementation of the JSTL, the type of the scoped variable as defined by var is also of the type org.w3c.dom.Document. The <x:parse> action performs the parse on the document; it does not perform any validation against Document Type Definition files (DTDs) or Schemas. The XML document to be used for the parse can either be specified with the xml attribute, or it can be specified inline by including it the action's body content.

The varDom attribute exposes a DOM document, making it possible to use the variable for collaboration with other custom actions you might have created. Objects exposed by var and varDom can be used to set the context of an XPath expression. This is exactly what we'll see in our <x:set> and <x:out> example when we reference the $doc in the select attribute. In the sample below, we import a document using the <c:import> action. Then we use that XML document for the parse. The results are stored in the var attribute of the parse action. We then use doc as the context for our other XML actions.

<c:import
url="http://www.mkp.com/catalog.xml"
var="xml"/>

If your source XML document is null or empty, a JspException will be thrown.

A common way to identify the XML file is to use the parse to expose it as an imported
resource. By using the <c:import> action, we access the XML file and
then use the EL to pass it to the <x:parse>. This is shown in Example 1.

Example 1. Using an Imported XML Document

<c:import var="xmlfile"
url="/people.xml" />
<x:parse var="doc"
xml="${xmlfile}" />
Hello <x:out
select="$doc/person/firstname" />

Using XML Documents to Determine Flow Control

While the XML core actions provide the basic functionality to parse and access XML data,
the XML flow control actions are used to do conditional processing and
iterations. The same way that we used various Core actions for flow control in
our JSPs can be applied to the conditional actions available in the XML tag
library. In fact, the XML actions mimic the Core actions. The actions available
are:

  • <x:if>
  • <x:choose>
  • <x:when>
  • <x:otherwise>
  • <x:forEach>

The only difference between the two libraries, which you might have guessed by now, is
the fact that the select attribute uses XPath
instead of the EL when working with the <x> actions. Using XPath
expressions, the XML control flow actions determine whether to process JSP
code. These actions act in much the same way as the Core tag library flow
control actions we already talked about, except for the utilization of XPath
instead of the expression language. Therefore, to avoid redundant information,
I am going to point out the differences between the XML and the Core actions (<c:if>, <c:choose>, and <c:forEach>), where appropriate.

The biggest difference is that the select attribute is
evaluated to a boolean expression, according
to the semantics of the XPath boolean() function. Otherwise,
everything that you've already learned applies to the control flow actions can
be applied here as well. You'll notice that before you do any type of control
flow, you always have to have a document available. This means that you always
have to do an <x:parse> on the document so
that it can be accessed through a variable.

The XML actions play an important role in today's web applications. Since XML is
omnipresent, dealing with XML documents becomes much easier with the actions
provided in the XML tag library. Using the XML actions, it's possible to do all
sorts of data comparison, iteration, and transformations using XSLT. All of
these actions should make your page authoring that much easier. In order to
make the best use of the XML actions, it is important to have a firm
understanding of XPath and XSL at the very least.

Working with the Internationalization and Formatting Actions

More than likely, the application you are developing today will have to be
internationalized tomorrow. Wouldn't it be great if the effort required to
internationalize your application could be reduced to zero? Well OK, that might be too optimistic to hope for since anyone who has developed applications
for international use knows there is always something that needs to be tweaked.
Luckily, the internationalization and formatting actions provided in the JSTL
are a comprehensive set of actions that can be used to minimize the headaches
of having to internationalize your application. These actions come under the
functionality of the I18N umbrella. I18N, which refers to the 18 letters
between the I and the N in internationalization, is a common acronym used when
talking about internationalization features. (It is also common to use the term L10N, for localization.)

In this section, we'll look at an overview of the tags provided for internationalization, and then do simple text substitution with the <fmt:message> tag. Refer to chapter 6 of the JSTL: Practical Guide for great details on how to work with Locales, resource bundles, and all of the I18N standard actions.

All of the actions related to I18N are contained in the custom tag library with the
URI http://java.sun.com/jstl/fmt and are frequently accessed by using the fmt prefix.

The I18N functional area can be broken down into two main areas:

1. Locale and resource bundles that include such actions as:

  • <fmt:setlocale>
  • <fmt:bundle>
  • <fmt:setBundle>
  • <fmt:message>
  • <fmt:param>
  • <fmt:requestEncoding>

2. Formatting for numbers, dates, and currency, which includes such actions as:

  • <fmt:timeZone>
  • <fmt:setTimezone>
  • <fmt:formatNumber>
  • <fmt:parseNumber>
  • <fmt:formatDate>
  • <fmt:parseDate>

First, the Action

Let's introduce the <fmt:message> action. If you really want to do
the bare-bones amount of work necessary to build an internationalized application,<fmt:message> is the only action that you'll need to consider. The <fmt:message> action takes advantage of the LocalizationContext. By using the <fmt:message>, you can output values from your
resource bundles as simply as:

<fmt:message key="welcome"/>

The appropriate resource bundle will be used to look up the key "welcome" and the
translated string will be provided. This is about as easy as it gets to incorporate international support into your application. The <fmt:message> action also supports parameterized content, also called parametric replacement. For example, you can provide variables that will be used within the string used by the key attribute. Say we want to personalize our welcome page and pass the name of a user so we can welcome them. To do this, we use the <fmt:param> subtag. A quick example, so that you are familiar with the format, the action might look like:

<fmt:message key="welcome">
<fmt:param value="${userNameString}"/>
</fmt:message>

In this example, we would be accessing a variable already set, called userNameString, which would then be used as a parameter to the message. If we were accessing the English version of the resource bundle, Welcome Sue would appear in the JspWriter.

Using the SQL Actions

The JSTL includes a number of actions that provide a mechanism for interacting with
databases. The previous sentence should, at a very minimum, send up a red flag
in your architectural visions. One might ask, "Do I really want to be able to
perform SQL actions such as queries, updates, and transactions from my JSP?
Isn't that business logic that belongs in the model?" The answer is yes. Yes,
yes, yes. To follow a Model-View-Controller
(MVC) architecture, which is the predominant design pattern used in building
web applications today, you definitely want to keep your model information in
your business logic. This means that you don't want it in your JSPs. Why then are
these actions even provided in the JSTL? Good question and one that I've
discussed with various members of the JSR-53 expert group. The reason is the
"C" or community in the Java Community Process (JCP). The community has asked
for it, the community has gotten it.

Many feel that for prototyping, small-scale, and/or very simple applications, or if
you just don't have the engineering staff to implement a full MVC model, then
the SQL actions might prove useful. While I can (barely) see the point being
made for use of the SQL actions for prototyping or small-scale applications, I
can't ever validate the argument that you just don't have the time to implement
an MVC model correctly. If that is the one and only reason why you are choosing
to use the SQL actions, then I suggest that you investigate using such
frameworks as Struts, which are part of the Jakarta projects and can be found at http://jakarta.apache.org/struts/index.html. Struts is an MVC framework that can be learned quickly and will provide a much cleaner architecture than having
Model information located throughout your JSPs. For a complete discussion on
Struts 1.1 along with a full sample application, refer to The Struts Framework: Practical Guide for Java Programmers.

If you are careful about how you code your SQL actions, it should be easy enough to
pull out the code and put it into classes that represent the Model interaction
at a later point. I am not going to go into the various design patterns that
can be applied for doing business or integration tier access. But if you
consider using the SQL actions in your application, it would be wise at least
to familiarize yourself with such common patterns as Transfer Objects, JDBC for Reading,
Data Transfer Object (DTO), Factory, Data Transfer Hashmap,and Data Transfer Rowset.
Doing so may help you avoid embedding the business logic/data access into your
JSPs so deeply that you are left with a tangled mess.

With that said, I don't consider it an architectural flaw to have the SQL actions
included in the JSTL. However, I do consider it an architectural flaw to use
them in your application development. It is up to the page author and
application architect to make sure that the design patterns are being adhered
to correctly, if not for the maintenance issue of the application then for the
practice of good engineering. However, since these actions are included in the
JSTL, I must make sure you understand them and their features so that you can
make an informed decision.

The JSTL SQL actions provide functionality that allows for:

  • Making database queries
  • Accessing query results
  • Performing database modifications
  • Database transactions

What all of the SQL actions have in common is that they work against a specific data
source.

The Available Actions

There are six actions provided in this tag library:

  • <sql:setDataSource> for exporting a variable that defines a data source
  • <sql:query> for querying to the database
  • <sql:update> for updating the database
  • <sql:transaction> for establishing a transaction context for doing queries and updates
  • <sql:param> for setting parameter markers ("?") used in SQL statements.

The <sql:setDataSource> is used to export a data source
either as a scoped variable or as the javax.servlet.jsp.jstl.sql.dataSource data source
configuration variable.

Using the var and scope attributes, the data source specified (either as a DataSource object or as a String) is exported. If no var is specified, the data source is exported in the javax.servlet.jsp.jstl.sql.dataSource configuration variable.

The data source may be specified by using the dataSource attribute. This can be specified as a DataSource object, as a Java Naming and Directory Interface (JNDI) relative path, or using a JDBC parameters string. If you don't want to use the dataSource attribute, it is also possible to specify the data source by using the four JDBC parameter attributes. All four of the parameters are just String types. These attributes are driver, url, user, and password. Using the JDBC attributes is just an easier way to configure the data source than specifying the values in the string syntax for the dataSource attribute. In Example 2 we see how to specify a data source using the JDBC parameters. We are making this data source available as an exported variable called datasource. This can then be used by other actions if they want to use this particular data source, as shown by the action.

Example 2. Setting a Data Source

<sql:setDataSource
var="datasource"
driver="org.gjt.mm.mysql.driver"
url="jdbc:mysql://localhost/db"
user="guest"
password="guest"/>
<sql:query datasource="${datasource}"
... />

Action

No mystery here, the <sql:query> action is used to
query a database. There are a number of attributes that are used with this
action. It is possible to specify a data source by using the dataSource attribute. If present, it will
override the default data source. If the dataSource is null, then a JspException is thrown. If a dataSource is specified, then the <sql:query> action must be specified inside of
a <sql:transaction> action. We won't go
into details about the <sql:transaction> in this article, but
you can find out the details in chapter 7 of the JSTL: Practical Guide.

A single result set is returned from a query. If the query produces no results, an empty
Result object (of size zero) is returned.
This would be the case for a SQL statement that contained an INSERT, DELETE, UPDATE, or any SQL statement that
returns nothing such as a SQL DDL statement. Returning an object of size zero
is consistent with the way return values are handled by the executeUpdate() method of the JDBC Statement class. This result set contains
rows of data if there are results. The data is then stored in a scoped variable
that is defined by the var and scope attributes. The default scope is page.

Obviously, there must be a way to specify the SQL query to be used. This can be done by
using the sql attribute, or by including the SQL
statement in the action's body content.

The code in Example 3 and that in Example 4 do exactly the same thing.

Example 3. SQL Defined in Attribute

<sql:query
sql="SELECT * FROM books WHERE title = 'JSTL' ORDER BY author"
var="titles"
dataSource="${datasource}" >
</sql:query>

Example 4. SQL In Body Content

<sql:query
var="titles" dataSource="${datasource}" >
SELECT * FROM books WHERE title = 'JSTL' ORDER BY author
</sql:query>

Summary

At this point, you should have a full appreciation for the power that the JSTL can
provide. By reading both of the excerpt articles, I hope you have seen that
this is just the tip of the iceberg. There are so many projects out there that
have JSP code that can utilize the JSTL. A great place to start is just refactoring some of the pages you might already have. You'll see how easy and efficient it is using the JSTL when compared with debugging through scriptlet code
that might be scattered throughout the pages. I hope that the JSTL: Practical Guide for JSP Programmers helps you get a headstart on everything you need to know about the JSTL.

Sue Spielman is president and senior consulting engineer for Switchback Software LLC , author of a number of books, and a speaker on various Java topics around the country.
Related Topics >> Web Development Tools   |