xlsx
On this page:
- spider.xlsx: Excel .xlsx files, written and read — opt-in with
-Dxlsx=true(see modules/xlsx/README.md).
spider.xlsx
Public API — pure-Zig writing and reading of Excel .xlsx files. No C, no dependency besides std, no global state, no temporary files.
Writing: build a Workbook, add sheets, set cells, then get the file as bytes or write it to any std.Io.Writer:
const wb = try xlsx.Workbook.init(allocator);
defer wb.deinit();
const sheet = try wb.addSheet("Results");
try sheet.setRow(0, 0, &.{ .{ .text = "Option" }, .{ .text = "Votes" } }, .{ .bold = true });
try sheet.setRow(1, 0, &.{ .{ .text = "Yes" }, .int(12) }, .{});
const bytes = try wb.toOwnedSlice(allocator);
Reading: open the bytes of a file with limits and iterate the rows of a sheet, typed, in bounded memory:
const book = try xlsx.Reader.open(allocator, bytes, .{});
defer book.deinit();
const rows = try book.rows(0, .{});
defer rows.deinit();
while (try rows.next()) |row| { … }
Written: several sheets; text, numbers, booleans, dates and formulas; column widths and row heights; fonts, background colour, borders, alignment, wrapped text and number formats; merged cells; links; hidden rows and columns; frozen panes, zoom and a filter per sheet; page setup, print area, page breaks, header and footer; protection. Read: sheets, rows and typed cells with their number format, cached formula results, merged ranges. Not done: streamed writing, compression, charts and images, .xls (see README.md).
spider.xlsx.Workbook
pub const Workbook = struct
A workbook being built. Not thread-safe; there is no global state, so separate workbooks can be built on separate threads.
Fields
gpa: std.mem.Allocatorarena: std.heap.ArenaAllocator: Owns everything the workbook keeps: sheets, cells, copied text.sheets: std.ArrayList(*Sheet) = .emptystrings: shared_strings.Table = .{}styles: styles_mod.Registry = .{}has_formulas: bool = falseprotection: ?Protected = null
xlsx.Workbook.protect
pub fn protect(self: *Workbook, protection: Protection) Error!void
Protects the workbook's structure: sheets cannot be added, removed, renamed, moved or unhidden. Cells stay editable unless their sheet is protected too. See Protection.
xlsx.Workbook.init
pub fn init(gpa: std.mem.Allocator) error{OutOfMemory}!*Workbook
Creates an empty workbook. All memory comes from gpa and is released by deinit. Text passed in is copied: the caller's buffers can be freed or reused right after each call.
xlsx.Workbook.deinit
pub fn deinit(self: *Workbook) void
Frees the workbook with its sheets and everything set on them. *Sheet pointers are invalid afterwards; bytes returned by toOwnedSlice are not touched.
xlsx.Workbook.setDefaultFont
pub fn setDefaultFont(self: *Workbook, name: []const u8, size: f32) Error!void
Sets the font of every cell whose style names none (Calibri 11 otherwise). Call it before setting any cell.
Column widths are counted in characters of the default font, so this also changes how wide a given setColumnWidth value is: a workbook copied from one that uses another default font needs the same default to keep the same column widths.
xlsx.Workbook.addSheet
pub fn addSheet(self: *Workbook, name: []const u8) Error!*Sheet
Adds a sheet; sheets appear in the order they are added.
The name follows Excel's rules: 1 to 31 characters, none of / \ ? * : [ ], no control characters, no apostrophe at either end, not "History", and different from the other sheets' names whatever the case of ASCII letters.
xlsx.Workbook.writeTo
pub fn writeTo(self: *Workbook, out: *Writer) Error!void
Writes the .xlsx file to out. out is not flushed: flush it afterwards if it is buffered. The workbook can be written more than once, and always produces the same bytes.
xlsx.Workbook.toOwnedSlice
pub fn toOwnedSlice(self: *Workbook, allocator: std.mem.Allocator) Error![]u8
Returns the .xlsx file as bytes owned by the caller (free them with allocator).
xlsx.Workbook.writeToPackager
pub fn writeToPackager(self: *Workbook, packager: zip.Packager) Error!void
Hands every part to packager and finishes it. This is the seam for another container (a compressing zip, a recorder in tests).
spider.xlsx.Sheet
pub const Sheet = struct
One sheet of a workbook. Created by Workbook.addSheet; rows and columns are zero-based.
Fields
workbook: *Workbookname: []const u8cells: std.ArrayList(Cell) = .emptycells_in_order: bool = true: False once a cell was set out of row/column order or twice.column_widths: std.ArrayList(ColumnWidth) = .emptyrow_heights: std.ArrayList(RowHeight) = .emptyhidden_columns: std.ArrayList(u16) = .emptyhidden_rows: std.ArrayList(u32) = .emptymerges: std.ArrayList(Range) = .emptylinks: std.ArrayList(Link) = .emptyfrozen_rows: u32 = 0frozen_cols: u32 = 0auto_filter: ?Range = nullzoom: u16 = 100: In percent.page_setup: ?PageSetup = nullprint_area: ?Range = nullprotection: ?Protected = nullrow_breaks: std.ArrayList(u32) = .empty: Zero-based index of the first row (column) of each new page.column_breaks: std.ArrayList(u32) = .emptyheader_footer: HeaderFooter = .{}default_column_width: ?f64 = null: In characters, like column widths.default_row_height: ?f64 = nullprint_title_rows: ?[2]u32 = null: First and last row repeated on every printed page.
xlsx.Sheet.set
pub fn set(self: *Sheet, row: u32, col: u32, value: Value) Error!void
Sets a cell with the default style. Cells may be set in any order; setting a cell again replaces it.
xlsx.Sheet.setStyled
pub fn setStyled(self: *Sheet, row: u32, col: u32, value: Value, style: Style) Error!void
Sets a cell and its style.
xlsx.Sheet.setRow
pub fn setRow(self: *Sheet, row: u32, first_col: u32, values: []const Value, style: Style) Error!void
Sets consecutive cells of one row, starting at first_col, all with the same style.
xlsx.Sheet.setColumnWidth
pub fn setColumnWidth(self: *Sheet, col: u32, width: f64) Error!void
Sets a column's width, in characters of the default font (the unit Excel shows in its "Column width" dialog). 0 hides nothing but makes the column as narrow as possible.
xlsx.Sheet.setRowHeight
pub fn setRowHeight(self: *Sheet, row: u32, points: f64) Error!void
Sets a row's height in points (a default row is 15). Without it a spreadsheet program sizes the row to its content when it draws the sheet, wrapped text included.
xlsx.Sheet.setRowHeightHint
pub fn setRowHeightHint(self: *Sheet, row: u32, points: f64) Error!void
Records the height a row has now without fixing it: a spreadsheet program may refit the row when its content changes (and some refit it on opening, for wrapped text). This is how Excel stores rows whose height nobody set by hand.
xlsx.Sheet.hideColumn
pub fn hideColumn(self: *Sheet, col: u32) Error!void
Hides a column. Its cells, and its width if one was set, stay in the file: the reader can show the column again.
xlsx.Sheet.hideRow
pub fn hideRow(self: *Sheet, row: u32) Error!void
Hides a row; see hideColumn.
xlsx.Sheet.setDefaultColumnWidth
pub fn setDefaultColumnWidth(self: *Sheet, width: f64) Error!void
Sets the width of every column that has no width of its own.
xlsx.Sheet.setDefaultRowHeight
pub fn setDefaultRowHeight(self: *Sheet, points: f64) Error!void
Sets the height of every row that has no height of its own.
xlsx.Sheet.mergeCells
pub fn mergeCells(self: *Sheet, range: Range) Error!void
Merges a rectangle of cells into one. The merged cell shows the value and the alignment of the range's top-left cell; borders and fills still come from each cell of the range, so style them all (blank cells with a style) to frame the merged cell.
The range must cover more than one cell and cannot share a cell with another merged range.
xlsx.Sheet.freeze
pub fn freeze(self: *Sheet, rows: u32, cols: u32) Error!void
Keeps the first rows rows and the first cols columns in view while the rest scrolls. freeze(1, 0) pins a header row.
xlsx.Sheet.setLink
pub fn setLink(self: *Sheet, row: u32, col: u32, target: []const u8) Error!void
Makes a cell a link to a site (http://, https://) or to an e-mail address (mailto:). Other schemes are refused, so a link built from user data cannot point at a local file or run anything. The cell keeps its own value and style: set the text to show with setStyled(row, col, value, xlsx.link_style). Setting a link again on the same cell replaces it.
xlsx.Sheet.setPageSetup
pub fn setPageSetup(self: *Sheet, setup: PageSetup) Error!void
Sets paper size, orientation and margins for printing. Without it the sheet has Excel's default margins and the paper is the reader's default, which depends on the country (Letter or A4).
xlsx.Sheet.protect
pub fn protect(self: *Sheet, protection: Protection) Error!void
Protects the sheet: cells cannot be edited, except those whose style has unlocked = true. See Protection for what this is and is not.
xlsx.Sheet.setPrintArea
pub fn setPrintArea(self: *Sheet, range: Range) Error!void
Limits printing to range.
xlsx.Sheet.addPageBreakBeforeRow
pub fn addPageBreakBeforeRow(self: *Sheet, row: u32) Error!void
Starts a new printed page at row (which cannot be the first).
xlsx.Sheet.addPageBreakBeforeColumn
pub fn addPageBreakBeforeColumn(self: *Sheet, col: u32) Error!void
Starts a new printed page at col (which cannot be the first).
xlsx.Sheet.setHeaderFooter
pub fn setHeaderFooter(self: *Sheet, header_footer: HeaderFooter) Error!void
Sets the text printed at the top and bottom of every page; see HeaderFooter for the notation. The text is copied.
xlsx.Sheet.setPrintTitleRows
pub fn setPrintTitleRows(self: *Sheet, first_row: u32, last_row: u32) Error!void
Repeats rows first_row to last_row at the top of every printed page: the header of a long table.
xlsx.Sheet.setZoom
pub fn setZoom(self: *Sheet, percent: u16) Error!void
Sets the zoom the sheet opens with, 10 to 400 percent. It only affects the screen, not printing.
xlsx.Sheet.setAutoFilter
pub fn setAutoFilter(self: *Sheet, range: Range) Error!void
Turns range into a filtered table: its first row gets the filter buttons. One filter per sheet; calling again replaces it.
spider.xlsx.Value
pub const Value = union(enum)
What a cell holds.
Fields
blank: No value. With a style, the cell is still written (an empty cell with a background, for instance).text: []const u8: Text, written exactly as given. Text is never interpreted: a string that starts with=,+,-or@stays text and is shown as typed. An empty string is the same asblank.number: f64: Numbers are IEEE doubles, as in every spreadsheet: integers are exact up to 2^53 and Excel shows 15 significant digits.boolean: booldate: Date: Stored as a number; shown as a date because the cell gets thedatenumber format unless the style names another one.datetime: DateTime: Likedate, with thedatetimenumber format by default.formula: []const u8: A formula in Excel's syntax with English function names and,between arguments, e.g."SUM(B2:B9)". A leading=is accepted and dropped. No result is stored: the program opening the file calculates it. Never build a formula from user input.
xlsx.Value.int
pub fn int(n: anytype) Value
A whole number.
spider.xlsx.Error
pub const Error = error
Everything building or writing a workbook can fail with. A value is checked when it is set, so the error comes from the call that passed it.
Errors
RowOutOfRange: Row index past the last row of a sheet (1,048,576 rows).ColumnOutOfRange: Column index past the last column of a sheet (16,384 columns).InvalidRange: A range whose last row or column comes before its first, a merge of a single cell, or a page break before the first row or column.TextTooLong: Cell text longer than 32,767 characters.InvalidUtf8: Text, a sheet name, a formula or a link that is not valid UTF-8.InvalidNumber: NaN or infinity: a cell cannot hold them.InvalidDate: Not a calendar date, or outside 1900-01-01 .. 9999-12-31.InvalidFormula: An empty formula, one longer than 8,192 characters, or one with characters XML cannot carry.InvalidSheetName: A sheet name Excel refuses (seeWorkbook.addSheet).DuplicateSheetName: A sheet with this name already exists.InvalidColumnWidth: A column width outside 0 .. 255.InvalidRowHeight: A row height outside 0 .. 409 points.OverlappingMerge: A merged range that shares a cell with another one.InvalidZoom: A zoom outside 10 .. 400 percent.InvalidMargin: A page margin that is negative, not finite or absurdly large.InvalidPageSetup: A print scale outside 10 .. 400, or both a scale and fit-to-page.InvalidHeaderFooter: A header or footer longer than 255 characters or with characters XML cannot carry.InvalidPassword: A protection password that is empty, longer than 255 characters or not printable ASCII.InvalidLink: A link that is nothttp://,https://ormailto:, is too long, or has spaces or control characters.TooManyLinks: More than 65,530 links on one sheet.InvalidNumberFormat: A custom number format that is empty, too long or malformed.InvalidFont: A font name that is empty, too long or malformed, or a font size outside 1 .. 409 points.TooManyStyles: More than 65,490 distinct styles.StylesAlreadyUsed:setDefaultFontwas called after a cell was given a style.NoSheets: A workbook must have at least one sheet to be written.ArchiveTooLarge: The package does not fit a plain zip archive (zip64 is not implemented): a part or the whole file passes 4 GiB.InvalidPartName: Only reachable with a customPackager: this module's own part names are always valid and distinct.DuplicatePartNameOutOfMemoryWriteFailed: The destination writer failed.
spider.xlsx.Style
pub const Style = struct
The formatting of one cell. The default value is a plain cell.
Fields
bold: bool = falseitalic: bool = falseunderline: bool = falsefont_color: ?u24 = null: Text colour as0xRRGGBB.font_name: ?[]const u8 = null: A font family name such as"Times New Roman". The file only carries the name: the font must exist on the reader's machine. Null is the workbook's default font (Calibri unless changed).font_size: ?f32 = null: Size in points, 1 to 409, in steps of a tenth. Null is the workbook's default size (11 unless changed).fill: ?u24 = null: Background colour as0xRRGGBB.fill_pattern: FillPattern = .solidborder: Border = .none: The line on the four sides of the cell.border_left: ?Border = null: One side only; when set, it replacesborderfor that side (.noneremoves the line there).border_right: ?Border = nullborder_top: ?Border = nullborder_bottom: ?Border = nullborder_color: ?u24 = null: Colour of the border lines as0xRRGGBB; null is the reader's automatic colour (black).number_format: NumberFormat = .generalh_align: HorizontalAlignment = .generalv_align: VerticalAlignment = .bottomwrap: bool = false: Breaks long text into lines inside the cell instead of letting it run over the next cells. Line breaks in the text itself also only show when this is set.shrink: bool = false: Makes the text smaller, when needed, so it fits the cell's width on one line. Spreadsheet programs ignore it whenwrapis set.unlocked: bool = false: Lets the cell be edited when its sheet is protected (cells are locked by default). Has no effect on an unprotected sheet.
spider.xlsx.Border
pub const Border = enum
A line drawn on the four sides of a cell.
Values
nonehairdotteddashedthinmediumthickdouble
spider.xlsx.FillPattern
pub const FillPattern = enum
How a cell's background is painted. solid covers it with the fill colour; the others draw dots of that colour (black without one) over the plain background, from darker to lighter.
Values
soliddark_graymedium_graylight_graygray125gray0625
spider.xlsx.NumberFormat
pub const NumberFormat = union(enum)
How a number is shown. The named ones are formats every spreadsheet program has built in, so they follow the reader's locale (decimal comma, day/month order). custom takes a format code in Excel's syntax, written with . as the decimal separator, e.g. "dd/mm/yyyy" or "#,##0.00".
Fields
generalinteger:0decimal:0.00thousands:#,##0thousands_decimal:#,##0.00percent:0%percent_decimal:0.00%date: The reader's short date.time:h:mm:ssdatetime: The reader's short date, thenh:mm.text: Shows the cell as typed, numbers included.custom: []const u8
spider.xlsx.HorizontalAlignment
pub const HorizontalAlignment = enum
Where a cell's content sits between its left and right edges. general is the spreadsheet's own rule: text to the left, numbers to the right.
Values
generalleftcenterright
spider.xlsx.VerticalAlignment
pub const VerticalAlignment = enum
Where a cell's content sits between its top and bottom edges.
Values
bottomcentertop
spider.xlsx.Date
pub const Date = struct
A calendar date (proleptic Gregorian, no time zone).
Fields
year: u16month: u8: 1 to 12.day: u8: 1 to 31.
xlsx.Date.serial
pub fn serial(date: Date) Error!u32
The day number the 1900 date system gives this date.
spider.xlsx.DateTime
pub const DateTime = struct
A calendar date and a time of day (no time zone: the spreadsheet shows exactly these fields).
Fields
year: u16month: u8day: u8hour: u8 = 0minute: u8 = 0second: u8 = 0millisecond: u16 = 0
xlsx.DateTime.serial
pub fn serial(dt: DateTime) Error!f64
Day number plus the fraction of the day.
xlsx.DateTime.fromUnix
pub fn fromUnix(seconds: i64) Error!DateTime
The UTC date and time of a Unix timestamp (seconds since 1970-01-01). Add the zone offset to seconds first to get local time.
spider.xlsx.Range
pub const Range = struct
A rectangle of cells, both corners included.
Fields
first_row: u32first_col: u32last_row: u32last_col: u32
xlsx.Range.write
pub fn write(range: Range, w: *Writer) Writer.Error!void
A1:D51.
xlsx.Range.writeAbsolute
pub fn writeAbsolute(range: Range, w: *Writer) Writer.Error!void
$A$1:$D$51.
spider.xlsx.PageSetup
pub const PageSetup = struct
How a sheet is printed.
Fields
paper: ?Paper = .a4: Null leaves the paper to the program that opens the file.orientation: Orientation = .portraitmargins: Margins = .{}scale: ?u16 = null: Prints at this percentage of the real size, 10 to 400.fit_to_width: ?u16 = null: Shrinks the sheet to this many pages across; 0 means as many as it takes. Cannot be combined withscale. When only one offit_to_widthandfit_to_heightis set, the other counts as 1 page: set it to 0 to leave that direction free.fit_to_height: ?u16 = null: Likewise, for pages down.
spider.xlsx.Paper
pub const Paper = enum(u8)
Paper sizes for PageSetup.paper.
Values
letter = 1legal = 5a3 = 8a4 = 9a5 = 11
spider.xlsx.Orientation
pub const Orientation = enum
Which way the page is turned when printed.
Values
portraitlandscape
spider.xlsx.Margins
pub const Margins = struct
Page margins in inches, the unit the file uses (cm converts). The defaults are Excel's "Normal" margins. header and footer are the distance from the paper's edge to the header and footer text.
Fields
left: f64 = 0.7right: f64 = 0.7top: f64 = 0.75bottom: f64 = 0.75header: f64 = 0.3footer: f64 = 0.3
spider.xlsx.HeaderFooter
pub const HeaderFooter = struct
Text printed at the top and bottom of every page, in Excel's notation: &L, &C and &R start the left, centre and right parts; &P is the page number, &N the number of pages, &D the date, &A the sheet name; && is a literal &. Example footer: "&LReport&RPage &P of &N".
Fields
header: ?[]const u8 = nullfooter: ?[]const u8 = null
spider.xlsx.Protection
pub const Protection = struct
Options of Workbook.protect and Sheet.protect.
Protection is a guard against editing by accident, not security: the file is not encrypted, anyone can read it, and the password is kept as a 16-bit hash that many other passwords also match.
Fields
password: ?[]const u8 = null: Asked for when the user removes the protection. Null: no password, protection is removed with a click.
spider.xlsx.cm
pub fn cm(centimetres: f64) f64
Centimetres to inches, for Margins.
spider.xlsx.link_style
pub const link_style: Style = .{ .underline = true, .font_color = 0x0563C1 }
How spreadsheet programs draw a link: blue and underlined. A link does not style its cell; pass this (or a copy with more fields set) with the cell's value.
spider.xlsx.Reader
pub const Reader = struct
An open .xlsx file. open reads the list of sheets; rows reads one sheet, row by row.
const book = try xlsx.Reader.open(allocator, bytes, .{});
defer book.deinit();
const rows = try book.rows(0, .{});
defer rows.deinit();
while (try rows.next()) |row| {
for (row.cells) |cell| switch (cell.value) {
.text => |text| std.debug.print("{d}:{d} {s}\n", .{ row.number, cell.column, text }),
.number => |n| std.debug.print("{d}:{d} {d}\n", .{ row.number, cell.column, n }),
else => {},
};
}
Rows and columns the file does not have are skipped: use row.number and cell.column, not the position in the iteration.
Apart from diagnostic, the fields are the reader's own state.
Fields
gpa: std.mem.Allocatorarena: std.heap.ArenaAllocator: Owns what lives as long as the reader: names, formats.archive: zip_reader.Archivelimits: Limitsdiagnostic: Diagnostic = .{}: Where the last error happened.sheet_list: []SheetInfo = &.{}sheet_parts: []?*const zip_reader.Entry = &.{}: Null for a sheet that is not a worksheet.date_system: date_mod.DateSystem = .excel_1900formats: []Format = &.{}strings_part: ?*const zip_reader.Entry = nullstrings_loaded: bool = falsestring_data: std.ArrayList(u8) = .empty: Every shared string, back to back, and where each one ends.string_ends: std.ArrayList(u32) = .empty
xlsx.Reader.open
pub fn open(gpa: std.mem.Allocator, bytes: []const u8, limits: Limits) Error!*Reader
Opens a workbook from the bytes of an .xlsx file. bytes must stay valid until deinit. Reads the sheet list and the number formats; sheets are read by rows. The reader is allocated with gpa: free it with deinit.
xlsx.Reader.openDiagnosed
pub fn openDiagnosed(gpa: std.mem.Allocator, bytes: []const u8, limits: Limits, diagnostic: *Diagnostic) Error!*Reader
Like open; when it fails, diagnostic says where.
xlsx.Reader.deinit
pub fn deinit(self: *Reader) void
Frees the reader. Free every Rows of it first. The file's bytes are no longer needed afterwards.
xlsx.Reader.sheets
pub fn sheets(self: *const Reader) []const SheetInfo
The sheets, in the order of the workbook's tabs.
xlsx.Reader.sheetIndex
pub fn sheetIndex(self: *const Reader, name: []const u8) ?usize
Finds a sheet by name, ignoring the case of ASCII letters.
xlsx.Reader.rows
pub fn rows(self: *Reader, sheet: usize, options: Options) Error!*Rows
Starts reading the rows of the sheet at index sheet (see sheets and sheetIndex). Free the iterator with Rows.deinit; several can be open at once. The first call also loads the shared strings table. Fails with error.SheetNotFound for an index past the last sheet and error.Unsupported for a sheet that is not a worksheet.
spider.xlsx.Rows
pub const Rows = struct
The rows of one sheet, read as they are asked for.
Fields
reader: *Readersheet: usizepart: *PartReaderoptions: Optionsrow_arena: std.heap.ArenaAllocator: Reset for every row: texts and formulas of the row's cells.cells: std.ArrayList(Cell) = .emptyscratch: std.ArrayList(u8) = .emptyformula_scratch: std.ArrayList(u8) = .emptymerges: std.ArrayList(Range) = .emptymasters: std.AutoHashMapUnmanaged(u32, SharedFormula) = .empty: First cell of each shared formula, for the cells that reuse it.masters_arena: std.heap.ArenaAllocatorin_sheet_data: bool = falsefinished: bool = falselast_row: ?u32 = nullrows_read: u32 = 0
xlsx.Rows.deinit
pub fn deinit(self: *Rows) void
Frees the iterator, the last row returned and the list of merged ranges. Call it before the reader's deinit.
xlsx.Rows.mergedRanges
pub fn mergedRanges(self: *const Rows) []const Range
The merged ranges of the sheet. They come after the rows in the file, so the list is complete only once next has returned null.
xlsx.Rows.next
pub fn next(self: *Rows) Error!?Row
The next row that exists in the file, or null after the last. After an error the iterator is finished.
spider.xlsx.ReadLimits
pub const Limits = struct
How much a file may ask of the server before it is refused.
The defaults are meant for files uploaded by people you do not know: they accept any ordinary spreadsheet and bound the memory and time a hostile one can take. Limits.large is for files you expect to be big.
Fields
max_file_bytes: u64 = 16 << 20: Size of the .xlsx file itself.max_entries: u32 = 1_000: Entries in the zip archive.max_part_bytes: u64 = 64 << 20: Uncompressed size of one part (a sheet's XML, for instance).max_total_bytes: u64 = 128 << 20: Uncompressed size of all parts together.max_compression_ratio: u32 = 200: Uncompressed/compressed ratio of one part larger than 1 MiB.max_shared_strings_bytes: u64 = 32 << 20: Memory the shared strings table may take. It is the one thing that has to be loaded whole before a sheet is read.max_rows: u32 = 100_000: Rows read from one sheet: the row after the last allowed one iserror.LimitExceeded, the sheet is not cut short.max_columns: u32 = 16_384: Columns: a cell beyond this is an error. Excel's limit.max_cell_text: u32 = 32_767: Characters in one cell's text, counted as Excel does. Excel's limit.max_merged_ranges: u32 = 10_000: Merged ranges per sheet; one more iserror.LimitExceeded.xml: xml_reader.Limits = .{}: Depth, attributes and sizes of the XML itself.
xlsx.ReadLimits.large
pub const large: Limits = .{ ...
For large files from a known source (an ERP export of a hundred thousand rows, say): files up to 256 MiB, parts up to 1 GiB, a full sheet of rows, 256 MiB of shared strings. Reading stays streamed, but the shared strings table alone may now take up to 256 MiB of memory, and parsing a gigabyte of XML takes tens of seconds of CPU: do not use it for uploads by strangers.
spider.xlsx.ReadOptions
pub const Options = struct
Options of Reader.rows. .{} reads values only.
Fields
formulas: bool = false: Also return each formula's text.
spider.xlsx.ReadError
pub const Error = error
Everything opening or reading a file can fail with. A Diagnostic says where in the file it happened.
Errors
LimitExceeded: One ofLimitswas exceeded;Diagnostic.limitsays which.InvalidZip: Not a zip archive, or a damaged one.InvalidXml: A part is not well-formed XML (or has a document type declaration, which is never accepted).InvalidFile: A valid zip and valid XML, but not a workbook this reader understands: a part is missing, a reference is malformed, rows or cells are out of order, a number is not a number.Unsupported: Not an .xlsx: an old .xls, an .xlsb, a zip64 archive, a compression method other than store and deflate, or a sheet that is not a worksheet (a chart sheet, a macro sheet).Encrypted: The file is protected by a password to open.SheetNotFoundOutOfMemory
spider.xlsx.ReadDiagnostic
pub const Diagnostic = struct
Where the last error happened. It never holds text from the file.
Fields
part: Part = .nonesheet: ?usize = null: Index of the sheet, whenpartis.sheet.row: ?u32 = null: Zero-based row and column being read, when known.column: ?u32 = nullbyte_offset: ?u64 = null: How far into the part's XML the reader was, in bytes.limit: ?LimitKind = null: Forerror.LimitExceeded: the limit.
spider.xlsx.ReadRow
pub const Row = struct
One row of a sheet. cells and the texts in it are valid until the next call to Rows.next.
Fields
number: u32: Zero-based. Rows the file does not have are simply not returned: numbers can jump.hidden: boolcells: []const Cell: In column order; columns can jump too.
spider.xlsx.ReadCell
pub const Cell = struct
One cell of a Row. Cells the file does not have are not returned.
Fields
column: u32: Zero-based.value: Valueformat: []const u8: The cell's number format code,"General"when it has none. It tells how the author meant a number to be shown: with"00000000000", 1234567890 is the document 01234567890.formula: ?[]const u8 = null: The formula's text without=, whenOptions.formulasis set and the cell has one. It is never evaluated.
spider.xlsx.ReadValue
pub const Value = union(enum)
What a cell holds.
Fields
empty: A cell with formatting and no content, or a formula never calculated.text: []const u8number: f64boolean: booldate: DateTime: A number shown as a date (seeCell.format), converted. The time of day is in it too. A number that is no date a spreadsheet can show (negative, day 0 or day 60 of the 1900 system) stays anumber.time: TimeOfDay: A number between 0 and 1 shown as a time.err: []const u8: An error value such as#DIV/0!or#N/A, as text.
spider.xlsx.SheetInfo
pub const SheetInfo = struct
One sheet of the file, as listed by Reader.sheets. name lives as long as the reader.
Fields
name: []const u8visibility: Visibility
spider.xlsx.TimeOfDay
pub const TimeOfDay = struct
The time of day of a cell that holds no date.
Fields
hour: u8minute: u8second: u8millisecond: u16
xlsx.TimeOfDay.fromFraction
pub fn fromFraction(fraction: f64) TimeOfDay
From the fraction of a day (0 up to 1), rounded to the millisecond. Anything from 1 on gives 23:59:59.999; a negative number, or one that is not a number, gives 00:00:00.
spider.xlsx.ReadLimitKind
pub const LimitKind = enum
Which of Limits was exceeded; each name is the field without max_.
Values
file_bytesentriespart_bytestotal_bytescompression_ratioshared_strings_bytesrowscolumnscell_textmerged_rangesxml
spider.xlsx.ReadPart
pub const Part = enum { none, package, workbook, styles, shared_strings, sheet }
Which part of the file was being read.
spider.xlsx.SheetVisibility
pub const Visibility = enum { visible, hidden, very_hidden }
Whether a sheet shows among the tabs. hidden and very_hidden are the file's two hidden states.
spider.xlsx.DateSystem
pub const DateSystem = enum
Which day a serial number counts from. A workbook says which one it uses; almost all use 1900.
Values
excel_1900: Day 1 is 1900-01-01, and day 60 is the 1900-02-29 that never existed.excel_1904: Day 0 is 1904-01-01; no phantom day.
spider.xlsx.Packager
pub const Packager = struct
What the workbook writes its parts to. Implement this to replace the container (a compressing zip, a directory on disk for debugging, a test double that records the parts).
addPart is called once per part, in a fixed order, and finish once at the end. content is only valid during the call.
Fields
ptr: *anyopaquevtable: *const VTable
xlsx.Packager.VTable
pub const VTable = struct
The two functions of an implementation; ptr is passed back to them.
Fields
addPart: *const fn (ptr: *anyopaque, name: []const u8, content: []const u8) Error!voidfinish: *const fn (ptr: *anyopaque) Error!void
xlsx.Packager.addPart
pub fn addPart(p: Packager, name: []const u8, content: []const u8) Error!void
Adds the part name with content. Called by the workbook.
xlsx.Packager.finish
pub fn finish(p: Packager) Error!void
Ends the package. Called by the workbook after the last part.
spider.xlsx.StoreZip
pub const StoreZip = struct
A zip writer that stores every entry uncompressed.
Fields
allocator: std.mem.Allocatorout: *Writerentries: std.ArrayList(Entry) = .emptyoffset: u64 = 0: Bytes written tooutso far, i.e. where the next header starts.finished: bool = false
xlsx.StoreZip.init
pub fn init(allocator: std.mem.Allocator, out: *Writer) StoreZip
out is not flushed by this type: flush it after finish if it is buffered (a file or socket writer).
xlsx.StoreZip.deinit
pub fn deinit(self: *StoreZip) void
Frees the list of entries. Writes nothing: call finish first.
xlsx.StoreZip.packager
pub fn packager(self: *StoreZip) Packager
This writer as a Packager, for Workbook.writeToPackager. It points at self, which must not move or be freed while it is in use.
xlsx.StoreZip.addPart
pub fn addPart(self: *StoreZip, name: []const u8, content: []const u8) Error!void
Writes one entry: local header, then the content.
xlsx.StoreZip.finish
pub fn finish(self: *StoreZip) Error!void
Writes the central directory and the end record. No part can be added afterwards.
spider.xlsx.content_type
pub const content_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
The MIME type of a .xlsx file, for a Content-Type header.
spider.xlsx.max_rows
pub const max_rows: u32 = 1_048_576
Excel's sheet size: rows 0..1,048,575 and columns 0..16,383 (XFD).
spider.xlsx.max_cols
pub const max_cols: u32 = 16_384
Columns per sheet (A to XFD).
spider.xlsx.max_text_len
pub const max_text_len = 32_767
Characters per cell, counted as Excel does (UTF-16 code units).
spider.xlsx.max_formula_len
pub const max_formula_len = 8_192
Characters per formula.
spider.xlsx.max_sheet_name_len
pub const max_sheet_name_len = 31
Characters per sheet name.
spider.xlsx.max_column_width
pub const max_column_width = 255
Widest column, in characters of the default font.
spider.xlsx.max_row_height
pub const max_row_height = 409
Row height, in points.
spider.xlsx.max_link_len
pub const max_link_len = 2_079
Longest link target, in bytes.
spider.xlsx.max_links_per_sheet
pub const max_links_per_sheet = 65_530
Links per sheet.