diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp
index 4d6f5405..eab4ade7 100644
--- a/include/xlnt/workbook/workbook.hpp
+++ b/include/xlnt/workbook/workbook.hpp
@@ -758,6 +758,11 @@ private:
///
void register_comments_in_manifest(worksheet ws);
+ ///
+ /// Removes calcChain part from manifest if no formulae remain in workbook.
+ ///
+ void garbage_collect_formulae();
+
///
/// An opaque pointer to a structure that holds all of the data relating to this workbook.
///
diff --git a/include/xlnt/worksheet/worksheet.hpp b/include/xlnt/worksheet/worksheet.hpp
index 13205352..16fc9dc5 100644
--- a/include/xlnt/worksheet/worksheet.hpp
+++ b/include/xlnt/worksheet/worksheet.hpp
@@ -742,6 +742,11 @@ private:
///
void register_comments_in_manifest();
+ ///
+ /// Removes calcChain part from manifest if no formulae remain in workbook.
+ ///
+ void garbage_collect_formulae();
+
///
///
///
diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp
index f1beb65b..7a60e095 100644
--- a/source/cell/cell.cpp
+++ b/source/cell/cell.cpp
@@ -508,6 +508,7 @@ std::string cell::formula() const
void cell::clear_formula()
{
d_->formula_.clear();
+ worksheet().garbage_collect_formulae();
}
void cell::error(const std::string &error)
@@ -609,8 +610,8 @@ void cell::clear_value()
{
d_->value_numeric_ = 0;
d_->value_text_.clear();
- d_->formula_.clear();
d_->type_ = cell::type::null;
+ clear_formula();
}
template <>
diff --git a/source/detail/custom_value_traits.cpp b/source/detail/custom_value_traits.cpp
index bd92dc82..928097c7 100644
--- a/source/detail/custom_value_traits.cpp
+++ b/source/detail/custom_value_traits.cpp
@@ -37,7 +37,7 @@ std::string to_string(relationship_type t)
case relationship_type::thumbnail:
return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
case relationship_type::calculation_chain:
- return "http://purl.oclc.org/ooxml/officeDocument/relationships/calcChain";
+ return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain";
case relationship_type::extended_properties:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
case relationship_type::core_properties:
diff --git a/source/workbook/tests/test_consume_xlsx.hpp b/source/workbook/tests/test_consume_xlsx.hpp
index b6a4ba77..44e0dddf 100644
--- a/source/workbook/tests/test_consume_xlsx.hpp
+++ b/source/workbook/tests/test_consume_xlsx.hpp
@@ -112,4 +112,16 @@ public:
TS_ASSERT(wb.has_custom_property("Client"));
TS_ASSERT_EQUALS(wb.custom_property("Client"), "me!");
}
+
+ void test_read_formulae()
+ {
+ xlnt::workbook wb;
+ wb.load("data/22_formulae.xlsx");
+ auto ws = wb.active_sheet();
+ TS_ASSERT_EQUALS(ws.cell("A1").value(), 6);
+ TS_ASSERT(ws.cell("A1").has_formula());
+ TS_ASSERT_EQUALS(ws.cell("A1").formula(), "A2*A3");
+ TS_ASSERT_EQUALS(ws.cell("A2").value(), 2);
+ TS_ASSERT_EQUALS(ws.cell("A3").value(), 3);
+ }
};
diff --git a/source/workbook/tests/test_produce_xlsx.hpp b/source/workbook/tests/test_produce_xlsx.hpp
index e42b1f29..a3bffa32 100644
--- a/source/workbook/tests/test_produce_xlsx.hpp
+++ b/source/workbook/tests/test_produce_xlsx.hpp
@@ -154,4 +154,15 @@ public:
TS_ASSERT(workbook_matches_file(wb, xlnt::path("data/15_basic_comments.xlsx")));
}
+
+ void test_save_after_clear_all_formulae()
+ {
+ xlnt::workbook wb;
+ wb.load("data/22_formulae.xlsx");
+ auto ws = wb.active_sheet();
+ TS_ASSERT(ws.cell("A1").has_formula());
+ TS_ASSERT_EQUALS(ws.cell("A1").formula(), "A2*A3");
+ ws.cell("A1").clear_formula();
+ wb.save("clear_formulae.xlsx");
+ }
};
diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp
index 87b9480e..288c5882 100644
--- a/source/workbook/workbook.cpp
+++ b/source/workbook/workbook.cpp
@@ -1260,4 +1260,38 @@ void workbook::calculation_properties(const class calculation_properties &props)
d_->calculation_properties_ = props;
}
+///
+/// Removes calcChain part from manifest if no formulae remain in workbook.
+///
+void workbook::garbage_collect_formulae()
+{
+ auto any_with_formula = false;
+
+ for (auto ws : *this)
+ {
+ for (auto row : ws.iter_cells(true))
+ {
+ for (auto cell : row)
+ {
+ if (cell.has_formula())
+ {
+ any_with_formula = true;
+ }
+ }
+ }
+ }
+
+ if (any_with_formula) return;
+
+ auto wb_rel = manifest().relationship(path("/"), relationship_type::office_document);
+
+ if (manifest().has_relationship(wb_rel.target().path(), relationship_type::calculation_chain))
+ {
+ auto calc_chain_rel = manifest().relationship(wb_rel.target().path(), relationship_type::calculation_chain);
+ auto calc_chain_part = manifest().canonicalize({wb_rel, calc_chain_rel});
+ manifest().unregister_override_type(calc_chain_part);
+ manifest().unregister_relationship(wb_rel.target(), calc_chain_rel.id());
+ }
+}
+
} // namespace xlnt
diff --git a/source/worksheet/worksheet.cpp b/source/worksheet/worksheet.cpp
index 7e1438ee..9531cf18 100644
--- a/source/worksheet/worksheet.cpp
+++ b/source/worksheet/worksheet.cpp
@@ -1068,4 +1068,9 @@ double worksheet::row_height(row_t row) const
}
}
+void worksheet::garbage_collect_formulae()
+{
+ workbook().garbage_collect_formulae();
+}
+
} // namespace xlnt
diff --git a/tests/data/22_formulae.xlsx b/tests/data/22_formulae.xlsx
new file mode 100644
index 00000000..e450aec0
Binary files /dev/null and b/tests/data/22_formulae.xlsx differ