xlsx/multiple-sheets

A workbook declares three sheets named 'First', 'Second', and 'Third' in its <sheets> catalogue.

Library verdicts: python-xlsx: — xlsxjs: pass

Metadata

Feature idxlsx/multiple-sheets
Formatxlsx
Categoryworkbook-structure
Spececma-376-5-part-1 § 18.2.2 sheets

XPath assertions

ID / partPredicateXPathpython-xlsxxlsxjs
sheets-count-3
xl/workbook.xml
match = ^3(\.0+)?$
The workbook must declare exactly 3 sheets in its <sheets> catalogue. (XPath count() returns a float; lxml stringifies as '3.0', so we regex-match.)
count(//x:sheets/x:sheet)
sheet-named-first
xl/workbook.xml
exist
A sheet named 'First' must appear in the workbook catalogue.
//x:sheets/x:sheet[@name='First']
sheet-named-second
xl/workbook.xml
exist
A sheet named 'Second' must appear in the workbook catalogue.
//x:sheets/x:sheet[@name='Second']
sheet-named-third
xl/workbook.xml
exist
A sheet named 'Third' must appear in the workbook catalogue.
//x:sheets/x:sheet[@name='Third']

Render assertions

IDPredicateSelectorpython-xlsxxlsxjs
multi-sheet-sectionscss_selector/ equal-count
The renderer must emit one section.xlsx per sheet (xlsxjs convention) — 3 sheets => 3 sections.
section.xlsxpass

Generator source

scripts/gen_multiple_sheets.py

#!/usr/bin/env python3
"""Generate ``fixtures/xlsx/multiple-sheets.xlsx``.

A minimal three-sheet workbook with sheets named ``First``, ``Second``,
and ``Third``, each containing a single cell value. Designed to satisfy
the assertions in ``features/xlsx/multiple-sheets.json``.
"""

from __future__ import annotations

from pathlib import Path

from xlsx import Workbook

import datetime as _dt
_REPRODUCIBLE_DT = _dt.datetime(2000, 1, 1, 0, 0, 0)

_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "xlsx" / "multiple-sheets.xlsx"


def main() -> int:
    wb = Workbook()
    ws1 = wb.active
    ws1.title = "First"
    ws1["A1"] = "Sheet one content"
    ws2 = wb.create_sheet(title="Second")
    ws2["A1"] = "Sheet two content"
    ws3 = wb.create_sheet(title="Third")
    ws3["A1"] = "Sheet three content"
    _OUT.parent.mkdir(parents=True, exist_ok=True)
    wb.save(_OUT, zip_date_time=_REPRODUCIBLE_DT)
    print(_OUT)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Manifest (expanded)

{
  "$schema": "../manifest.schema.json",
  "id": "xlsx/multiple-sheets",
  "title": "Workbook with multiple sheets",
  "format": "xlsx",
  "category": "workbook-structure",
  "summary": "A workbook declares three sheets named 'First', 'Second', and 'Third' in its <sheets> catalogue.",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "18.2.2",
    "element": "sheets",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/SpreadsheetML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/sml.xsd",
    "notes": "Workbook sheet enumeration in SpreadsheetML lives on <sheets> inside xl/workbook.xml, with one <sheet name='...' sheetId='...' r:id='...'/> per worksheet. The r:id attribute ties the sheet to a worksheet part via xl/_rels/workbook.xml.rels. Each sheet's data lives in its own part (xl/worksheets/sheet1.xml, sheet2.xml, sheet3.xml). SpreadsheetML parts use a default namespace with no prefix; XPath therefore needs an explicit binding (here 'x'). A single XPath assertion can only target one part, so the sheet-name presence check is split into three assertions, one per expected name."
  },
  "fixtures": {
    "machine": "xlsx/multiple-sheets",
    "office": "xlsx/multiple-sheets"
  },
  "generator": {
    "python": "scripts/gen_multiple_sheets.py"
  },
  "assertions": [
    {
      "id": "sheets-count-3",
      "part": "xl/workbook.xml",
      "namespaces": {
        "x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "count(//x:sheets/x:sheet)",
      "must": "match",
      "value": "^3(\\.0+)?$",
      "description": "The workbook must declare exactly 3 sheets in its <sheets> catalogue. (XPath count() returns a float; lxml stringifies as '3.0', so we regex-match.)"
    },
    {
      "id": "sheet-named-first",
      "part": "xl/workbook.xml",
      "namespaces": {
        "x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "//x:sheets/x:sheet[@name='First']",
      "must": "exist",
      "description": "A sheet named 'First' must appear in the workbook catalogue."
    },
    {
      "id": "sheet-named-second",
      "part": "xl/workbook.xml",
      "namespaces": {
        "x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "//x:sheets/x:sheet[@name='Second']",
      "must": "exist",
      "description": "A sheet named 'Second' must appear in the workbook catalogue."
    },
    {
      "id": "sheet-named-third",
      "part": "xl/workbook.xml",
      "namespaces": {
        "x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "//x:sheets/x:sheet[@name='Third']",
      "must": "exist",
      "description": "A sheet named 'Third' must appear in the workbook catalogue."
    }
  ],
  "render_assertions": [
    {
      "id": "multi-sheet-sections",
      "kind": "css_selector",
      "selector": "section.xlsx",
      "must": "equal-count",
      "count": 3,
      "description": "The renderer must emit one section.xlsx per sheet (xlsxjs convention) — 3 sheets => 3 sections."
    }
  ]
}

Fixture

Download multiple-sheets.xlsx (5.6 KB)

Reference preview

Reference (machine, page 1 PNG)

xlsx/multiple-sheets page 1 reference

Reference PDF


Download PDF Open in PDF.js

Spec notes

Workbook sheet enumeration in SpreadsheetML lives on <sheets> inside xl/workbook.xml, with one <sheet name='...' sheetId='...' r:id='...'/> per worksheet. The r:id attribute ties the sheet to a worksheet part via xl/_rels/workbook.xml.rels. Each sheet's data lives in its own part (xl/worksheets/sheet1.xml, sheet2.xml, sheet3.xml). SpreadsheetML parts use a default namespace with no prefix; XPath therefore needs an explicit binding (here 'x'). A single XPath assertion can only target one part, so the sheet-name presence check is split into three assertions, one per expected name.