diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index f7aa4e3c2..1b977aefe 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -82,6 +82,7 @@ struct stylesheet; struct workbook_impl; class xlsx_consumer; class xlsx_producer; +struct defined_name; } // namespace detail @@ -751,6 +752,38 @@ class XLNT_API workbook /// bool known_fonts_enabled() const; + // Defined Names + + /// + /// Add a defined name to a sheet + /// + /// Returns a copy of workbook defined names + /// + std::vector get_defined_names() const; + + /// + /// Returns a reference to a single defined name + /// + detail::defined_name &get_defined_name(const std::size_t index); + + /// + /// Returns a reference to a single defined name. Finds the first name that matches, there may be multiple with the same name + /// + detail::defined_name &get_defined_name(const std::string &name); + + /// + /// Removes the defined name at the given index + /// + void remove_defined_name(const std::size_t index); + + /// + /// Removes the defined name that first matches the passed name. + /// + void remove_defined_name(const std::string &name); + // Manifest /// diff --git a/include/xlnt/worksheet/worksheet.hpp b/include/xlnt/worksheet/worksheet.hpp index a4cf9e077..a303c3f9d 100644 --- a/include/xlnt/worksheet/worksheet.hpp +++ b/include/xlnt/worksheet/worksheet.hpp @@ -64,7 +64,7 @@ namespace detail { class xlsx_consumer; class xlsx_producer; - +struct defined_name; struct worksheet_impl; } // namespace detail @@ -729,6 +729,38 @@ class XLNT_API worksheet /// cell_reference active_cell() const; + // Defined Names + + /// + /// Add a defined name to a sheet + /// + /// Returns a copy of workbook defined names + /// + std::vector get_defined_names() const; + + /// + /// Returns a reference to a single defined name + /// + detail::defined_name &get_defined_name(const std::size_t index); + + /// + /// Returns a reference to a single defined name. Finds the first name that matches, there may be multiple with the same name + /// + detail::defined_name &get_defined_name(const std::string &name); + + /// + /// Removes the defined name at the given index + /// + void remove_defined_name(const std::size_t index); + + /// + /// Removes the defined name that first matches the passed name. + /// + void remove_defined_name(const std::string &name); + // page breaks /// diff --git a/source/detail/implementations/workbook_impl.hpp b/source/detail/implementations/workbook_impl.hpp index 338146188..1f5c8301a 100644 --- a/source/detail/implementations/workbook_impl.hpp +++ b/source/detail/implementations/workbook_impl.hpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -88,11 +89,20 @@ struct workbook_impl extended_properties_ = other.extended_properties_; custom_properties_ = other.custom_properties_; + defined_names_ = other.defined_names_; + return *this; } - bool operator==(const workbook_impl &other) + bool operator==(const workbook_impl &other) const { + if (defined_names_.size() != other.defined_names_.size()) return false; + + for (std::size_t i = 0; i < defined_names_.size(); i++) + { + if (defined_names_[i] != other.defined_names_[i]) return false; + } + return active_sheet_index_ == other.active_sheet_index_ && worksheets_ == other.worksheets_ && shared_strings_ids_ == other.shared_strings_ids_ @@ -168,6 +178,7 @@ struct workbook_impl optional abs_path_; optional arch_id_flags_; optional extensions_; + std::vector defined_names_; }; } // namespace detail diff --git a/source/detail/implementations/worksheet_impl.hpp b/source/detail/implementations/worksheet_impl.hpp index 7afcfb1d5..94f6af0c3 100644 --- a/source/detail/implementations/worksheet_impl.hpp +++ b/source/detail/implementations/worksheet_impl.hpp @@ -41,6 +41,7 @@ #include #include #include +#include namespace xlnt { @@ -88,6 +89,8 @@ struct worksheet_impl extension_list_ = other.extension_list_; sheet_properties_ = other.sheet_properties_; print_options_ = other.print_options_; + defined_names_ = other.defined_names_; + for (auto &cell : cell_map_) { @@ -97,8 +100,15 @@ struct worksheet_impl workbook *parent_; - bool operator==(const worksheet_impl& rhs) const + bool operator==(const worksheet_impl &rhs) const { + if (defined_names_.size() != rhs.defined_names_.size()) return false; + + for (std::size_t i = 0; i < defined_names_.size(); i++) + { + if (defined_names_[i] != rhs.defined_names_[i]) return false; + } + return id_ == rhs.id_ && title_ == rhs.title_ && format_properties_ == rhs.format_properties_ @@ -122,6 +132,7 @@ struct worksheet_impl && print_options_ == rhs.print_options_ && sheet_properties_ == rhs.sheet_properties_ && extension_list_ == rhs.extension_list_; + } std::size_t id_; @@ -160,6 +171,8 @@ struct worksheet_impl std::string drawing_rel_id_; optional drawing_; + + std::vector defined_names_; }; } // namespace detail diff --git a/source/detail/serialization/defined_name.hpp b/source/detail/serialization/defined_name.hpp index 3aeb91323..82a44ead1 100644 --- a/source/detail/serialization/defined_name.hpp +++ b/source/detail/serialization/defined_name.hpp @@ -30,10 +30,63 @@ namespace detail { struct defined_name { - std::string name; - std::size_t sheet_id; - bool hidden; - std::string value; + + defined_name &operator=(const defined_name &other) + { + name = other.name; + comment = other.comment; + custom_menu = other.custom_menu; + description = other.description; + help = other.help; + + status_bar = other.status_bar; + sheet_id = other.sheet_id; + hidden = other.hidden; + function = other.function; + function_group_id = other.function_group_id; + + shortcut_key = other.shortcut_key; + value = other.value; + + return *this; + } + + bool operator==(const defined_name &other) const + { + return name == other.name + && comment == other.comment + && custom_menu == other.custom_menu + && description == other.description + && help == other.help + && status_bar == other.status_bar + && sheet_id == other.sheet_id + && hidden == other.hidden + && function == other.function + && function_group_id == other.function_group_id + && shortcut_key == other.shortcut_key + && value == other.value; + } + + bool operator!=(const defined_name &other) const + { + return !(*this == other); + } + + // Implements (most of) CT_RevisionDefinedName, there's several "old" members in the spec but they're also ignored in other librarie + std::string name; // A string representing the name for this defined name. + optional comment; // A string representing a comment about the defined name. + optional custom_menu; // A string representing the new custom menu text + optional description; // A string representing the new description text for the defined name. + optional help; // A string representing the new help topic text. + optional status_bar; // A string representing the new status bar text. + optional sheet_id; // An integer representing the id of the sheet to which this defined name belongs. This shall be used local defined names only. 0 indexed indexed. + optional hidden; // A Boolean value indicating whether the named range is now hidden. + optional function; // A Boolean value indicating that the defined name refers to a function. True if the defined name is a function, false otherwise. + optional function_group_id;// Represents the new function group id. + optional shortcut_key; // Represents the new keyboard shortcut. This is unsigned byte in the spec, but openpyxl uses string so let's try that + std::string value; // The actual value of the name, ie "='Sheet1'!A1" + + }; } // namespace detail diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp index dc50106cb..1aa6a6d8c 100644 --- a/source/detail/serialization/xlsx_consumer.cpp +++ b/source/detail/serialization/xlsx_consumer.cpp @@ -534,7 +534,7 @@ std::string xlsx_consumer::read_worksheet_begin(const std::string &rel_id) expect_start_element(qn("spreadsheetml", "worksheet"), xml::content::complex); // CT_Worksheet skip_attributes({qn("mc", "Ignorable")}); - read_defined_names(ws, defined_names_); + read_defined_names(ws, ws.d_->defined_names_); while (in_element(qn("spreadsheetml", "worksheet"))) { @@ -2082,16 +2082,61 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_ defined_name name; name.name = parser().attribute("name"); - name.sheet_id = parser().attribute("localSheetId"); - name.hidden = false; + + if (parser().attribute_present("comment")) + { + name.comment = parser().attribute("comment"); + } + + if (parser().attribute_present("customMenu")) + { + name.custom_menu = parser().attribute("customMenu"); + } + + if (parser().attribute_present("description")) + { + name.description = parser().attribute("description"); + } + + if (parser().attribute_present("help")) + { + name.help = parser().attribute("help"); + } + + if (parser().attribute_present("statusBar")) + { + name.status_bar = parser().attribute("statusBar"); + } + + if (parser().attribute_present("localSheetId")) + { + name.sheet_id = parser().attribute("localSheetId"); + } + if (parser().attribute_present("hidden")) { name.hidden = is_true(parser().attribute("hidden")); } + + if (parser().attribute_present("function")) + { + name.function = is_true(parser().attribute("function")); + } + + if (parser().attribute_present("functionGroupId")) + { + name.function_group_id = parser().attribute("functionGroupId"); + } + + if (parser().attribute_present("shortcutKey")) + { + name.shortcut_key = parser().attribute("shortcutKey"); + } + parser().attribute_map(); // skip remaining attributes name.value = read_text(); - defined_names_.push_back(name); - + target_.d_->defined_names_.push_back(name); + expect_end_element(qn("spreadsheetml", "definedName")); } } @@ -2195,6 +2240,7 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_ } } + std::vector workbook_names; for (auto worksheet_rel : manifest().relationships(workbook_path, relationship_type::worksheet)) { auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(), @@ -2203,7 +2249,7 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_ return p.second == worksheet_rel.id(); })->first; - auto id = sheet_title_id_map_[title]; + auto id = sheet_title_id_map_[title]; // 1-indexed auto index = sheet_title_index_map_[title]; auto insertion_iter = target_.d_->worksheets_.begin(); @@ -2215,11 +2261,34 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_ current_worksheet_ = &*target_.d_->worksheets_.emplace(insertion_iter, &target_, id, title); + // If there's any defined names that are worksheet specific, move them here. + for (std::size_t i = 0; i < target_.d_->defined_names_.size(); i++) + { + const auto &name = target_.d_->defined_names_[i]; + if (name.sheet_id.is_set()) + { + const auto target_id = name.sheet_id.get(); + if (target_id == index) + { + // It's a match, remove it from the workbook and add it to the sheet + current_worksheet_->defined_names_.push_back(name); + } + } + else + { + // Name is global and belongs to the workbook, if i'ts not already added + if (std::find(workbook_names.begin(), workbook_names.end(), name) == workbook_names.end()) + workbook_names.push_back(name); + } + } + if (!streaming_) { read_part({workbook_rel, worksheet_rel}); } } + // Update the workbook with the new defined names + target_.d_->defined_names_ = workbook_names; } // Write Workbook Relationship Target Parts diff --git a/source/detail/serialization/xlsx_producer.cpp b/source/detail/serialization/xlsx_producer.cpp index 6f6e26ccc..06051958f 100644 --- a/source/detail/serialization/xlsx_producer.cpp +++ b/source/detail/serialization/xlsx_producer.cpp @@ -435,6 +435,9 @@ void xlsx_producer::write_workbook(const relationship &rel) std::size_t num_visible = 0; std::vector defined_names; + defined_names = source_.d_->defined_names_; + std::size_t sheet_id = 1; + for (auto ws : source_) { if (!ws.has_page_setup() || ws.page_setup().sheet_state() == sheet_state::visible) @@ -444,30 +447,35 @@ void xlsx_producer::write_workbook(const relationship &rel) auto title_ref = "'" + ws.title() + "'!"; + bool added_auto_filter = false; + bool added_print_area = false; + bool added_print_titles = false; if (ws.has_auto_filter()) { defined_name name; - name.sheet_id = ws.id(); + name.sheet_id = sheet_id; name.name = "_xlnm._FilterDatabase"; name.hidden = true; name.value = title_ref + range_reference::make_absolute(ws.auto_filter()).to_string(); defined_names.push_back(name); + added_auto_filter = true; } if (ws.has_print_area()) { defined_name name; - name.sheet_id = ws.id(); + name.sheet_id = sheet_id; name.name = "_xlnm.Print_Area"; name.hidden = false; name.value = title_ref + range_reference::make_absolute(ws.print_area()).to_string(); defined_names.push_back(name); + added_print_area = true; } if (ws.has_print_titles()) { defined_name name; - name.sheet_id = ws.id(); + name.sheet_id = sheet_id; name.name = "_xlnm.Print_Titles"; name.hidden = false; @@ -489,7 +497,22 @@ void xlsx_producer::write_workbook(const relationship &rel) } defined_names.push_back(name); + added_print_titles = true; + } + // Add any sheet defined names to the vector + for (auto &sheet_defined_name : ws.d_->defined_names_) + { + sheet_defined_name.sheet_id = sheet_id; + if (sheet_defined_name.name == "_xlnm._FilterDatabase" && !added_auto_filter) + defined_names.push_back(sheet_defined_name); + else if (sheet_defined_name.name == "_xlnm.Print_Area" && !added_print_area) + defined_names.push_back(sheet_defined_name); + else if (sheet_defined_name.name == "_xlnm.Print_Titles" && !added_print_titles) + defined_names.push_back(sheet_defined_name); + else if (!added_auto_filter && !added_print_area && !added_print_titles) + defined_names.push_back(sheet_defined_name); } + sheet_id++; } if (num_visible == 0) @@ -664,11 +687,66 @@ void xlsx_producer::write_workbook(const relationship &rel) { write_start_element(xmlns, "definedName"); write_attribute("name", name.name); - if (name.hidden) + + if (name.comment.is_set()) { - write_attribute("hidden", write_bool(true)); + write_attribute("comment", name.comment.get()); } - write_attribute("localSheetId", std::to_string(name.sheet_id - 1)); // 0-indexed for some reason + + if (name.custom_menu.is_set()) + { + write_attribute("customMenu", name.custom_menu.get()); + } + + if (name.description.is_set()) + { + write_attribute("description", name.description.get()); + } + + if (name.help.is_set()) + { + write_attribute("help", name.help.get()); + } + + if (name.status_bar.is_set()) + { + write_attribute("statusBar", name.status_bar.get()); + } + + if (name.sheet_id.is_set()) + { + write_attribute("localSheetId", std::to_string(name.sheet_id.get() - 1)); // Don't think this is meant to require subtracting 1? + } + + if (name.hidden.is_set()) + { + const auto hidden_state = name.hidden.get(); + if (hidden_state) + { + write_attribute("hidden", write_bool(true)); + } + } + + if (name.function.is_set()) + { + const auto function_state = name.function.get(); + if (function_state) + { + write_attribute("function", write_bool(true)); + } + } + + if (name.function_group_id.is_set()) + { + const auto function_group_id = name.function_group_id.get(); + write_attribute("functionGroupId", std::to_string(function_group_id)); + } + + if (name.shortcut_key.is_set()) + { + write_attribute("shortcutKey", name.shortcut_key.get()); + } + write_characters(name.value); write_end_element(xmlns, "definedName"); } diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index dce9d3bd0..6bf067494 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include namespace { @@ -1713,4 +1714,50 @@ void workbook::reorder_relationships() } } +void workbook::add_defined_name(detail::defined_name name) +{ + d_->defined_names_.push_back(name); +} + +std::vector workbook::get_defined_names() const +{ + return d_->defined_names_; +} + +detail::defined_name &workbook::get_defined_name(const std::size_t index) +{ + return d_->defined_names_[index]; +} + +detail::defined_name &workbook::get_defined_name(const std::string &name) +{ + // Only return the first matching + for (auto &defined_name : d_->defined_names_) + if (defined_name.name == name) + return defined_name; + throw key_not_found(); +} + +void workbook::remove_defined_name(const std::size_t index) +{ + d_->defined_names_.erase(d_->defined_names_.begin() + index); +} + +void workbook::remove_defined_name(const std::string &name) +{ + // Only remove first matching + std::size_t offending_index = 0; + std::size_t index = 0; + for (auto &defined_name : d_->defined_names_) + { + if (defined_name.name == name) + { + offending_index = index; + break; + } + index++; + } + if (d_->defined_names_.size() > 0) + remove_defined_name(offending_index); +} } // namespace xlnt diff --git a/source/worksheet/worksheet.cpp b/source/worksheet/worksheet.cpp index bd64ac37d..9b3829a79 100644 --- a/source/worksheet/worksheet.cpp +++ b/source/worksheet/worksheet.cpp @@ -1352,4 +1352,51 @@ bool worksheet::is_empty() const return d_->cell_map_.empty(); } +void worksheet::add_defined_name(detail::defined_name name) +{ + d_->defined_names_.push_back(name); +} + +std::vector worksheet::get_defined_names() const +{ + return d_->defined_names_; +} + +detail::defined_name &worksheet::get_defined_name(const std::size_t index) +{ + return d_->defined_names_[index]; +} + +detail::defined_name &worksheet::get_defined_name(const std::string &name) +{ + // Only return the first matching + for (auto &defined_name : d_->defined_names_) + if (defined_name.name == name) + return defined_name; + throw key_not_found(); +} + +void worksheet::remove_defined_name(const std::size_t index) +{ + d_->defined_names_.erase(d_->defined_names_.begin() + index); +} + +void worksheet::remove_defined_name(const std::string &name) +{ + // Only remove first matching + std::size_t offending_index = 0; + std::size_t index = 0; + for (auto &defined_name : d_->defined_names_) + { + if (defined_name.name == name) + { + offending_index = index; + break; + } + index++; + } + if (d_->defined_names_.size() > 0) + remove_defined_name(offending_index); +} + } // namespace xlnt diff --git a/tests/data/19_defined_names.xlsx b/tests/data/19_defined_names.xlsx index 4c430ba35..a1708d863 100644 Binary files a/tests/data/19_defined_names.xlsx and b/tests/data/19_defined_names.xlsx differ diff --git a/tests/workbook/serialization_test_suite.cpp b/tests/workbook/serialization_test_suite.cpp index ca6383a18..8fea0ede2 100644 --- a/tests/workbook/serialization_test_suite.cpp +++ b/tests/workbook/serialization_test_suite.cpp @@ -73,6 +73,7 @@ class serialization_test_suite : public test_suite register_test(test_Issue503_external_link_load); register_test(test_formatting); register_test(test_active_sheet); + register_test(test_named_range); } bool workbook_matches_file(xlnt::workbook &wb, const xlnt::path &file) @@ -808,6 +809,11 @@ class serialization_test_suite : public test_suite wb.load(path_helper::test_file("20_active_sheet.xlsx")); xlnt_assert_equals(wb.active_sheet(), wb[2]); } + + void test_named_range() + { + xlnt_assert(round_trip_matches_rw(path_helper::test_file("19_defined_names.xlsx"))); + } }; static serialization_test_suite x; diff --git a/tests/workbook/workbook_test_suite.cpp b/tests/workbook/workbook_test_suite.cpp index 09e37660a..8dab88ac9 100644 --- a/tests/workbook/workbook_test_suite.cpp +++ b/tests/workbook/workbook_test_suite.cpp @@ -36,6 +36,7 @@ #include #include #include +#include class workbook_test_suite : public test_suite { @@ -60,6 +61,9 @@ class workbook_test_suite : public test_suite register_test(test_add_named_range); register_test(test_get_named_range); register_test(test_remove_named_range); + register_test(test_add_defined_name); + register_test(test_modify_defined_name); + register_test(test_remove_defined_name); register_test(test_post_increment_iterator); register_test(test_copy_iterator); register_test(test_manifest); @@ -342,6 +346,63 @@ class workbook_test_suite : public test_suite xlnt_assert_throws(wb.remove_named_range("test_nr2"), std::runtime_error); } + void test_add_defined_name() + { + xlnt::workbook wb; + auto new_sheet = wb.create_sheet(); + + xlnt::detail::defined_name name; + const std::string dname = "Workbook Defined Name"; + const std::string dcomment = "This should only exist on a workbook"; + name.name = dname; + name.comment = dcomment; + name.value = "='Sheet1'!A1"; + wb.add_defined_name(name); + + xlnt_assert(wb.get_defined_names().size() == 1); + } + + void test_modify_defined_name() + { + xlnt::workbook wb; + auto new_sheet = wb.create_sheet(); + + xlnt::detail::defined_name name; + const std::string dname = "Workbook Defined Name"; + const std::string dcomment = "This should only exist on a workbook"; + name.name = dname; + name.comment = dcomment; + name.value = "='Sheet1'!A1"; + wb.add_defined_name(name); + + xlnt_assert(wb.get_defined_name(0).name == dname); + xlnt_assert(wb.get_defined_name(dname).comment == dcomment); + + wb.get_defined_name(0).hidden = true; + xlnt_assert(wb.get_defined_name(0).hidden == true); + + xlnt_assert_throws(wb.get_defined_name("Doesn't exist"), xlnt::key_not_found); + } + + void test_remove_defined_name() + { + xlnt::workbook wb; + auto new_sheet = wb.create_sheet(); + + xlnt::detail::defined_name name; + const std::string dname = "Workbook Defined Name"; + const std::string dcomment = "This should only exist on a workbook"; + name.name = dname; + name.comment = dcomment; + name.value = "='Sheet1'!A1"; + wb.add_defined_name(name); + + xlnt_assert(wb.get_defined_names().size() == 1); + wb.remove_defined_name(dname); + + xlnt_assert(wb.get_defined_names().size() == 0); + } + void test_post_increment_iterator() { xlnt::workbook wb; diff --git a/tests/worksheet/worksheet_test_suite.cpp b/tests/worksheet/worksheet_test_suite.cpp index 9c1097a04..696dd3c48 100644 --- a/tests/worksheet/worksheet_test_suite.cpp +++ b/tests/worksheet/worksheet_test_suite.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include class worksheet_test_suite : public test_suite @@ -111,6 +112,9 @@ class worksheet_test_suite : public test_suite register_test(test_hidden_sheet); register_test(test_xlsm_read_write); register_test(test_issue_484); + register_test(test_add_defined_name); + register_test(test_modify_defined_name); + register_test(test_remove_defined_name); } void test_new_worksheet() @@ -1674,6 +1678,69 @@ class worksheet_test_suite : public test_suite xlnt_assert_equals("B12:B12", ws.columns(true).reference()); xlnt_assert_equals("A1:B12", ws.columns(false).reference()); } + + + void test_add_defined_name() + { + xlnt::workbook wb; + auto ws = wb.create_sheet(); + + xlnt::detail::defined_name name; + const std::string dname = "Worksheet Defined Name"; + const std::string dcomment = "This should only exist on a Worksheet"; + name.name = dname; + name.comment = dcomment; + name.value = "='Sheet1'!A1"; + ws.add_defined_name(name); + + xlnt_assert(ws.get_defined_names().size() == 1); + ws = wb.create_sheet(); + xlnt_assert(ws.get_defined_names().size() == 0); + } + + void test_modify_defined_name() + { + xlnt::workbook wb; + auto ws = wb.create_sheet(); + + xlnt::detail::defined_name name; + const std::string dname = "Worksheet Defined Name"; + const std::string dcomment = "This should only exist on a Worksheet"; + name.name = dname; + name.comment = dcomment; + name.value = "='Sheet1'!A1"; + ws.add_defined_name(name); + + xlnt_assert(ws.get_defined_name(0).name == dname); + xlnt_assert(ws.get_defined_name(dname).comment == dcomment); + + ws.get_defined_name(0).hidden = true; + xlnt_assert(ws.get_defined_name(0).hidden == true); + + xlnt_assert_throws(ws.get_defined_name("Doesn't exist"), xlnt::key_not_found); + + ws = wb.create_sheet(); + xlnt_assert_throws(ws.get_defined_name(dname), xlnt::key_not_found); + } + + void test_remove_defined_name() + { + xlnt::workbook wb; + auto ws = wb.create_sheet(); + + xlnt::detail::defined_name name; + const std::string dname = "Worksheet Defined Name"; + const std::string dcomment = "This should only exist on a Worksheet"; + name.name = dname; + name.comment = dcomment; + name.value = "='Sheet1'!A1"; + ws.add_defined_name(name); + + xlnt_assert(ws.get_defined_names().size() == 1); + ws.remove_defined_name(dname); + + xlnt_assert(ws.get_defined_names().size() == 0); + } }; static worksheet_test_suite x;