Open sa2304 opened 2 years ago
Okay, I found a solution. Not optimized yet, but working.
bool InRange(const xlnt::cell &cell, const xlnt::range_reference &range) {
return range.top_left().row() <= cell.row()
&& range.top_left().column() <= cell.column()
&& cell.row() <= range.bottom_right().row()
&& cell.column() <= range.bottom_right().column();
}
template <class T>
std::optional<T> GetValue(const xlnt::cell& cell) try {
auto s = cell.to_string();
return boost::lexical_cast<T>(s);
} catch (...) {
return {};
}
template <class T>
std::optional<T> GetMergedCellValue(const xlnt::worksheet& sheet, const xlnt::cell& cell) {
if (cell.is_merged()) {
for (const auto& r : sheet.merged_ranges()) {
if (InRange(cell, r)) {
return GetValue<T>(sheet.cell(r.top_left()));
}
}
} else return GetValue<T>(cell);
}
class TestUtils : public ::testing::Test {};
TEST_F(TestUtils, GetMergedCellValue) {
{
xlnt::workbook wb;
auto sheet = wb.active_sheet();
sheet.cell("A1"s).value("Test"s);
ASSERT_FALSE(sheet.cell("A2"s).has_value());
sheet.merge_cells("A1:A3"s);
// value is not copied to other cells
ASSERT_FALSE(sheet.cell("A2"s).has_value());
// but our utility function could access it
auto value = utils::GetMergedCellValue<string>(sheet, sheet.cell("A2"s));
ASSERT_EQ("Test"s, value);
}
}
I could see how this would be useful. Glad that you found a workaround. I can take a look at the code to see if I can add a built-in interface for this.
merged-cells.xlsx
I've got an XLSX file with some merged cells. Each line in file describes an item.
I iterate over rows and want to get all the values in columns.
File contains cell A1="Group 1" that is merged: spans range A1:A3. When I read first line, I've got A1's value. But A2 doesn't have any value, only spreadsheet knows that it has mergeCells node.
I only see xlnt::cell has is_merged() flag, but does xlnt API have any way to get a reference to first cell in that range?