use std::path::Path;
use lo_core::{CellAddr, CellValue, Result, Workbook};
use crate::common::{content_root_attrs, package_document, MIME_ODS};
fn odf_formula(formula: &str) -> String {
if formula.starts_with("of:=") {
formula.to_string()
} else if formula.starts_with('=') {
format!("of:{formula}")
} else {
format!("of:={formula}")
}
}
fn cell_xml(value: &CellValue) -> String {
match value {
CellValue::Empty => "<table:table-cell/>".to_string(),
CellValue::Number(number) => format!(
"<table:table-cell office:value-type=\"float\" office:value=\"{number}\"><text:p>{number}</text:p></table:table-cell>"
),
CellValue::Text(text) => format!(
"<table:table-cell office:value-type=\"string\"><text:p>{}</text:p></table:table-cell>",
lo_core::escape_text(text)
),
CellValue::Bool(value) => format!(
"<table:table-cell office:value-type=\"boolean\" office:boolean-value=\"{}\"><text:p>{}</text:p></table:table-cell>",
value,
value
),
CellValue::Formula(formula) => format!(
"<table:table-cell table:formula=\"{}\" office:value-type=\"string\"><text:p>{}</text:p></table:table-cell>",
lo_core::escape_attr(&odf_formula(formula)),
lo_core::escape_text(formula)
),
CellValue::Error(message) => format!(
"<table:table-cell office:value-type=\"string\"><text:p>#ERR {}</text:p></table:table-cell>",
lo_core::escape_text(message)
),
}
}
pub fn serialize_spreadsheet_document(book: &Workbook) -> String {
let mut xml = lo_core::XmlBuilder::new();
xml.declaration();
xml.open("office:document-content", &content_root_attrs());
xml.empty("office:scripts", &[]);
xml.empty("office:automatic-styles", &[]);
xml.open("office:body", &[]);
xml.open("office:spreadsheet", &[]);
for sheet in &book.sheets {
xml.raw(&format!(
"<table:table table:name=\"{}\">",
lo_core::escape_attr(&sheet.name)
));
let (max_row, max_col) = sheet.max_extent();
for row in 0..=max_row {
xml.raw("<table:table-row>");
for col in 0..=max_col {
let addr = CellAddr::new(row, col);
let cell = sheet.get(addr).map(|cell| &cell.value).unwrap_or(&CellValue::Empty);
xml.raw(&cell_xml(cell));
}
xml.raw("</table:table-row>");
}
xml.raw("</table:table>");
}
xml.close();
xml.close();
xml.close();
xml.finish()
}
pub fn save_spreadsheet_document(path: impl AsRef<Path>, book: &Workbook) -> Result<()> {
let content = serialize_spreadsheet_document(book);
package_document(path, MIME_ODS, content, &book.meta, Vec::new())
}