A 2x1 outer table whose first cell contains another 2x2 inner table with the literal cells Inner A1 / Inner A2 / Inner B1 / Inner B2.
Library verdicts: python-docx: — docxjs: —
| Feature id | docx/nested-table |
|---|---|
| Format | docx |
| Category | tables |
| Spec | ecma-376-5-part-1 § 17.4.24 w:tbl |
| ID / part | Predicate | XPath | python-docx | docxjs |
|---|---|---|---|---|
outer-tbl-presentword/document.xml | existThe outer <w:tbl> must be a direct child of <w:body>. | //w:body/w:tbl | — | — |
nested-tbl-presentword/document.xml | existA <w:tbl> must appear as a child of a <w:tc> inside another <w:tbl> — the canonical nested-table shape. | //w:tbl/w:tr/w:tc/w:tbl | — | — |
inner-cell-a1-textword/document.xml | existThe inner table must contain a cell with the literal 'Inner A1'. | //w:tbl//w:tbl//w:t[normalize-space()='Inner A1'] | — | — |
inner-cell-a2-textword/document.xml | existThe inner table must contain a cell with the literal 'Inner A2'. | //w:tbl//w:tbl//w:t[normalize-space()='Inner A2'] | — | — |
inner-cell-b1-textword/document.xml | existThe inner table must contain a cell with the literal 'Inner B1'. | //w:tbl//w:tbl//w:t[normalize-space()='Inner B1'] | — | — |
inner-cell-b2-textword/document.xml | existThe inner table must contain a cell with the literal 'Inner B2'. | //w:tbl//w:tbl//w:t[normalize-space()='Inner B2'] | — | — |
outer-bottom-cell-textword/document.xml | existThe outer table's second row must contain a cell with the literal 'Outer bottom'. Anchors the outer-table shape independently of the nested table. | //w:tbl/w:tr[2]/w:tc//w:t[normalize-space()='Outer bottom'] | — | — |
| ID | Predicate | Selector | python-docx | docxjs |
|---|---|---|---|---|
nested-table-inner-cell-a1 | css_selector/ match-text = Inner A1A rendered <td>/<th> inside a <table> that is itself inside another <table> must contain 'Inner A1'. Catches renderers that flatten nested tables. | .docx-wrapper table table td, .docx-wrapper table table th | — | — |
nested-table-inner-cell-count | css_selector/ equal-countThe inner (nested) table must contribute exactly four rendered cells. | .docx-wrapper table table td, .docx-wrapper table table th | — | — |
scripts/gen_nested_table.py
#!/usr/bin/env python3
"""Generate ``fixtures/docx/nested-table.docx``.
A minimal document exercising table-inside-cell nesting (ECMA-376
17.4.24). The outer table is 2x1:
- cell(0, 0) contains an inner 2x2 table with cells ``Inner A1``,
``Inner A2``, ``Inner B1``, ``Inner B2``.
- cell(1, 0) contains a plain-text paragraph ``Outer bottom`` so the
outer-table shape is obvious even when the nested one is ignored.
python-docx's ``_Cell.add_table()`` does the nesting natively; no raw
XML authoring is needed.
"""
from __future__ import annotations
from pathlib import Path
from docx import Document
_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "docx" / "nested-table.docx"
def main() -> int:
doc = Document()
outer = doc.add_table(rows=2, cols=1)
# -- nested 2x2 table inside the outer top-left cell --
inner = outer.cell(0, 0).add_table(rows=2, cols=2)
inner.cell(0, 0).text = "Inner A1"
inner.cell(0, 1).text = "Inner A2"
inner.cell(1, 0).text = "Inner B1"
inner.cell(1, 1).text = "Inner B2"
outer.cell(1, 0).text = "Outer bottom"
_OUT.parent.mkdir(parents=True, exist_ok=True)
doc.save(_OUT, reproducible=True)
print(_OUT)
return 0
if __name__ == "__main__":
raise SystemExit(main())
{
"$schema": "../manifest.schema.json",
"id": "docx/nested-table",
"title": "Nested table (table inside a cell)",
"format": "docx",
"category": "tables",
"summary": "A 2x1 outer table whose first cell contains another 2x2 inner table with the literal cells Inner A1 / Inner A2 / Inner B1 / Inner B2.",
"spec": {
"source": "ecma-376-5-part-1",
"clause": "17.4.24",
"element": "w:tbl",
"rnc_reference": "spec/ecma-376-5/part-1/rnc/WordprocessingML.rnc",
"xsd_reference": "spec/ecma-376-5/part-1/xsd/wml.xsd",
"notes": "OOXML allows a <w:tc> (table cell) to contain another <w:tbl> as a child, producing a nested table. This fixture has a 2x1 outer table; cell(0,0) holds a 2x2 inner table whose four cells contain 'Inner A1', 'Inner A2', 'Inner B1', 'Inner B2'. cell(1,0) of the outer table carries a plain text paragraph 'Outer bottom' to make the outer-table shape obvious. python-docx exposes _Cell.add_table() for nested-table construction, so no raw XML authoring is needed."
},
"fixtures": {
"machine": "docx/nested-table",
"office": "docx/nested-table"
},
"generator": {
"python": "scripts/gen_nested_table.py"
},
"assertions": [
{
"id": "outer-tbl-present",
"part": "word/document.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:body/w:tbl",
"must": "exist",
"description": "The outer <w:tbl> must be a direct child of <w:body>."
},
{
"id": "nested-tbl-present",
"part": "word/document.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:tbl/w:tr/w:tc/w:tbl",
"must": "exist",
"description": "A <w:tbl> must appear as a child of a <w:tc> inside another <w:tbl> — the canonical nested-table shape."
},
{
"id": "inner-cell-a1-text",
"part": "word/document.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:tbl//w:tbl//w:t[normalize-space()='Inner A1']",
"must": "exist",
"description": "The inner table must contain a cell with the literal 'Inner A1'."
},
{
"id": "inner-cell-a2-text",
"part": "word/document.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:tbl//w:tbl//w:t[normalize-space()='Inner A2']",
"must": "exist",
"description": "The inner table must contain a cell with the literal 'Inner A2'."
},
{
"id": "inner-cell-b1-text",
"part": "word/document.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:tbl//w:tbl//w:t[normalize-space()='Inner B1']",
"must": "exist",
"description": "The inner table must contain a cell with the literal 'Inner B1'."
},
{
"id": "inner-cell-b2-text",
"part": "word/document.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:tbl//w:tbl//w:t[normalize-space()='Inner B2']",
"must": "exist",
"description": "The inner table must contain a cell with the literal 'Inner B2'."
},
{
"id": "outer-bottom-cell-text",
"part": "word/document.xml",
"namespaces": {
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
},
"xpath": "//w:tbl/w:tr[2]/w:tc//w:t[normalize-space()='Outer bottom']",
"must": "exist",
"description": "The outer table's second row must contain a cell with the literal 'Outer bottom'. Anchors the outer-table shape independently of the nested table."
}
],
"render_assertions": [
{
"id": "nested-table-inner-cell-a1",
"kind": "css_selector",
"selector": ".docx-wrapper table table td, .docx-wrapper table table th",
"must": "match-text",
"value": "Inner A1",
"description": "A rendered <td>/<th> inside a <table> that is itself inside another <table> must contain 'Inner A1'. Catches renderers that flatten nested tables."
},
{
"id": "nested-table-inner-cell-count",
"kind": "css_selector",
"selector": ".docx-wrapper table table td, .docx-wrapper table table th",
"must": "equal-count",
"count": 4,
"description": "The inner (nested) table must contribute exactly four rendered cells."
}
]
}
No rendered reference is available for this case.