125 / Entrada, salida y datos

Leer una hoja .xlsx

Un banco manda el estado de cuenta en Excel y el ERP lo concilia. Para no depender de un archivo de entrada, la receta arma primero un libro con xlsx_write y después lo lee como si viniera de afuera.

125-xlsx-leer-hoja.nxFuente →
// Nyx by Example: leer una planilla .xlsx e imprimir una hoja.
//
// El caso real: un banco manda el estado de cuenta en Excel y el ERP lo
// concilia. Para no depender de un archivo de entrada, la receta arma primero
// una planilla con xlsx_write y después la lee como si viniera de afuera.
//
// Lo que muestra:
//   - xlsx_read(bytes, xlsx_read_opts()): topes por omisión contra bombas zip
//     y libros gigantes (archivo, partes, total descomprimido, celdas);
//   - cada celda trae su TIPO (kind: text, number, date, bool, error, empty),
//     `text` (un importe se lee tal cual está escrito) y `number`;
//   - las fechas salen en ISO (con la época 1900 o 1904 del libro);
//   - rows[f][c] es la celda de la fila f+1, columna c+1: los huecos son celdas
//     "empty", así "C7" cae donde debe; xlsx_cell(hoja, "B3") la pide por nombre;
//   - las FÓRMULAS no se evalúan: se lee el valor que el archivo trae en caché;
//   - xlsx_sheet(libro, nombre) busca la hoja por nombre (Option).
//
// Correr: nyx run

import "std/xlsx"
import "std/error"

fn planilla() -> Result<String, Error> {
    var h: XlsxSheetOut = xlsx_sheet_new("Movimientos")
    h.row([xlsx_text("Fecha"), xlsx_text("Descripción"), xlsx_text("Monto")])
    h.row([xlsx_date("2026-09-01"), xlsx_text("Depósito"), xlsx_number(1234.5, 2)])
    h.row([xlsx_date("2026-09-03"), xlsx_text("Comisión"), xlsx_number(0.0 - 12.75, 2)])
    h.row([xlsx_date("2026-09-10"), xlsx_blank(), xlsx_number(80.0, 2)])
    return xlsx_write([h])
}

fn main() -> int {
    let bytes: String = match planilla() {
        Result.Ok(b) => b
        Result.Err(e) => {
            print("no se pudo armar la planilla: " + error_to_string(e))
            return 1
        }
    }

    match xlsx_read(bytes, xlsx_read_opts()) {
        Result.Ok(libro) => {
            match xlsx_sheet(libro, "Movimientos") {
                Option.Some(hoja) => {
                    print("hoja " + hoja.name + ": " + int_to_string(hoja.rows.length()) + " filas")
                    for fila: Array in hoja.rows {
                        var linea: String = ""
                        for c: XlsxCell in fila {
                            var t: String = c.text
                            if c.kind == "empty" { t = "-" }
                            linea = linea + t + " | "
                        }
                        print(linea)
                    }
                    let monto: XlsxCell = xlsx_cell(hoja, "C2")
                    print("C2 es " + monto.kind + ", vale " + float_to_string(monto.number) + ", formato " + monto.format)
                    let fecha: XlsxCell = xlsx_cell(hoja, "A3")
                    print("A3 es " + fecha.kind + ": " + fecha.text)
                    let hueco: XlsxCell = xlsx_cell(hoja, "B4")
                    print("B4 es " + hueco.kind)
                }
                Option.None => {
                    print("no hay hoja Movimientos")
                    return 1
                }
            }
        }
        Result.Err(e) => {
            print("planilla inválida: " + error_to_string(e))
            return 1
        }
    }
    return 0
}
Salidastdout
hoja Movimientos: 4 filas
Fecha | Descripción | Monto | 
2026-09-01 | Depósito | 1234.50 | 
2026-09-03 | Comisión | -12.75 | 
2026-09-10 | - | 80.00 | 
C2 es number, vale 1234.5, formato 0.00
A3 es date: 2026-09-03
B4 es empty

Cómo funciona

xlsx_read(bytes, xlsx_read_opts()) trae topes por omisión contra bombas zip y libros gigantes (archivo, partes, total descomprimido, celdas). Cada celda trae su TIPO — text, number, date, bool, error o empty — además de su text, de modo que un importe se lee tal cual está escrito, y su number. Las fechas salen en ISO, con la época 1900 o 1904 del libro ya aplicada.

rows[f][c] es la celda de la fila f+1, columna c+1. Los huecos son celdas de tipo empty, así C7 cae donde debe, y xlsx_cell(hoja, "B3") pide una por su nombre — mira las tres últimas líneas de la salida. Las FÓRMULAS no se evalúan: se lee el valor que el archivo trae en caché. xlsx_sheet(libro, nombre) busca una hoja por nombre y devuelve un Option.