Iterator Tags — Functional Description

<forEach>
<forTokens>


1. Introduction

The <forEach> tag repeats its nested body content over the collection of objects defined by the items attribute. For example, the JSP code below creates an HTML table with one column that shows the default display value of each item in the collection.
  <table>
    <c:forEach var="customer" items="$customers">
      <tr><td><c:expr value="$customer"/></td></tr>
    </c:forEach>
  </table>
The forEach tag has the following features: The forEach tag is the base iteration tag. It handles the most common iteration cases conveniently. Other iteration tags are also provided in the stardard tag library to support specific, specialized functionality not handled by the forEach tag (e.g. the forTokens tag). Developers can also easily extend the behavior of this base iteration tag to customize it according to an application's specific needs.

2. Collection of objects to iterate over

The forEach tag supports the following data types for the collection of objects to iterate over. The items attribute is optional. If it is not specified, the range attributes must be specified to iterate a specific number of times over the tag's body.

3. The current item

The current item of the iteration is made available via a JSP page scope attribute defined with attribute var. Attribute var has nested visibility, i.e. it only exists within the body of the <forEach> tag. At the end of the tag, the attribute is removed (no prior value is restored). Attribute var is optional. The page attribute is not created if a value is not defined for var.

Normally, each object exposed by the forEach tag is an item of the underlying collection being iterated over. However, if iterating over a Map or a ResultSet, the exposed object is as follows:

If items is of type Map, then the current item will be of type Map.Entry which has the following two properties:

So, to iterate over the values of a Hashtable, the code would be implemented as follows:

  <c:forEach var="entry" items="$myHashtable"/>
    Next element is <c:expr value="$entry.value/>
  </c:forEach>

If items is of type ResultSet, then the current item is the ResultSet object itself positioned at the current row. Columns are accessed using the standard ResultSet API.

5. Iteration Status

The iterator tag also makes available a wealth of information relative to the iteration taking place. The set of properties supported by the status object is described here.

This status information is accessible by defining a JSP page scope attribute via the status attribute. This page scope attribute has nested visibility, i.e. it only exists within the body of the <forEach> tag. At the end of the tag, the attribute is removed (no prior value is restored). This is an optional attribute with no default. No page attribute is exposed if a value is not specified for the status attribute.

In the example below, the JSP code creates an HTML table with the first column containing the position of the item in the collection, and the second containing the name of the employee.

  <table>
    <c:forEach var="employee" items="$employees" status="status">                                       
      <tr>
        <td><c:expr value="$status.count"/></td>
        <td><c:expr value="$employee.name"/></td>
      </tr>
    </c:forEach>
  </table>

6. Range Attributes

A set of range attributes is available to iterate on a subset of the collection of items. The begin and end indices can be specified, along with a step. If the items attribute is not specified, then the value of the current item is set to the integer value of the current index.

In this example, i would take values from 100 to 110 (included).

  <c:forEach var="i" begin="100" end="110">
    <c:expr value="$i"/>
  </c:forEach>
specified not specified
begin iteration starts at the item located at the specified index. First item in the collection is at index 0. Iteration starts at the first item if items is specified. Illegal if items is also not specified.
end iteration ends at the item located at the specified index (inclusive) Iteration ends at the last element in the collection. Illegal if items is also not specified.
step the iteration will only process every 'step' item of the collection, starting with the first one Every item in the collection is processed

8. Attributes:

collection to iterate over
items optional expr The collection of objects to iterate over. If not specified, the range attributes begin and/or end are required to specify the range of the iteration (for loop).
current item
var optional String Name of the page scope attribute used to store the current object being iterated over. Visibility is "nested".
iteration status
status optional String Name of the variable used to store the current status of the iteration. Visibility is "nested".
range
begin optional expr Iteration begins at the item located at the specified index. First item has index 0.
end optional expr Iteration ends at the item located at the specified index (inclusive).
step optional expr Iteration will only process every 'step' item of the collection.

9. IteratorTagStatus

The iteration status object (attribute status) has the following properties.
 
