Merge Common Cells
The objective was to take a normal table (created by the View and Form Builder) which had many common values in the data, and merge the cells with those common records into a single cell, using the HTML rowspan attribute to cause that single cell to stretch across all the records with that value.
When you are working with the JSP for a table, you have to remember that the data doesn't actually exist yet – it won't exist until an end-user is actually running the Model and has fetched some current data from the Service. There aren't different rows of HTML that you can modify; there is only the one row, and it will be calculating all of its values from the loop variable, RowLoopVar. You make your modifications to the JSP on the page, always thinking about this pass through the code, with the current data in the Variable RowLoopVar.
This uses the Visibility Setter Builder and the Attribute Setter Builder to merge the common values. Below is the original table, with my goals to create the look shown above (only shown for the first column). I wanted to hide the extra rows, and then use the rowspan attribute to inform the cell for each new row that it should stretch down the correct length.
However, as I am modifying the page, I am thinking: "If the cell in the current row is a first value, show it; if it's a duplicate hide it. Calculate its rowspan based on how many duplicates follow it." When the code goes on to the next row, the code will be making the same evaluation, but it might come to a different conclusion because it will be working with new data.
I created two methods which can be used for any column of data. The first accepts the row and the column name and tells you whether or not this row has the first of a new value for the specified column. The second method will calculate how many rows have the common value – the number to be used in the rowspan attribute.
* Generated Method [isFirstWithValue]
public boolean isFirstWithValue(WebAppAccess webAppAccess, IXml xml, String column)
boolean result = true;
IXml prev = xml.getPreviousSiblingElement();
if (prev != null)
String prevVal = prev.getText(column);
String val = xml.getText(column);
result = val == null || !val.equals(prevVal);
* Generated Method [getDupCount]
public int getDupCount(WebAppAccess webAppAccess, IXml xml, String column)
String val = xml.getText(column);
if (val == null) return 1;
int result = 0;
while (xml != null)
xml = xml.getNextSiblingElement();
Visibility and Attribute Setter Builders
The next step was to get these calculated values into the right place in the JSP page. I wanted to put a Visibility Setter Builder on the TD, such that, when a row with the first of a new value is being processed, the TD will be visible, and when a row that contains a duplicate is being processed, the TD is not shown. The visibility setter can call the first of my two methods, above to discover whether or not the row being processed is a duplicate or not.
However, the next problem is an issue of creating the PageLocation that points to the right element in the JSP page. There is no conveniently named tag on which to hang the Visibility Setter. It has a name, but it is a name that it shares with all the columns. Fortunately, there is the SPAN tag used by the column control – it has a unique name. If we can make a PageLocation that can identify that node, then we can use the xpath syntax (in the advanced PageLocation window) to make a pagelocation that identifies its parent element, which should be the TD we want to target.
The resulting PageLocation is
Page Merge_ViewPage NameSearch Make XPath ..
This says to look on the Page "Merge_ViewPage" and search from the elements with the name "Make." From that point (actually, from each of those points, if there were more than one) traverse the XPath ".." which means traverse to your parent.
Similarly, I created an attribute setter with the same PageLocation. It sets the attribute "rowspan" to be the correct value from the second method.
After running it to confirm that it all works as expected, I added another Visibility Setter and another Attribute Setter, this time targetting the "Model" Column. The result is what you see above.
Notes on running the sample and prerequisites
Import the attached zip file into your project using the Import WebSphere Portlet Factory Archive command.