Working with Merged Cells

Several cells in a table can be merged together into a single cell. This is useful when certain rows require a title or large blocks of text which span across the width of the table. This can only be achieved by merging cells in the table into a single cell. Aspose.Words supports merged cells when working with all input formats including when importing HTML content.

In Aspose.Words, merged cells are represented by CellFormat.setHorizontalMerge(int) and CellFormat.setVerticalMerge(int). The CellFormat.getHorizontalMerge() property describes if the cell is part of a horizontal merge of cells. Likewise the CellFormat.getVerticalMerge() property describes if the cell is a part of a vertical merge of cells.

The values of these properties are what define the merge behavior of cells.

  • The first cell in a sequence of merged cells will have CellMerge.First.
  • Any subsequently merged cells have CellMerge.Previous.
  • A cell which is not merged has CellMerge.None.

work-with-merged-cells-aspose-words-java

Checking if a Cell is Merged

To check if a cell is part of a sequence of merged cells, we simply check the CellFormat.getHorizontalMerge() and CellFormat.getVerticalMerge() properties.

Example: Getting the Merge Type

Below example prints the horizontal and vertical merge type of a cell.

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
Document doc = new Document(dataDir + "Table.MergedCells.doc");
// Retrieve the first table in the document.
Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
for (Row row : table.getRows()) {
for (Cell cell : row.getCells()) {
System.out.println(printCellMergeType(cell));
}
}

Merging Cells in a Table

The same technique is used to set the merge behavior on the cells in a table. When building a table with merged cells with DocumentBuilder you need to set the appropriate merge type for each cell. Also, you must remember to clear the merge setting or otherwise all cells in the table will become merged. This can be done by setting the value of the appropriate merge property to CellMerge.None.

Example: Merging Cells Horizontally

Creates a table with two rows with cells in the first row horizontally merged.

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
public static void mergeCellsHorizontally() throws Exception {
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
builder.write("Text in merged cells.");
builder.insertCell();
// This cell is merged to the previous and should be empty.
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.endRow();
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);
builder.write("Text in one cell.");
builder.insertCell();
builder.write("Text in another cell.");
builder.endRow();
builder.endTable();
}

Example: Merging Cells Vertically

Creates a table with two columns with cells merged vertically in the first column.

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
public static void mergeCellsVertically() throws Exception {
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.insertCell();
builder.getCellFormat().setVerticalMerge(CellMerge.FIRST);
builder.write("Text in merged cells.");
builder.insertCell();
builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
builder.write("Text in one cell");
builder.endRow();
builder.insertCell();
// This cell is vertically merged to the cell above and should be empty.
builder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
builder.write("Text in another cell");
builder.endRow();
builder.endTable();
}

There are different ways to start a table. In the code snippets above builder.insertCell(); is used. Another method is to use builder.startTable(). Either approach starts a new table.

Read more: Inserting a Table using DocumentBuilder.

In other situations where a builder is not used, such as in an existing table, merging cells in this way may not be as simple. Instead, we can wrap the base operations which are involved in apply merge properties to cells into a method which makes the task much easier. This method is similar to the automation Merge method which is called to merge a range of cells in a table. The code below will merge the range of cells in the table starting from the given cell, to the end cell. This range can span over many rows or columns.

Example: Merging all Cells in a Range

A method which merges all cells of a table in the specified range of cells.

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
/**
* Merges the range of cells found between the two specified cells both
* horizontally and vertically. Can span over multiple rows.
*/
public static void mergeCells(Cell startCell, Cell endCell) {
Table parentTable = startCell.getParentRow().getParentTable();
// Find the row and cell indices for the start and end cell.
Point startCellPos = new Point(startCell.getParentRow().indexOf(startCell), parentTable.indexOf(startCell.getParentRow()));
Point endCellPos = new Point(endCell.getParentRow().indexOf(endCell), parentTable.indexOf(endCell.getParentRow()));
// Create the range of cells to be merged based off these indices. Inverse each index if the end cell if before the start cell.
Rectangle mergeRange = new Rectangle(Math.min(startCellPos.x, endCellPos.x), Math.min(startCellPos.y, endCellPos.y), Math.abs(endCellPos.x - startCellPos.x) + 1,
Math.abs(endCellPos.y - startCellPos.y) + 1);
for (Row row : parentTable.getRows()) {
for (Cell cell : row.getCells()) {
Point currentPos = new Point(row.indexOf(cell), parentTable.indexOf(row));
// Check if the current cell is inside our merge range then merge it.
if (mergeRange.contains(currentPos)) {
if (currentPos.x == mergeRange.x)
cell.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
else
cell.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
if (currentPos.y == mergeRange.y)
cell.getCellFormat().setVerticalMerge(CellMerge.FIRST);
else
cell.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);
}
}
}

Example: Merging Cells between Two Cells

Merges the range of cells between the two specified cells.

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
Document doc = new Document(dataDir + "Table.SimpleTable.doc");
// Retrieve the first table in the document.
Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
// We want to merge the range of cells found in between these two cells.
Cell cellStartRange = table.getRows().get(1).getCells().get(1);
Cell cellEndRange = table.getRows().get(2).getCells().get(2);
// Merge all the cells between the two specified cells into one.
mergeCells(cellStartRange, cellEndRange);
doc.save(dataDir + "Table.MergeCellsInARange Out.doc");

Convert To Horizontally Merged Cells

In the latest versions of MS Word, the cells are merged horizontally by its width. Whereas, the merge flags were used in the older technique,  like Cell.CellFormat.HorizontalMerge. The merge flags are not used when cells are horizontally merged by their width and it is also not possible to detect which cells are merged. Aspose.Words provides ConvertToHorizontallyMergedCells method to convert cells which are horizontally merged by its width to the cell horizontally merged by flags. It simply transforms the table and adds new cells when needed.

The following code example shows the working of the above-mentioned method.

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java
Document doc = new Document();
Table table = doc.getFirstSection().getBody().getTables().get(0);
table.convertToHorizontallyMergedCells(); // Now merged cells have appropriate merge flags.