current item
current Object The current item. This object is also accessible directly from the IteratorTag interface. It is also made available here as a convenience.
current index / position
index int The absolute, 0 based index of the current item.
count int The relative, 1 based position of the current item. This increases by 1 for each item, regardless of begin, end, or step.
first boolean Flag indicating if the current item is the first in the iteration.
last boolean Flag indicating if the current item is the last in the iteration. This property is not supported when iterating over a ResultSet and step is > 1. 
range
These values (combined with count) are important for allowing people to define special tags that tell when you're in the middle of a list, or when you're in an even or odd part of the list, etc. Because these values might have been specified as complex rtexprvalues or EL expressions, it's valuable to have these in a "precomputed" form.
beginSpecified boolean Flag indicating if the begin attribute was specified.
begin int The value of the begin attribute as specified in the tag. If the attribute was not specified, its corresponding value is undefined.
endSpecified boolean Flag indicating if the end attribute was specified.
end int The value of the end attribute as specified in the tag. If the attribute was not specified, its corresponding value is undefined.
stepSpecified boolean Flag indicating if the step attribute was specified.
step int The value of the step attribute as specified in the tag. If the attribute was not specified, its corresponding value is undefined.

10. Tag Collaboration

Custom tags give developers the power to provide added functionality to a JSP application without having the page author to use Java code.

In this example, a page author must handle an item of the iteration differently depending whether it is an odd or even element.

  <c:forEach var="product" items="products" status="status">
    <c:declare id="status" type="javax.servlet.jsp.jstl.core.IteratorTagStatus"/>

    <c-rt:choose>
      <c-rt:when test="<%= status.getCount() % 2 == 0 %>">
        <!-- even item -->
      </c-rt:when>
      <c-rt:otherwise>
        <!-- odd item -->
      </c-rt:otherwise>
    </c-rt:choose>
  </c:forEach>

If this type of processing needs to be repeated often in the web applications of a company, it might be worth to provide page authors with a couple extra tags that would remove the need for conditional tags and expressions. For example:

  <c:forEach items="$products">
    <xyz:even>
      <!-- even item -->
    </xyz:even>
    <xyz:odd>
      <!-- odd item -->
    </xyz:odd>
  </c:forEach>

In order to make this possible, tags like <odd> and <even> need to be able to get access to the information exported by the forEach tag. This could be done explicitely, by specifying the name of the status object exported by the forEach tag. For example:

  <c:forEach items="<%=products%>" status="status">
    <xyz:even iter="status">
      <!-- even item -->
    </xyz:even>
    <xyz:odd iter="status">
      <!-- odd item -->
    </xyz:odd>
  </c:forEach>

The cooperation between these tags and the forEach tag can also be done implicitely via the findAncestorWithClass() method of the JSP API. This is possible because the forEach tag implements an interface that can be used in the call to findAncestorWithClass to get to the enclosing forEach tag.

The interface is defined as follows:

  interface IteratorTag {
    public Object getCurrent();
    public IteratorTagStatus getIteratorStatus();
  }

Interface IteratorTagStatus was described in a previous section.

The fact that the forEach tag exposes an interface also means that other tags with iterative behavior can be developed using the same interface and will collaborate in the same manner with nested tags. See class IteratorTagSupport below to make this process even easier.

11. Tag Extensibility

The forEach tag provides iteration capabilities for the most common cases. A developer simply needs to expose an appropriate kind of object to take advantage of it.

However, there will be situations where more specialized functionality will be required. A developer may need to write a new tag to expose new controlling functionality (e.g. for traversal order of a deep data structure, custom filtering, selection of appropriate objects from a custom data source). This is why the IteratorTagSupport class is provided. It will facilitate the implementation of specialized iterator tags that will meet an application's specific requirements.

  public abstract class IteratorTagSupport {
     ... (see source code)...
  }
JSTL itself uses this inheritance-based mechanism to support additional specialized iterator tags. For example, the <forTokens> tag is specialized to support string tokens. It leverages the iteration behavior implemented in IteratorTagSupport, and simply exposes a set of attributes that facilitate the specification of how tokens are derived from a String object.