Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
The Apache Velocity template engine simplifies creation of textual content by merging data contained in a Java object model with Velocity templates. But creating complex HTML tables with cells that span multiple columns and rows can lead to elaborate nested hierarchies of Velocity directives, which quickly render the Velocity template difficult to read and maintain. In this article Matthias Laux introduces a Java package that simplifies handling of even highly complex HTML tables, using a small number of directives while retaining all the benefits of Velocity for HTML generation. The package is independent of Apache Velocity and can potentially be used with other rendering schemes, such as JavaServer Pages.
I've worked on several projects that required generated HTML pages to display large amounts of data, typically available in a database or as XML files. To apply the well-established Model-View-Controller paradigm, I used Apache Velocity as the template engine to generate all the pages. The controller application's task was to read the data, fill in some Java data structures based on the data model for a given use case, and merge the data objects with Velocity templates.
Most of the data I worked with required extensive use of HTML tables on the Velocity side. The data contained hierarchical
information, so the tables became increasingly complex because cells had to be merged using rowspan or colspan attributes to reflect the hierarchies. Correct output of required HTML markup elements such as <tr> and <td>, and the use of rowspan and colspan attributes, had to be controlled by Velocity directives (such as #if ... #end), which eventually overwhelmed the template's HTML code. This recurring pattern led me to implement a general solution for
handling complex tables in this context. Beyond basic functionality, I wanted the solution to include some convenience features,
such as:
This article introduces my solution: a Java package that takes the complexity out of HTML table generation with Velocity. First I'll demonstrate how complex tables lead to overly complex Velocity templates. Then I'll show you how you can use my solution to generate a complex table with minimal Java code and a few Velocity directives. Finally, with the help of a real-world example, you'll learn how to take advantage of the package's convenience features.
Table 1 is an (abridged) example of a fairly complex table. Several of its cells are combined via rowspan attributes.
The values of the rowspan attributes in Table 1 must be assigned dynamically at page-creation time, because the number of hierarchy elements (MainTopic,
Topic, and SubTopic), and the string values, aren't known until then. For this reason, the Velocity template must handle the
required HTML output, causing the template to be cluttered with directives to handle all possible cases. As you can see in
Listing 1, the template contains several references to the data model objects (such as $categoryData).
<table cellpadding="2" cellspacing="1" border="1" style="empty-cells:show">
<tr bgcolor="$headerBackgroundColor">
<td align="center"> $headerFontOn MainTopic $headerFontOff
<td align="center"> $headerFontOn # $headerFontOff
<td align="center"> $headerFontOn Topic $headerFontOff
<td align="center"> $headerFontOn # $headerFontOff
<td align="center"> $headerFontOn SubTopic $headerFontOff
<td align="center"> $headerFontOn # $headerFontOff
</tr>
#foreach ( $mainTopic_Name in $categoryData.backlogElements.keySet() )
#set ( $mainTopic_Category = $categoryData.categories.get($mainTopic_Name) )
#set ( $mainTopic_Category_BacklogElementCount = $categoryData.backlogElements.get($mainTopic_Name).size() )
#set ( $topic_Category_Count = $mainTopic_Category.backlogElements.size() )
#set ( $rowCount1 = 0 )
#foreach ( $topic_Name in $mainTopic_Category.backlogElements.keySet() )
#set ( $topic_Category = $mainTopic_Category.categories.get($topic_Name) )
#foreach ( $subTopic_Name in $topic_Category.backlogElements.keySet() )
#set ( $rowCount1 = $rowCount1 + 1 )
#end
#end
#set ( $first1 = 1 )
#foreach ( $topic_Name in $mainTopic_Category.backlogElements.keySet() )
#set ( $topic_Category = $mainTopic_Category.categories.get($topic_Name) )
#set ( $topic_Category_BacklogElementCount = $mainTopic_Category.backlogElements.get($topic_Name).size() )
#set ( $subTopic_Category_Count = $topic_Category.backlogElements.size() )
#set ( $rowCount2 = 0 )
#foreach ( $subTopic_Name in $topic_Category.backlogElements.keySet() )
#set ( $rowCount2 = $rowCount2 + 1 )
#end
#set ( $first2 = 1 )
#foreach ( $subTopic_Name in $topic_Category.backlogElements.keySet() )
#set ( $subTopic_Category_BacklogElementCount = $topic_Category.backlogElements.get($subTopic_Name).size() )
<tr>
#if ( $first1 == 1 )
<td rowspan="$rowCount1" valign="top">
$plainFontOn
<a href="#$formatter.getAnchorName($mainTopic_Name)">
$mainTopic_Name
</a>
$plainFontOff
</td>
<td rowspan="$rowCount1" valign="top"
bgcolor="$colorScheme.getNextColor($mainTopic_Category_BacklogElementCount, $maxCount)">
$plainFontOn
$mainTopic_Category_BacklogElementCount
$plainFontOff
</td>
#set ( $first1 = 0 )
#end
#if ( $first2 == 1 )
<td rowspan="$rowCount2" valign="top">
<a href="#$formatter.getAnchorName($mainTopic_Name, $topic_Name)">
$plainFontOn $topic_Name $plainFontOff
</a>
</td>
<td rowspan="$rowCount2" valign="top"
bgcolor="$colorScheme.getNextColor($topic_Category_BacklogElementCount, $maxCount)">
$plainFontOn $topic_Category_BacklogElementCount $plainFontOff
</td>
#set ( $first2 = 0 )
#end
<td valign="top">
<a href="#$formatter.getAnchorName($mainTopic_Name, $topic_Name, $subTopic_Name)">
$plainFontOn $subTopic_Name $plainFontOff
</a>
</td>
<td valign="top" bgcolor="$colorScheme.getNextColor($subTopic_Category_BacklogElementCount, $maxCount)">
$plainFontOn $subTopic_Category_BacklogElementCount $plainFontOff
</td>
</tr>
#end
#end
#end
<tr bgcolor="$subHeaderBackgroundColor">
<td> $plainFontOn <b> Total Count </b> $plainFontOff
<td> $plainFontOn <b> $cnt1 </b> $plainFontOff
<td> $plainFontOn <b> Total Count </b> $plainFontOff
<td> $plainFontOn <b> $cnt2 </b> $plainFontOff
<td> $plainFontOn <b> Total Count </b> $plainFontOff
<td> $plainFontOn <b> $cnt3 </b> $plainFontOff
</tr>
</table><p>
Clearly, the Velocity directives in Listing 1 predominate over the actual formatting of the output, making the HTML code that controls the page's appearance difficult to read and maintain.
Archived Discussions (Read only)