Common Java Cookbook

Edition: 0.19

Download PDF or Read on Scribd

Download Examples (ZIP)

9.7. Writing Templates with Conditionals and Loops

9.7.1. Problem

Your template needs to iterate over a list of objects and highlight objects if a specific property meets a certain criteria.

9.7.2. Solution

Use a Velocity template with the #foreach and #if directives. The following Velocity template uses a #foreach to loop through a List of Airport beans and an #if to check for the location of an airport relative to the supplied $countryCode:

The World's Busiest Airports
<table>
  <tr>
    <td>Rank</td><td>Code</td><td>Name</td><td>Passengers</td>
    <td>${countryCode} Domestic</td>
  </tr>
  #foreach( $airport in $airports )
    <tr>
      <td>$velocityCount</td>
      <td>$airport.code</td>
      <td>$airport.name</td>
      <td>$airport.passengers</td>
      #if( $airport.countryCode == $countryCode )
        <td>Y</td>
      #else
        <td>N</td>
      #end
    </tr>
  #end
</table>

To render this template, a List of Airport objects and a countryCode String is created and put into a VelocityContext. The $countryCode reference is used to test the countryCode property of every Airport object in the List; if the countryCode property matches, a Y is placed in the last column. The following code initializes the Velocity engine, creates a VelocityContext, and renders the template:

import org.apache.velocity.Velocity;
import org.apache.velocity.app.VelocityContext;
// Initialize Velocity with default properties
Velocity.init( );
// Create a List to hold our Airport objects
List airports = new ArrayList( );
airports.add( new Airport(1, "ATL", "Hartsfield Atlanta", 76876128, "US" ) );
airports.add( new Airport(2, "ORD", "Chicago O'Hare", 66501496, "US" ) );
airports.add( new Airport(3, "LHR", "London Heathrow", 63338649, "UK" ) );    
airports.add( new Airport(4, "HND", "Tokyo-Haneda", 61079478, "JP" ) );
airports.add( new Airport(5, "LAX", "Los Angeles", 56198447, "US" ) );
airports.add( new Airport(6, "DFW", "Dallas/Fort Worth", 52826304, "US" ) );    
// Create a context and put a List into the context, and a country code
VelocityContext context = new VelocityContext( );
context.put( "airports", airports );
context.put( "countryCode", "US" );
// Create a Reader to read our velocity template.
Reader reader = new FileReader( new File("renew.vm") );
// Evaluate our template and write the result to a StringWriter
StringWriter writer = new StringWriter( );
Velocity.evaluate(context, writer, "test", reader);
System.out.println( writer.toString( ) );

This code produces the following output after merging the Velocity template with a VelocityContext :

The World's Busiest Airports
Rank  Code  Name                Passengers  US Domestic
1     ATL   Hartsfield Atlanta  76876128            Y
2     ORD   Chicago O'Hare      66501496            Y
3     LHR   Heathrow            63338649            N
4     HND   Tokyo-Haneda        61079478            N
5     LAX   Los Angeles         56198447            Y
6     DFW   Dallas/Fort Worth   52826304            Y

9.7.3. Discussion

The #foreach directive can iterate over arrays, Enumerations, Lists, and Sets; each element is exposed as a local reference specified in the parameter to #foreach. A #foreach block is terminated by #end. The #foreach directive also exposes a local reference $velocityCount, which holds the index of the current row, and, if you need to create a table with alternating row colors, use the velocityCount variable with the #if directive:

#foreach( $widgets in $theToolbox )
  #if( $velocityCount % 2 == 0 )
    #set( $bgColor = '#DDD' )
  #else
    #set( $bgColor = '#CCC' )
  #end
  <tr color="${bgColor}">
    <td>Some Data</td>
  </tr>
#end

The #if directive takes a boolean expression, and renders the content contained in the #if block if this expression evaluates to true. Like #foreach, an #if block is also terminated by #end. The #if directive can also be followed by an #elseif block or an #else block, as shown in the following example:

#if( $variable == "TEST" )
  This is a test.
#elseif( $variable == "SERIOUS" )
  The condition is Serious.
#elseif( $variable == "MAJOR" )
  The condition is Major.
#else
  The condition is Nominal
#end

The #foreach directive can be used to iterate over a Set of keys from a Map. To access each element in a Map, use the bracket notation shown in the following example:

#set( $keys = someMap.keySet( ) )
#foreach( $key in $keys )
  $key: $someMap[$key]
#end

9.7.4. See Also

For information about the relational and logical operators supports by Velocity, see the Velocity Template Language (VTL) Reference Guide (http://velocity.apache.org/engine/releases/velocity-1.6.1/vtl-reference-guide.html).


Creative Commons License
Common Java Cookbook by Tim O'Brien is licensed under a Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 United States License.
Permissions beyond the scope of this license may be available at http://www.discursive.com/books/cjcook/reference/jakartackbk-PREFACE-1.html. Copyright 2009. Common Java Cookbook Chunked HTML Output. Some Rights Reserved.