Hướng dẫn python-docx merge cells - các ô hợp nhất python-docx

Table - Merge Cells¶

Word allows contiguous table cells to be merged, such that two or more cells appear to be a single cell. Cells can be merged horizontally (spanning multple columns) or vertically (spanning multiple rows). Cells can also be merged both horizontally and vertically at the same time, producing a cell that spans both rows and columns. Only rectangular ranges of cells can be merged.

Table diagrams¶

Diagrams like the one below are used to depict tables in this analysis. Horizontal spans are depicted as a continuous horizontal cell without vertical dividers within the span. Vertical spans are depicted as a vertical sequence of cells of the same width where continuation cells are separated by a dashed top border and contain a caret (‘^’) to symbolize the continuation of the cell above. Cell ‘addresses’ are depicted at the column and row grid lines. This is conceptually convenient as it reuses the notion of list indices (and slices) and makes certain operations more intuitive to specify. The merged cell A below has top, left, bottom, and right values of 0, 0, 2, and 2 respectively:

\ 0   1   2   3
0 +---+---+---+
  | A     |   |
1 + - - - +---+
  | ^     |   |
2 +---+---+---+
  |   |   |   |
3 +---+---+---+

Basic cell access protocol¶

There are three ways to access a table cell:

  • >>> table = document.add_table(3, 3)
    >>> middle_cell = table.cell(1, 1)
    >>> table.rows[1].cells[1] == middle_cell
    True
    >>> table.columns[1].cells[1] == middle_cell
    True
    
    5
  • >>> table = document.add_table(3, 3)
    >>> middle_cell = table.cell(1, 1)
    >>> table.rows[1].cells[1] == middle_cell
    True
    >>> table.columns[1].cells[1] == middle_cell
    True
    
    6
  • >>> table = document.add_table(3, 3)
    >>> middle_cell = table.cell(1, 1)
    >>> table.rows[1].cells[1] == middle_cell
    True
    >>> table.columns[1].cells[1] == middle_cell
    True
    
    7

Accessing the middle cell of a 3 x 3 table:

>>> table = document.add_table(3, 3)
>>> middle_cell = table.cell(1, 1)
>>> table.rows[1].cells[1] == middle_cell
True
>>> table.columns[1].cells[1] == middle_cell
True

Basic merge protocol¶

A merge is specified using two diagonal cells:

>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)

\ 0   1   2   3
0 +---+---+---+        +---+---+---+
  | a |   |   |        | A     |   |
1 +---+---+---+        + - - - +---+
  |   | b |   |  -->   | ^     |   |
2 +---+---+---+        +---+---+---+
  |   |   |   |        |   |   |   |
3 +---+---+---+        +---+---+---+

Accessing a merged cell¶

A cell is accessed by its “layout grid” position regardless of any spans that may be present. A grid address that falls in a span returns the top-leftmost cell in that span. This means a span has as many addresses as layout grid cells it spans. For example, the merged cell A above can be addressed as (0, 0), (0, 1), (1, 0), or (1, 1). This addressing scheme leads to desirable access behaviors when spans are present in the table.

The length of Row.cells is always equal to the number of grid columns, regardless of any spans that are present. Likewise, the length of Column.cells is always equal to the number of table rows, regardless of any spans.

>>> table = document.add_table(2, 3)
>>> row = table.rows[0]
>>> len(row.cells)
3
>>> row.cells[0] == row.cells[1]
False

>>> a, b = row.cells[:2]
>>> a.merge(b)

>>> len(row.cells)
3
>>> row.cells[0] == row.cells[1]
True

\ 0   1   2   3
0 +---+---+---+        +---+---+---+
  | a | b |   |        | A     |   |
1 +---+---+---+  -->   +---+---+---+
  |   |   |   |        |   |   |   |
2 +---+---+---+        +---+---+---+

Cell content behavior on merge¶

When two or more cells are merged, any existing content is concatenated and placed in the resulting merged cell. Content from each original cell is separated from that in the prior original cell by a paragraph mark. An original cell having no content is skipped in the contatenation process. In Python, the procedure would look roughly like this:

merged_cell_text = '\n'.join(
    cell.text for cell in original_cells if cell.text
)

Merging four cells with content

