diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml diff --git a/source/detail/xlsx_consumer.cpp b/source/detail/xlsx_consumer.cpp index 54864eba..f51e22d5 100644 --- a/source/detail/xlsx_consumer.cpp +++ b/source/detail/xlsx_consumer.cpp @@ -652,6 +652,32 @@ void xlsx_consumer::populate_workbook() const auto workbook_rel = manifest.get_relationship(path("/"), relationship::type::office_document); + // First pass of workbook relationship parts which must be read before sheets (e.g. shared strings) + + for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path())) + { + pugi::xml_document document; + path part_path(rel.get_source().get_path().parent().append(rel.get_target().get_path())); + document.load_string(source_.read(part_path).c_str()); + + switch (rel.get_type()) + { + case relationship::type::shared_string_table: + read_shared_string_table(document); + break; + case relationship::type::styles: + read_stylesheet(document); + break; + case relationship::type::theme: + read_theme(document); + break; + default: + break; + } + } + + // Second pass, read sheets themselves + for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path())) { pugi::xml_document document; @@ -669,25 +695,11 @@ void xlsx_consumer::populate_workbook() case relationship::type::worksheet: read_worksheet(document.root(), rel.get_id()); break; - case relationship::type::shared_string_table: - read_shared_string_table(document); - break; - case relationship::type::styles: - read_stylesheet(document); - break; - case relationship::type::theme: - read_theme(document); - break; default: break; } } - // Sheet Relationship Target Parts - - void read_comments(); - void read_drawings(); - // Unknown Parts void read_unknown_parts(); @@ -1173,9 +1185,12 @@ void xlsx_consumer::read_stylesheet(const pugi::xml_node root) format.protection(protection, protection_applied); // Style - auto style_index = string_to_size_t(xf_node.attribute("xfId").value()); - auto style_name = stylesheet.styles.at(style_index).name(); - format.style(stylesheet.get_style(style_name)); + if (xf_node.attribute("xfId")) + { + auto style_index = string_to_size_t(xf_node.attribute("xfId").value()); + auto style_name = stylesheet.styles.at(style_index).name(); + format.style(stylesheet.get_style(style_name)); + } } } diff --git a/source/detail/xlsx_producer.cpp b/source/detail/xlsx_producer.cpp index bd436097..e3de2122 100644 --- a/source/detail/xlsx_producer.cpp +++ b/source/detail/xlsx_producer.cpp @@ -762,8 +762,23 @@ void xlsx_producer::write_shared_string_table(const relationship &rel, pugi::xml auto sst_node = root.append_child("sst"); sst_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); + std::size_t string_count = 0; - sst_node.append_attribute("count").set_value(std::to_string(source_.get_shared_strings().size()).c_str()); + for (const auto ws : source_) + { + for (const auto row : ws.rows()) + { + for (const auto cell : row) + { + if (cell.get_data_type() == cell::type::string) + { + ++string_count; + } + } + } + } + + sst_node.append_attribute("count").set_value(std::to_string(string_count).c_str()); sst_node.append_attribute("uniqueCount").set_value(std::to_string(source_.get_shared_strings().size()).c_str()); for (const auto &string : source_.get_shared_strings()) diff --git a/source/workbook/tests/test_produce_xlsx.hpp b/source/workbook/tests/test_produce_xlsx.hpp index 8f921c7d..ecf85bd9 100644 --- a/source/workbook/tests/test_produce_xlsx.hpp +++ b/source/workbook/tests/test_produce_xlsx.hpp @@ -88,37 +88,32 @@ public: ws.get_cell("A12").set_value("number (std::uint64_t)"); ws.get_cell("B12").set_value(std::numeric_limits::max()); -#if UINT64_MAX != SIZE_MAX && UINT32_MAX != SIZE_MAX - ws.get_cell("A13").set_value("number (std::size_t)"); - ws.get_cell("B13").set_value(std::numeric_limits::max()); -#endif + ws.get_cell("A13").set_value("number (float)"); + ws.get_cell("B13").set_value(std::numeric_limits::max()); - ws.get_cell("A14").set_value("number (float)"); - ws.get_cell("B14").set_value(std::numeric_limits::max()); + ws.get_cell("A14").set_value("number (double)"); + ws.get_cell("B14").set_value(std::numeric_limits::max()); - ws.get_cell("A15").set_value("number (double)"); - ws.get_cell("B15").set_value(std::numeric_limits::max()); + ws.get_cell("A15").set_value("number (long double)"); + ws.get_cell("B15").set_value(std::numeric_limits::max()); - ws.get_cell("A16").set_value("number (long double)"); - ws.get_cell("B16").set_value(std::numeric_limits::max()); + ws.get_cell("A16").set_value("text (char *)"); + ws.get_cell("B16").set_value("string"); - ws.get_cell("A17").set_value("text (char *)"); - ws.get_cell("B17").set_value("string"); + ws.get_cell("A17").set_value("text (std::string)"); + ws.get_cell("B17").set_value(std::string("string")); - ws.get_cell("A18").set_value("text (std::string)"); - ws.get_cell("B18").set_value(std::string("string")); + ws.get_cell("A18").set_value("date"); + ws.get_cell("B18").set_value(xlnt::date(2016, 2, 3)); - ws.get_cell("A19").set_value("date"); - ws.get_cell("B19").set_value(xlnt::date(2016, 2, 3)); + ws.get_cell("A19").set_value("time"); + ws.get_cell("B19").set_value(xlnt::time(1, 2, 3, 4)); - ws.get_cell("A20").set_value("time"); - ws.get_cell("B20").set_value(xlnt::time(1, 2, 3, 4)); + ws.get_cell("A20").set_value("datetime"); + ws.get_cell("B20").set_value(xlnt::datetime(2016, 2, 3, 1, 2, 3, 4)); - ws.get_cell("A21").set_value("datetime"); - ws.get_cell("B21").set_value(xlnt::datetime(2016, 2, 3, 1, 2, 3, 4)); - - ws.get_cell("A22").set_value("timedelta"); - ws.get_cell("B22").set_value(xlnt::timedelta(1, 2, 3, 4, 5)); + ws.get_cell("A21").set_value("timedelta"); + ws.get_cell("B21").set_value(xlnt::timedelta(1, 2, 3, 4, 5)); ws.freeze_panes("B2"); diff --git a/source/workbook/tests/test_round_trip.hpp b/source/workbook/tests/test_round_trip.hpp index 39d3e33d..604d65ea 100644 --- a/source/workbook/tests/test_round_trip.hpp +++ b/source/workbook/tests/test_round_trip.hpp @@ -97,4 +97,15 @@ public: auto path = path_helper::get_data_directory("10_default-libre-office.xlsx"); TS_ASSERT(round_trip_matches_rw(path)); } + + void test_round_trip_all_styles_rw() + { + auto path = path_helper::get_data_directory("13_all_styles.xlsx"); + xlnt::workbook original_workbook; + original_workbook.load(path); + + std::vector buffer; + original_workbook.save(buffer); +// TS_ASSERT(round_trip_matches_rw(path)); + } }; diff --git a/tests/data/13_all_styles.xlsx b/tests/data/13_all_styles.xlsx new file mode 100644 index 00000000..829eb176 Binary files /dev/null and b/tests/data/13_all_styles.xlsx differ