Open cell-bold.xlsx (1 row: A1='Hello bold cell' bold), ws.append([1, 2, 3]), save. Assert (a) the existing row 1 is preserved intact (A1 keeps @s='1' and its shared-string reference), (b) a new row r='2' with cells A2,B2,C2 carrying numeric values 1,2,3 is present, (c) dimension ref expanded to A1:C2.
Library verdicts: python-xlsx: — xlsxjs: —
| Feature id | xlsx/modify-add-row |
|---|---|
| Format | xlsx |
| Category | modify-in-place |
| Spec | ecma-376-5-part-1 § 18.3.1.73 row |
| ID / part | Predicate | XPath | python-xlsx | xlsxjs |
|---|---|---|---|---|
row-count-is-twoxl/worksheets/sheet1.xml | match = ^2(\.0+)?$sheetData must contain exactly 2 rows. | count(//s:sheetData/s:row) | — | — |
original-a1-style-preservedxl/worksheets/sheet1.xml | equal = 1Row 1's A1 must keep its bold style index. Append must not re-author pre-existing rows. | //s:sheetData/s:row[@r='1']/s:c[@r='A1']/@s | — | — |
original-a1-text-preservedxl/sharedStrings.xml | existThe original shared string must still be present — append of numeric values must not touch the string table. | //s:si/s:t[normalize-space()='Hello bold cell'] | — | — |
row2-a2-valuexl/worksheets/sheet1.xml | equal = 1A2 must carry the first appended value (1). | //s:sheetData/s:row[@r='2']/s:c[@r='A2']/s:v | — | — |
row2-b2-valuexl/worksheets/sheet1.xml | equal = 2B2 must carry the second appended value (2). | //s:sheetData/s:row[@r='2']/s:c[@r='B2']/s:v | — | — |
row2-c2-valuexl/worksheets/sheet1.xml | equal = 3C2 must carry the third appended value (3). | //s:sheetData/s:row[@r='2']/s:c[@r='C2']/s:v | — | — |
row2-cells-are-numericxl/worksheets/sheet1.xml | not-match = ^s$A2 must NOT be shared-string-typed — numeric append must not accidentally round-trip through the string table. | //s:sheetData/s:row[@r='2']/s:c[@r='A2']/@t | — | — |
dimension-expandedxl/worksheets/sheet1.xml | equal = A1:C2dimension/@ref must expand from A1:A1 to A1:C2 to cover the new row. | //s:dimension/@ref | — | — |
No render assertions declared.
scripts/gen_modify_add_row.py
#!/usr/bin/env python3
"""Generate ``fixtures/xlsx/cell-bold--append-row.xlsx``.
Thin wrapper around ``scripts.mutations.xlsx_append_row``. Opens
``fixtures/xlsx/cell-bold.xlsx``, ws.append([1, 2, 3]), saves.
Satisfies ``features/xlsx/modify-add-row.json``.
"""
from __future__ import annotations
from pathlib import Path
from mutations import xlsx_append_row
_REPO_ROOT = Path(__file__).resolve().parent.parent
_IN = _REPO_ROOT / "fixtures" / "xlsx" / "cell-bold.xlsx"
_OUT = _REPO_ROOT / "fixtures" / "xlsx" / "cell-bold--append-row.xlsx"
def main() -> int:
xlsx_append_row(_IN, _OUT)
print(_OUT)
return 0
if __name__ == "__main__":
raise SystemExit(main())
{
"$schema": "../manifest.schema.json",
"id": "xlsx/modify-add-row",
"title": "Modify: append row to existing .xlsx",
"format": "xlsx",
"category": "modify-in-place",
"summary": "Open cell-bold.xlsx (1 row: A1='Hello bold cell' bold), ws.append([1, 2, 3]), save. Assert (a) the existing row 1 is preserved intact (A1 keeps @s='1' and its shared-string reference), (b) a new row r='2' with cells A2,B2,C2 carrying numeric values 1,2,3 is present, (c) dimension ref expanded to A1:C2.",
"roles": [
"authoring"
],
"spec": {
"source": "ecma-376-5-part-1",
"clause": "18.3.1.73",
"element": "row",
"rnc_reference": "spec/ecma-376-5/part-1/rnc/SpreadsheetML.rnc",
"xsd_reference": "spec/ecma-376-5/part-1/xsd/sml.xsd",
"notes": "ws.append places the values into the first row below the last row that contains data. Existing rows must be byte-preserved — rewriting row 1 while appending row 2 is a common silent regression."
},
"fixtures": {
"machine": "xlsx/cell-bold--append-row"
},
"modify": {
"input_fixture": "fixtures/xlsx/cell-bold.xlsx",
"mutation": "xlsx_append_row",
"output_fixture": "fixtures/xlsx/cell-bold--append-row.xlsx"
},
"generator": {
"python": "scripts/gen_modify_add_row.py"
},
"assertions": [
{
"id": "row-count-is-two",
"part": "xl/worksheets/sheet1.xml",
"namespaces": {
"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "count(//s:sheetData/s:row)",
"must": "match",
"value": "^2(\\.0+)?$",
"description": "sheetData must contain exactly 2 rows."
},
{
"id": "original-a1-style-preserved",
"part": "xl/worksheets/sheet1.xml",
"namespaces": {
"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "//s:sheetData/s:row[@r='1']/s:c[@r='A1']/@s",
"must": "equal",
"value": "1",
"description": "Row 1's A1 must keep its bold style index. Append must not re-author pre-existing rows."
},
{
"id": "original-a1-text-preserved",
"part": "xl/sharedStrings.xml",
"namespaces": {
"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "//s:si/s:t[normalize-space()='Hello bold cell']",
"must": "exist",
"description": "The original shared string must still be present — append of numeric values must not touch the string table."
},
{
"id": "row2-a2-value",
"part": "xl/worksheets/sheet1.xml",
"namespaces": {
"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "//s:sheetData/s:row[@r='2']/s:c[@r='A2']/s:v",
"must": "equal",
"value": "1",
"description": "A2 must carry the first appended value (1)."
},
{
"id": "row2-b2-value",
"part": "xl/worksheets/sheet1.xml",
"namespaces": {
"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "//s:sheetData/s:row[@r='2']/s:c[@r='B2']/s:v",
"must": "equal",
"value": "2",
"description": "B2 must carry the second appended value (2)."
},
{
"id": "row2-c2-value",
"part": "xl/worksheets/sheet1.xml",
"namespaces": {
"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "//s:sheetData/s:row[@r='2']/s:c[@r='C2']/s:v",
"must": "equal",
"value": "3",
"description": "C2 must carry the third appended value (3)."
},
{
"id": "row2-cells-are-numeric",
"part": "xl/worksheets/sheet1.xml",
"namespaces": {
"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "//s:sheetData/s:row[@r='2']/s:c[@r='A2']/@t",
"must": "not-match",
"value": "^s$",
"description": "A2 must NOT be shared-string-typed — numeric append must not accidentally round-trip through the string table."
},
{
"id": "dimension-expanded",
"part": "xl/worksheets/sheet1.xml",
"namespaces": {
"s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
},
"xpath": "//s:dimension/@ref",
"must": "equal",
"value": "A1:C2",
"description": "dimension/@ref must expand from A1:A1 to A1:C2 to cover the new row."
}
]
}
No rendered reference is available for this case.