>>> table = document.add_table(3, 3)
>>> middle_cell = table.cell(1, 1)
>>> table.rows[1].cells[1] == middle_cell
True
>>> table.columns[1].cells[1] == middle_cell
True
8,
>>> table = document.add_table(3, 3)
>>> middle_cell = table.cell(1, 1)
>>> table.rows[1].cells[1] == middle_cell
True
>>> table.columns[1].cells[1] == middle_cell
True
9,
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
0, and
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
1 respectively results in a merged cell having text
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
2.

Cell size behavior on merge¶

Cell width and height, if present, are added when cells are merged:

>>> a, b = row.cells[:2]
>>> a.width.inches, b.width.inches
(1.0, 1.0)
>>> A = a.merge(b)
>>> A.width.inches
2.0

Removing a redundant row or column¶

Collapsing a column. When all cells in a grid column share the same

>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
3 specification, the spanned columns can be collapsed into a single column by removing the
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
3 attributes.

Word behavior¶

  • Row and Column access in the MS API just plain breaks when the table is not uniform. Table.Rows(n) and Cell.Row raise EnvironmentError when a table contains a vertical span, and Table.Columns(n) and Cell.Column unconditionally raise EnvironmentError when the table contains a horizontal span. We can do better.
  • Table.Cell(n, m) works on any non-uniform table, although it uses a visual grid that greatly complicates access. It raises an error for n or m out of visual range, and provides no way other than try/except to determine what that visual range is, since Row.Count and Column.Count are unavailable.
  • In a merge operation, the text of the continuation cells is appended to that of the origin cell as separate paragraph(s).
  • If a merge range contains previously merged cells, the range must completely enclose the merged cells.
  • Word resizes a table (adds rows) when a cell is referenced by an out-of-bounds row index. If the column identifier is out of bounds, an exception is raised. This behavior will not be implemented in
    >>> table = document.add_table(3, 3)
    >>> a = table.cell(0, 0)
    >>> b = table.cell(1, 1)
    >>> A = a.merge(b)
    
    5.

Glossary¶

layout gridThe regular two-dimensional matrix of rows and columns that determines the layout of cells in the table. The grid is primarily defined by the w:gridCol elements that define the layout columns for the table. Each row essentially duplicates that layout for an additional row, although its height can differ from other rows. Every actual cell in the table must begin and end on a layout grid “line”, whether the cell is merged or not.spanThe single “combined” cell occupying the area of a set of merged cells.skipped cellThe WordprocessingML (WML) spec allows for ‘skipped’ cells, where a layout cell location contains no actual cell. I can’t find a way to make a table like this using the Word UI and haven’t experimented yet to see whether Word will load one constructed by hand in the XML.uniform tableA table in which each cell corresponds exactly to a layout cell. A uniform table contains no spans or skipped cells.non-uniform tableA table that contains one or more spans, such that not every cell corresponds to a single layout cell. I suppose it would apply when there was one or more skipped cells too, but in this analysis the term is only used to indicate a table with one or more spans.uniform cellA cell not part of a span, occupying a single cell in the layout grid.origin cellThe top-leftmost cell in a span. Contrast with continuation cell.continuation cellA layout cell that has been subsumed into a span. A continuation cell is mostly an abstract concept, although a actual w:tc element will always exist in the XML for each continuation cell in a vertical span.

Hiểu hợp nhất xml bằng trực giác Or

Một cái nhìn sâu sắc quan trọng là các tế bào được hợp nhất luôn trông giống như sơ đồ dưới đây. Phạm vi ngang được thực hiện với một phần tử W: TC duy nhất trong mỗi hàng, sử dụng thuộc tính GridSpan để kéo dài các cột lưới bổ sung. Các nhịp dọc được thực hiện với một ô giống hệt nhau trong mỗi hàng tiếp tục, có cùng giá trị lưới và có Vmerge được thiết lập để tiếp tục (mặc định). Các tế bào tiếp tục dọc này được mô tả trong các sơ đồ bên dưới với đường viền trên cùng đứt nét và một chiếc xe hơi (‘^,) trong cột lưới nhất bên trái để tượng trưng cho sự tiếp tục của ô trên .:

\ 0   1   2   3
0 +---+---+---+
  | A     |   |
1 + - - - +---+
  | ^     |   |
2 +---+---+---+
  |   |   |   |
3 +---+---+---+

