Kết hợp các ô bảng

Đôi khi một số hàng trong bảng cần tiêu đề hoặc các khối văn bản lớn chiếm đầy chiều rộng của bảng. Để thiết kế bảng đúng cách, người dùng có thể hợp nhất nhiều ô vào một. Aspose.Words hỗ trợ các ô được hợp nhất khi làm việc với tất cả các định dạng nhập, bao gồm nhập nội dung HTML.

Cách Nối Thép Sàn Bảng

Trong Aspose.Words, các ô kết hợp được biểu diễn bởi thuộc tính sau của lớp CellFormat:

  • HorizontalMerge mô tả nếu ô là một phần của sự hợp nhất ngang giữa các ô
  • VerticalMerge mô tả nếu tế bào là một phần của sự hợp nhất theo chiều dọc của các tế bào

Giá trị của các thuộc tính xác định hành vi hợp nhất của các ô:

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

Kiểm tra nếu một tế bào được hợp nhất

Để kiểm tra một ô có thuộc chuỗi các ô hợp nhất hay không, chúng ta chỉ cần kiểm tra tính chất HorizontalMergeVerticalMerge của nó.

Ví dụ sau cho thấy cách in loại hợp nhất các ô ngang và dọc:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document(getMyDir() + "Table with merged cells.docx");
Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
for (Row row : (Iterable<Row>) table.getRows())
{
for (Cell cell : (Iterable<Cell>) row.getCells())
{
System.out.println(printCellMergeType(cell));
}
}

Merge Cell Khi Sử Dụng DocumentBuilder

Để kết hợp các ô trong một bảng được tạo bằng DocumentBuilder, bạn cần thiết lập loại kết hợp thích hợp cho từng ô nơi dự kiến sự kết hợp – lần đầu tiên CellMerge.First và sau đó là CellMerge.Previous.

Và bạn phải nhớ xóa cài đặt hợp nhất cho các ô mà không cần hợp nhất – điều này có thể thực hiện bằng cách đặt ô đầu tiên không hợp nhất là CellMerge.None. Nếu không thực hiện điều này thì tất cả các ô trong bảng sẽ được hợp nhất.

Mã ví dụ sau cho thấy cách tạo một bảng với hai hàng trong đó các ô ở hàng đầu được kết hợp ngang:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
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();
doc.save(getArtifactsDir() + "WorkingWithTables.HorizontalMerge.docx");

Mã ví dụ sau cho thấy cách tạo một bảng hai cột, trong đó các ô ở cột đầu tiên được kết hợp theo chiều dọc:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
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();
doc.save(getArtifactsDir() + "WorkingWithTables.VerticalMerge.docx");

Hợp nhất các ô bảng trong các trường hợp khác

Trong các tình huống khác mà " DocumentBuilder " không được sử dụng, chẳng hạn như trong một bảng hiện có, việc hợp nhất các ô theo cách trước đây có thể không dễ dàng bằng. Thay vì, chúng ta có thể bọc các thao tác cơ bản liên quan đến việc áp dụng tính năng hợp nhất vào các ô trong một phương pháp khiến nhiệm vụ này dễ dàng hơn nhiều. Phương pháp này tương tự phương pháp tự động hóa “Merge”, được gọi để hợp nhất một phạm vi các ô trong bảng.

Mã dưới đây sẽ kết hợp các ô trong phạm vi được chỉ định, bắt đầu từ ô đã cho và kết thúc tại ô cuối. Trong trường hợp này, khoảng cách có thể trải dài trên nhiều hàng hoặc cột:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
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 a range of cells to be merged based on these indices.
// Inverse each index if the end cell is before the start cell.
Rectangle mergeRange = new Rectangle(Math.min(startCellPos.x, endCellPos.y),
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))
{
cell.getCellFormat().setHorizontalMerge(currentPos.x == mergeRange.getX() ? CellMerge.FIRST : CellMerge.PREVIOUS);
cell.getCellFormat().setVerticalMerge(currentPos.y == mergeRange.getY() ? CellMerge.FIRST : CellMerge.PREVIOUS);
}
}
}
}

Mã ví dụ sau cho thấy cách kết hợp một phạm vi các ô giữa hai ô được chỉ định:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document(getMyDir() + "Table with merged cells.docx");
Table table = doc.getFirstSection().getBody().getTables().get(0);
// We want to merge the range of cells found inbetween these two cells.
Cell cellStartRange = table.getRows().get(0).getCells().get(0);
Cell cellEndRange = table.getRows().get(1).getCells().get(1);
// Merge all the cells between the two specified cells into one.
mergeCells(cellStartRange, cellEndRange);
doc.save(getArtifactsDir() + "WorkingWithTables.MergeCellRange.docx");

Các ô hợp nhất thẳng đứng và ngang trong bảng HTML

Như chúng ta đã nói trong các bài trước, một bảng trong Microsoft Word là một tập hợp các hàng độc lập. Mỗi hàng có một tập các ô không phụ thuộc vào các ô của các hàng khác. Và Aspose.Words hỗ trợ khái niệm bảng này.

