How Kexcel Works¶
An .xlsx file is a ZIP archive of XML parts. Kexcel reads it into an
in-memory object graph, lets you mutate that graph, then serializes it back into a
ZIP. Understanding this pipeline helps explain the API's shape.
flowchart LR
A[.xlsx bytes] -->|decodeBytes / decodeStream| B(Parse)
B --> C[In-memory model<br/>Excel · Sheet · Data]
C -->|updateCell, merge, …| C
C -->|encode| D(Save)
D --> E[.xlsx bytes]
Two third-party, pure-Kotlin libraries do the heavy lifting:
no.synth:kmp-zip— ZIP archive I/O.com.fleeksoft.ksoup— XML parsing and DOM.
Excel is the document state¶
The Excel instance is the mutable document. It holds:
- the parsed XML documents (
xmlFiles), - the
Sheetobjects (sheetMap), - the shared-string pool, and
- the style / font / border / number-format tables.
All sheet-level operations (updateCell, insertRow, merge, findAndReplace,
copy, rename, delete, …) are methods on Excel that delegate to the relevant
Sheet.
A three-stage pipeline¶
Each stage owns a package in the source tree.
1. Parse (read path) — parser/¶
Constructed in Excel's init block, the parser walks the archive in order:
[Content_Types].xml → workbook relationships → styles.xml
→ sharedStrings.xml → each worksheet → merged cells
It populates the Excel object's maps and builds Sheet instances.
2. Model / edit — sheet/¶
A Sheet stores cells as a nested Map<row, Map<col, Data>>. Each cell's value
is a CellValue (see Reading & Writing Cells)
plus an optional CellStyle (which references a FontStyle, a BorderSet, and a
number format). CellIndex converts between "A3" strings and 0-based
(column, row) coordinates.
This is the layer you interact with. Sheets can be linked or cloned; Sheet.clone
gives an independent copy.
3. Save (write path) — save/¶
encode() runs Save/SaveFile, which mutate the ksoup XML documents to reflect
the current model, then re-zip everything into a ByteArray.
Supporting packages¶
| Package | Responsibility |
|---|---|
archive/ |
the ZIP/stream abstraction both parse and save build on |
shared_strings/ |
the workbook's deduplicated string pool |
number_format/ |
number/date/time format types and the format registry |
utils/ |
coordinate/color conversion, enums, and constants |
Design consequence: read and write stay symmetric¶
The recurring pattern when the library grows is:
- extend the
Sheet/CellValuemodel, - teach the parser to read the corresponding XML on load, and
- teach save to emit it.
The read and write paths must mirror each other — anything the parser can read, save must be able to write back.
Why "in memory"?¶
Because parsing and saving both operate on byte arrays and an in-memory DOM, the library has no dependency on a filesystem. That's what lets the exact same code run on the JVM, Android and iOS — you supply bytes in, you get bytes out, and platform-specific file handling stays in your app. See Saving & Loading.