FIX: Minimal support for inlineStr

Fixes #424
This commit is contained in:
Nicolás Hatcher
2025-07-31 18:24:48 +02:00
committed by Nicolás Hatcher Andrés
parent b9b3cb1628
commit faa0ff9b69
3 changed files with 65 additions and 15 deletions

View File

@@ -336,6 +336,7 @@ fn get_cell_from_excel(
sheet_name: &str, sheet_name: &str,
cell_ref: &str, cell_ref: &str,
shared_strings: &mut Vec<String>, shared_strings: &mut Vec<String>,
rich_text_inline: Option<String>,
) -> Cell { ) -> Cell {
// Possible cell types: // Possible cell types:
// 18.18.11 ST_CellType (Cell Type) // 18.18.11 ST_CellType (Cell Type)
@@ -397,12 +398,15 @@ fn get_cell_from_excel(
} }
} }
"inlineStr" => { "inlineStr" => {
// Not implemented let s = rich_text_inline.unwrap_or_default();
println!("Invalid type (inlineStr) in {sheet_name}!{cell_ref}"); let si = if let Some(i) = shared_strings.iter().position(|r| r == &s) {
Cell::ErrorCell { i
ei: Error::NIMPL, } else {
s: cell_style, shared_strings.push(s.to_string());
} shared_strings.len() - 1
} as i32;
Cell::SharedString { si, s: cell_style }
} }
"empty" => Cell::EmptyCell { s: cell_style }, "empty" => Cell::EmptyCell { s: cell_style },
_ => { _ => {
@@ -480,16 +484,11 @@ fn get_cell_from_excel(
} }
} }
"inlineStr" => { "inlineStr" => {
// Not implemented // NB: This is untested, I don't know of any engine that uses inline strings in formulas
let o = format!("{sheet_name}!{cell_ref}"); Cell::CellFormulaString {
let m = Error::NIMPL.to_string();
println!("Invalid type (inlineStr) in {sheet_name}!{cell_ref}");
Cell::CellFormulaError {
f: formula_index, f: formula_index,
ei: Error::NIMPL, v: rich_text_inline.unwrap_or("".to_string()),
s: cell_style, s: cell_style,
o,
m,
} }
} }
_ => { _ => {
@@ -796,7 +795,7 @@ pub(super) fn load_sheet<R: Read + std::io::Seek>(
// 18.3.1.4 c (Cell) // 18.3.1.4 c (Cell)
// Child Elements: // Child Elements:
// * v: Cell value // * v: Cell value
// * is: Rich Text Inline (not used in IronCalc) // * is: Rich Text Inline
// * f: Formula // * f: Formula
// Attributes: // Attributes:
// r: reference. A1 style // r: reference. A1 style
@@ -820,6 +819,26 @@ pub(super) fn load_sheet<R: Read + std::io::Seek>(
None None
}; };
// <c r="A1" t="inlineStr">
// <is>
// <t>Hello, World!</t>
// </is>
// </c>
let cell_rich_text_nodes: Vec<Node> =
cell.children().filter(|n| n.has_tag_name("is")).collect();
let cell_rich_text = if cell_rich_text_nodes.is_empty() {
None
} else {
let texts: Vec<String> = cell_rich_text_nodes[0]
.descendants()
.filter(|n| n.has_tag_name("t"))
.filter_map(|n| n.text())
.map(|s| s.to_string())
.collect();
Some(texts.join(""))
};
let cell_metadata = cell.attribute("cm"); let cell_metadata = cell.attribute("cm");
// type, the default type being "n" for number // type, the default type being "n" for number
@@ -976,6 +995,7 @@ pub(super) fn load_sheet<R: Read + std::io::Seek>(
sheet_name, sheet_name,
cell_ref, cell_ref,
shared_strings, shared_strings,
cell_rich_text,
); );
data_row.insert(column, cell); data_row.insert(column, cell);
} }

Binary file not shown.

View File

@@ -531,3 +531,33 @@ fn test_user_model() {
// we can still use the model afterwards // we can still use the model afterwards
model.set_rows_height(0, 1, 1, 100.0).unwrap(); model.set_rows_height(0, 1, 1, 100.0).unwrap();
} }
// This is produced with:
// from openpyxl import Workbook
// # Create new workbook
// wb = Workbook()
// ws = wb.active
// # Write text and formula
// ws['A1'] = 'Hello, World!'
// ws['A2'] = '=1+1'
// ws['B1'] = '=CONCAT("It is", " what it is")'
// # Save
// wb.save('openpyxl_example.xlsx')
#[test]
fn test_pyopenxl_example() {
let mut model = load_from_xlsx("tests/openpyxl_example.xlsx", "en", "UTC").unwrap();
model.evaluate();
let a1 = model.get_formatted_cell_value(0, 1, 1).unwrap();
assert_eq!(a1, "Hello, World!");
let a2 = model.get_formatted_cell_value(0, 2, 1).unwrap();
assert_eq!(a2, "2");
let b1 = model.get_formatted_cell_value(0, 1, 2).unwrap();
assert_eq!(b1, "It is what it is");
}