tafia / calamine

A pure Rust Excel/OpenDocument SpreadSheets file reader: rust on metal sheets
MIT License
1.6k stars 155 forks source link

How to open_workbook from excel xml? #371

Closed bwkam closed 8 months ago

bwkam commented 8 months ago

Hi, newbie here. I read the xlsx files on the client side and send their xml content to the server, so I need a way to read the files from the xml, how do I achieve that? I see open_workbook requires the path of the file though. Sorry if that's a basic question, but I wasn't able to find an answer.

Edit:

#[derive(Deserialize, Debug)]
pub struct Payload {
    pub data: Vec<String>,
}

async fn hello(Json(body): Json<Payload>) -> impl IntoResponse {
    println!("{:?}", &body.data[0]);
    let bytes = &body.data[0].as_bytes();
    let reader = Cursor::new(&bytes);
    let xlsx = open_workbook_auto_from_rs(reader).unwrap();
    let sheets = xlsx.sheet_names().to_owned();
    println!("{:?}", sheets);

    Json(message)
}

I found open_workbook_auto_from_rs, I believe that's what I want, not sure if I'm doing this correctly, but I keep getting this:

thread 'tokio-runtime-worker' panicked at 'called `Result::unwrap()` on an `Err` value: Msg("Cannot detect file format")'
"PK\u{3}\u{4}\u{14}\0\0\0\0\0\0\0\0\0�\u{1}���\u{2}\0\0�\u{2}\0\0\u{1a}\0\0\0xl/_rels/workbook.xml.rels<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\"><Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/><Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme\" Target=\"theme/theme1.xml\"/><Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/><Relationship Id=\"rId4\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata\" Target=\"metadata.xml\"/></Relationships>PK\u{3}\u{4}\u{14}\0\0\0\0\0\0\0\0\00\u{f}�k�\u{1d}\0\0�\u{1d}\0\0\u{13}\0\0\0xl/theme/theme1.xml<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\r\n<a:theme xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\" name=\"Office Theme\"><a:themeElements><a:clrScheme name=\"Office\"><a:dk1><a:sysClr val=\"windowText\" lastClr=\"000000\"/></a:dk1><a:lt

This is what the data I'm sending from the client kinda looks like. (incomplete)

Edit 2:

async fn hello(Json(body): Json<Payload>) -> impl IntoResponse {
    let bytes = body.data[0].as_bytes();
    let reader = Cursor::new(&bytes);
    let mut excel = Sheets::new(reader).unwrap();
}

This errors with Msg("Sheets must be created from a Path"). I don't know why, I looked into https://github.com/tafia/calamine/blob/c66195c76676b29bdd78c6e977b3333082dc6fd5/src/auto.rs#L83C1-L85C6, no idea why it blindly returns an err.

I tried the open_workbook_from_rs function, but that as well errors.

async fn hello(Json(body): Json<Payload>) -> impl IntoResponse {
    let bytes = body.data[0].as_bytes();
    let reader = Cursor::new(&bytes);
    let mut excel: Xlsx<_> = open_workbook_from_rs(reader).unwrap();
}

Zip(Io(Error { kind: UnexpectedEof, message: "failed to fill whole buffer" }))

bwkam commented 8 months ago

Nevermind, I fixed it. I returned a formdata from my client, and the sent the file(s) binaries as the fields, then read the bytes from open_workbook_from_rs. Worked good.