Bảng được mô tả ở trên tương ứng với XML này (giảm thiểu cho rõ ràng):


  
     
     
     
  
  
     
        
            w:val="2"/>
            w:val="restart"/>
        
     
     
  
  
     
        
            w:val="2"/>
           
        
     
     
  
  
     
     
     
  

XML Semantics¶

Trong một sự hợp nhất ngang, thuộc tính

>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
6 cho biết số lượng cột mà ô phải kéo dài. Chỉ có tế bào ngoài cùng bên trái được bảo tồn; Các ô còn lại trong hợp nhất bị xóa.

Để hợp nhất theo chiều dọc, thuộc tính tế bào bảng

>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
7 của ô cao nhất của cột được đặt thành giá trị khởi động lại của loại
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
8. Sau đây, các ô thấp hơn được bao gồm trong hợp nhất dọc phải có phần tử
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
7 có trong phần tử thuộc tính tế bào của chúng (
\ 0   1   2   3
0 +---+---+---+        +---+---+---+
  | a |   |   |        | A     |   |
1 +---+---+---+        + - - - +---+
  |   | b |   |  -->   | ^     |   |
2 +---+---+---+        +---+---+---+
  |   |   |   |        |   |   |   |
3 +---+---+---+        +---+---+---+
0). Giá trị của nó phải được đặt thành tiếp tục, mặc dù không cần thiết phải xác định rõ ràng nó, vì nó là giá trị mặc định. Một sự hợp nhất dọc kết thúc ngay khi phần tử
\ 0   1   2   3
0 +---+---+---+        +---+---+---+
  | a |   |   |        | A     |   |
1 +---+---+---+        + - - - +---+
  |   | b |   |  -->   | ^     |   |
2 +---+---+---+        +---+---+---+
  |   |   |   |        |   |   |   |
3 +---+---+---+        +---+---+---+
0 ô thiếu phần tử
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
7. Tương tự như phần tử
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
3, các phần tử ____27 chỉ được yêu cầu khi bố cục bảng không đồng đều trên các cột khác nhau của nó. Trong trường hợp đó là, chỉ có ô trên cùng được giữ; Các ô thấp hơn khác trong khu vực hợp nhất bị xóa cùng với các phần tử
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
7 của chúng và thuộc tính hàng bảng
\ 0   1   2   3
0 +---+---+---+        +---+---+---+
  | a |   |   |        | A     |   |
1 +---+---+---+        + - - - +---+
  |   | b |   |  -->   | ^     |   |
2 +---+---+---+        +---+---+---+
  |   |   |   |        |   |   |   |
3 +---+---+---+        +---+---+---+
6 được sử dụng để chỉ định chiều cao kết hợp của các ô hợp nhất.

triển khai Len () cho Row.Cells và Cột.Cells¶

Mỗi đối tượng

\ 0   1   2   3
0 +---+---+---+        +---+---+---+
  | a |   |   |        | A     |   |
1 +---+---+---+        + - - - +---+
  |   | b |   |  -->   | ^     |   |
2 +---+---+---+        +---+---+---+
  |   |   |   |        |   |   |   |
3 +---+---+---+        +---+---+---+
7 và
\ 0   1   2   3
0 +---+---+---+        +---+---+---+
  | a |   |   |        | A     |   |
1 +---+---+---+        + - - - +---+
  |   | b |   |  -->   | ^     |   |
2 +---+---+---+        +---+---+---+
  |   |   |   |        |   |   |   |
3 +---+---+---+        +---+---+---+
8 cung cấp quyền truy cập vào bộ sưu tập các ô mà nó chứa. Độ dài của các bộ sưu tập tế bào này không bị ảnh hưởng bởi sự hiện diện của các tế bào hợp nhất.

