committed

ZDS 0005: The XLSX Reader

Category Format Record
Intended Status Committed
Created 2026-08-06
Last Updated 2026-08-08
Authors Zen Contributors <team@insan.ai>
Discussion Mapping, omissions, and round-trip expectations for the XLSX reader

Abstract

The format record for zenfmt_xlsx (ai.insan.zenfmt.xlsx). A workbook is a set of grids; the projection is direct: each sheet becomes a level-two heading naming it, followed by one table with the sheet’s first row as its header. The interesting decisions are about numbers, because a spreadsheet’s raw storage lies to humans: serial dates and percentage fractions are formatted, everything else passes through verbatim.

Mapping

Every non-empty cell also carries a GridFacet (ZDS 0013): sheet name, zero-based row and column, value type, the formula source when present, and the cached value exactly as the source spelled it. Markdown ignores the facet; a future spreadsheet writer re-emits the formula from it.

SourceTree resultFacets
xl/workbook.xml sheet listOne heading (level 2) per sheet, in workbook order, resolved through the workbook relationships.none.
Sheet rows and cellsOne table per sheet; the first row is table_head, the rest table_body. Sparse rows are materialized: skipped cells become empty cells, and short rows pad to the sheet’s widest row.GridFacet per non-empty cell; padding cells carry none.
t="s" cellsThe shared string from xl/sharedStrings.xml.GridFacet with value type text.
t="inlineStr", t="str" cellsTheir text.GridFacet with value type text.
t="b" cellsTRUE or FALSE.GridFacet with value type boolean; t="e" cells carry error_value.
Number cells with a date formatISO yyyy-mm-dd, from the serial through Hinnant’s civil-from-days. Built-in format ids 14–22 and 45–47 count as dates; serials below 60 inherit Excel’s fictional 1900-02-29 and land one day early, which real spreadsheets never exercise.GridFacet with value type date; the cached field keeps the raw serial.
Number cells with a percentage formatThe fraction times one hundred with a % sign; ids 9 and 10.GridFacet with value type number and the raw fraction cached.
Other number cellsThe raw value, verbatim.GridFacet with value type number.
<f> formulasNever evaluated; the cached <v> is used. xlsx.formula-without-cached-value when there is none.GridFacet.formula carries the formula source text verbatim.

Deliberate omissions

WhatWhy
Cell styling, colors, borders, widthsA GFM table has none of it.
Charts, images, pivot tables, defined namesNo tree node exists, and inventing one is a ZDS 0002 amendment, not a reader’s decision.
Custom number formats beyond dates and percentagesFormat-string interpretation is a rendering engine; the raw value is honest, a wrong rendering is not.
Hidden rows, columns, and sheetsHiding is presentation; the data is the content. Everything converts.

Round-trip expectations

None: XLSX is read-only and no preservation namespace is written. A spreadsheet round trip would need cell-level typing that Markdown cannot carry; the honest form of that feature is a CSV writer, not a promise here.

Security

The shared zenfmt_ooxml archive limits and the DTD-free XML parser apply unchanged. Sheet materialization is bounded: cells beyond the widest declared reference cap at 1,024 columns per row, so a hostile dimension string cannot inflate output quadratically.

References

  • ZDS 0002, Reading the Office Formats.
  • ECMA-376 Part 1, SpreadsheetML.