Một bảng trong HTML có cấu trúc cơ bản khác nhau: mỗi hàng có cùng số lượng ô và (nếu quan trọng đối với nhiệm vụ) mỗi ô có độ rộng của cột tương ứng, giống như tất cả các ô trong một cột. Vậy nếu HorizontalMergeVerticalMerge trả về giá trị không chính xác thì dùng đoạn mã ví dụ sau đây

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document(getMyDir() + "Table with merged cells.docx");
SpanVisitor visitor = new SpanVisitor(doc);
doc.accept(visitor);
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
/// <summary>
/// Helper class that contains collection of rowinfo for each row.
/// </summary>
public static class TableInfo
{
public ArrayList<RowInfo> getRows() { return mRows; }
private ArrayList<RowInfo> mRows = new ArrayList<>();
}
/// <summary>
/// Helper class that contains collection of cellinfo for each cell.
/// </summary>
public static class RowInfo
{
public ArrayList<CellInfo> getCells() { return mCells; };
private ArrayList<CellInfo> mCells = new ArrayList<>();
}
/// <summary>
/// Helper class that contains info about cell. currently here is only colspan and rowspan.
/// </summary>
public static class CellInfo
{
public CellInfo(int colSpan, int rowSpan)
{
mColSpan = colSpan;
mRowSpan = rowSpan;
}
public int getColSpan() { return mColSpan; };
private int mColSpan;
public int getRowSpan() { return mRowSpan; };
private int mRowSpan;
}
public static class SpanVisitor extends DocumentVisitor
{
/// <summary>
/// Creates new SpanVisitor instance.
/// </summary>
/// <param name="doc">
/// Is document which we should parse.
/// </param>
public SpanVisitor(Document doc) throws Exception {
mWordTables = doc.getChildNodes(NodeType.TABLE, true);
// We will parse HTML to determine the rowspan and colspan of each cell.
ByteArrayOutputStream htmlStream = new ByteArrayOutputStream();
HtmlSaveOptions options = new HtmlSaveOptions();
{
options.setImagesFolder(System.getProperty("java.io.tmpdir"));
}
doc.save(htmlStream, options);
// Load HTML into the XML document.
org.jsoup.nodes.Document document = Jsoup.parse(htmlStream.toString());
// Get collection of tables in the HTML document.
Elements tables = document.getElementsByTag("table");
for (Element table : tables) {
TableInfo tableInf = new TableInfo();
// Get collection of rows in the table.
Elements rows = table.getElementsByTag("tr");
for (Element row : rows) {
RowInfo rowInf = new RowInfo();
// Get collection of cells.
Elements cells = row.getElementsByTag("td");
for (Element cell : cells) {
// Determine row span and colspan of the current cell.
String colSpanAttr = cell.attributes().get("colspan");
String rowSpanAttr = cell.attributes().get("rowspan");
int colSpan = StringUtils.isNotBlank(colSpanAttr) ? Integer.parseInt(colSpanAttr) : 0;
int rowSpan = StringUtils.isNotBlank(rowSpanAttr) ? Integer.parseInt(rowSpanAttr) : 0;
CellInfo cellInf = new CellInfo(colSpan, rowSpan);
rowInf.getCells().add(cellInf);
}
tableInf.getRows().add(rowInf);
}
mTables.add(tableInf);
}
}
public int visitCellStart(Cell cell)
{
int tabIdx = mWordTables.indexOf(cell.getParentRow().getParentTable());
int rowIdx = cell.getParentRow().getParentTable().indexOf(cell.getParentRow());
int cellIdx = cell.getParentRow().indexOf(cell);
int colSpan = 0;
int rowSpan = 0;
if (tabIdx < mTables.size() &&
rowIdx < mTables.get(tabIdx).getRows().size() &&
cellIdx < mTables.get(tabIdx).getRows().get(rowIdx).getCells().size())
{
colSpan = mTables.get(tabIdx).getRows().get(rowIdx).getCells().get(cellIdx).getColSpan();
rowSpan = mTables.get(tabIdx).getRows().get(rowIdx).getCells().get(cellIdx).getRowSpan();
}
System.out.println(MessageFormat.format("{0}.{1}.{2} colspan={3}\t rowspan={4}", tabIdx, rowIdx, cellIdx, colSpan, rowSpan));
return VisitorAction.CONTINUE;
}
private ArrayList<TableInfo> mTables = new ArrayList<>();
private NodeCollection mWordTables;
}

Chuyển đổi sang tế bào hợp nhất ngang

Đôi khi không thể phát hiện được các ô nào đã được kết hợp vì một số phiên bản mới hơn của Microsoft Word không còn sử dụng cờ kết hợp khi các ô kết hợp theo chiều ngang. Nhưng đối với tình huống mà các ô được hợp nhất ngang theo chiều rộng bằng cờ hợp nhất thì Aspose.Words cung cấp phương pháp ConvertToHorizontallyMergedCells để chuyển đổi các ô. Phương pháp này đơn giản chỉ biến đổi bảng và thêm những ô mới khi cần thiết.

Mã ví dụ sau cho thấy phương pháp trên đang hoạt động như thế nào:

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