Len () luôn dựa trên số lượng của nó trên lưới bố trí, như thể không có ô được hợp nhất.

  • \ 0   1   2   3
    0 +---+---+---+        +---+---+---+
      | a |   |   |        | A     |   |
    1 +---+---+---+        + - - - +---+
      |   | b |   |  -->   | ^     |   |
    2 +---+---+---+        +---+---+---+
      |   |   |   |        |   |   |   |
    3 +---+---+---+        +---+---+---+
    
    9 là số lượng các phần tử W: Gridcol, đại diện cho số lượng cột lưới, mà không liên quan đến sự hiện diện của các ô hợp nhất trong bảng.
  • >>> table = document.add_table(2, 3)
    >>> row = table.rows[0]
    >>> len(row.cells)
    3
    >>> row.cells[0] == row.cells[1]
    False
    
    >>> a, b = row.cells[:2]
    >>> a.merge(b)
    
    >>> len(row.cells)
    3
    >>> row.cells[0] == row.cells[1]
    True
    
    0 là số lượng các phần tử W: TR, bất kể bất kỳ ô được hợp nhất nào có thể có trong bảng.
  • >>> table = document.add_table(2, 3)
    >>> row = table.rows[0]
    >>> len(row.cells)
    3
    >>> row.cells[0] == row.cells[1]
    False
    
    >>> a, b = row.cells[:2]
    >>> a.merge(b)
    
    >>> len(row.cells)
    3
    >>> row.cells[0] == row.cells[1]
    True
    
    1 là số lượng cột lưới, bất kể bất kỳ ô nào trong hàng được hợp nhất.
  • >>> table = document.add_table(2, 3)
    >>> row = table.rows[0]
    >>> len(row.cells)
    3
    >>> row.cells[0] == row.cells[1]
    False
    
    >>> a, b = row.cells[:2]
    >>> a.merge(b)
    
    >>> len(row.cells)
    3
    >>> row.cells[0] == row.cells[1]
    True
    
    2 là số lượng hàng trong bảng, bất kể bất kỳ ô nào trong cột được hợp nhất.

Hợp nhất một ô đã chứa một nhịp

Một hoặc cả hai tế bào góc đường chéo của đường chéo trong một hoạt động hợp nhất có thể là một ô được hợp nhất, miễn là vùng được chỉ định là hình chữ nhật.

Ví dụ:

>>> table = document.add_table(3, 3)
>>> middle_cell = table.cell(1, 1)
>>> table.rows[1].cells[1] == middle_cell
True
>>> table.columns[1].cells[1] == middle_cell
True
0

or:

>>> table = document.add_table(3, 3)
>>> middle_cell = table.cell(1, 1)
>>> table.rows[1].cells[1] == middle_cell
True
>>> table.columns[1].cells[1] == middle_cell
True
1

Ngược lại, một trong hai hoạt động hợp nhất này sẽ là bất hợp pháp:

>>> table = document.add_table(3, 3)
>>> middle_cell = table.cell(1, 1)
>>> table.rows[1].cells[1] == middle_cell
True
>>> table.columns[1].cells[1] == middle_cell
True
2

Thuật toán chung

  • Tìm chiều rộng mục tiêu và trên cùng bên trái, chiều cao
  • Đối với mỗi TR ở chiều cao đích, tc.grow_right (target_width)

Mẫu vật XML¶

Một bảng 3 x 3 trong đó một khu vực được xác định bởi các tế bào 2 x 2 đã được hợp nhất, chứng minh việc sử dụng kết hợp của

>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
3 cũng như các yếu tố
>>> table = document.add_table(3, 3)
>>> a = table.cell(0, 0)
>>> b = table.cell(1, 1)
>>> A = a.merge(b)
7, như được tạo ra bởi Word:

>>> table = document.add_table(3, 3)
>>> middle_cell = table.cell(1, 1)
>>> table.rows[1].cells[1] == middle_cell
True
>>> table.columns[1].cells[1] == middle_cell
True
3

Đoạn trích lược đồ

>>> table = document.add_table(3, 3)
>>> middle_cell = table.cell(1, 1)
>>> table.rows[1].cells[1] == middle_cell
True
>>> table.columns[1].cells[1] == middle_cell
True
4

Các vấn đề mở

  • Word có cho phép các ô đã bỏ qua các ô ở đầu một hàng không (phần tử W: Gridbefor)? Chúng được mô tả trong thông số kỹ thuật, nhưng tôi không thấy một cách trong từ UI để tạo ra một bảng như vậy.

Ressource¶

  • Phương pháp Cell.merge trên MSDN

Các phần liên quan trong ISO Spec¶

  • 17.4.17 GridSpan (cột lưới được kéo dài bởi ô bảng hiện tại)
  • 17.4.84 Vmerge (ô được hợp nhất theo chiều dọc)
  • 17,18,57 ST_merge (loại ô hợp nhất)