From afbab819c432510772a089d154f551a53954a233 Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Mon, 2 Jan 2017 17:42:16 -0500 Subject: [PATCH] implement consumption of vt:lpwstr custom properties --- include/xlnt/workbook/workbook.hpp | 17 +++++++++++++++ source/detail/constants.cpp | 2 +- source/detail/custom_value_traits.cpp | 2 +- source/detail/xlsx_consumer.cpp | 24 ++++++++++++++++++++- source/workbook/tests/test_consume_xlsx.hpp | 8 +++++++ source/workbook/workbook.cpp | 24 +++++++++++++++++++++ 6 files changed, 74 insertions(+), 3 deletions(-) diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index c4d731be..4d6f5405 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -320,6 +320,23 @@ public: template void extended_property(const std::string &property_name, const T value); + /// + /// Returns true if the workbook has the custom property with the given name. + /// + bool has_custom_property(const std::string &property_name) const; + + /// + /// + /// + template + T custom_property(const std::string &property_name) const; + + /// + /// + /// + template + void custom_property(const std::string &property_name, const T value); + /// /// /// diff --git a/source/detail/constants.cpp b/source/detail/constants.cpp index af202f14..9c5964a7 100644 --- a/source/detail/constants.cpp +++ b/source/detail/constants.cpp @@ -118,7 +118,7 @@ const std::unordered_map &constants::namespaces() {"workbook", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}, {"core-properties", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"}, {"extended-properties", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"}, - {"custom-properties", "http://schemas.openxmlformats.org/officeDocument/2006/customProperties"}, + {"custom-properties", "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"}, {"encryption", "http://schemas.microsoft.com/office/2006/encryption"}, {"encryption-password", "http://schemas.microsoft.com/office/2006/keyEncryptor/password"}, diff --git a/source/detail/custom_value_traits.cpp b/source/detail/custom_value_traits.cpp index 97eebb93..bd92dc82 100644 --- a/source/detail/custom_value_traits.cpp +++ b/source/detail/custom_value_traits.cpp @@ -61,7 +61,7 @@ std::string to_string(relationship_type t) case relationship_type::unknown: return "unknown"; case relationship_type::custom_properties: - return "custom-properties"; + return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties"; case relationship_type::printer_settings: return "printer-settings"; case relationship_type::connections: diff --git a/source/detail/xlsx_consumer.cpp b/source/detail/xlsx_consumer.cpp index d925f01a..25feea5f 100644 --- a/source/detail/xlsx_consumer.cpp +++ b/source/detail/xlsx_consumer.cpp @@ -812,6 +812,8 @@ void xlsx_consumer::read_content_types() void xlsx_consumer::read_properties(const path &part, const xml::qname &root) { + static const auto xmlns_vt = constants::namespace_("vt"); + auto content_type = manifest().content_type(part); std::unordered_map properties; @@ -821,16 +823,36 @@ void xlsx_consumer::read_properties(const path &part, const xml::qname &root) { auto property_element = expect_start_element(xml::content::mixed); - if (property_element.name() != "Property") + if (property_element.name() != "property") { properties[property_element.name()] = read_text(); } + else + { + auto property_name = parser().attribute("name"); + auto variant_child_element = expect_start_element(xml::content::simple); + + if (variant_child_element == xml::qname(xmlns_vt, "lpwstr")) + { + properties[property_name] = read_text(); + } + + expect_end_element(variant_child_element); + } skip_remaining_content(property_element); expect_end_element(property_element); } expect_end_element(root); + + if (content_type == "application/vnd.openxmlformats-officedocument.custom-properties+xml") + { + for (const auto &prop : properties) + { + target_.custom_property(prop.first, prop.second); + } + } } void xlsx_consumer::read_office_document(const std::string &content_type) // CT_Workbook diff --git a/source/workbook/tests/test_consume_xlsx.hpp b/source/workbook/tests/test_consume_xlsx.hpp index af9c9d91..b6a4ba77 100644 --- a/source/workbook/tests/test_consume_xlsx.hpp +++ b/source/workbook/tests/test_consume_xlsx.hpp @@ -104,4 +104,12 @@ public: TS_ASSERT(ws.header_footer().has_footer(xlnt::header_footer::location::right)); TS_ASSERT_EQUALS(ws.header_footer().footer(xlnt::header_footer::location::right).plain_text(), "right footer"); } + + void test_read_custom_properties() + { + xlnt::workbook wb; + wb.load("data/21_custom_properties.xlsx"); + TS_ASSERT(wb.has_custom_property("Client")); + TS_ASSERT_EQUALS(wb.custom_property("Client"), "me!"); + } }; diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index cf46de88..c665ebc4 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -165,6 +165,30 @@ std::string workbook::extended_property(const std::string &property_name) const return d_->extended_properties_.at(property_name); } + +bool workbook::has_custom_property(const std::string &property_name) const +{ + return d_->custom_properties_.count(property_name) > 0; +} + +template <> +void workbook::custom_property(const std::string &property_name, const std::string value) +{ + d_->custom_properties_[property_name] = value; +} + +template <> +void workbook::custom_property(const std::string &property_name, const char *value) +{ + d_->custom_properties_[property_name] = value; +} + +template <> +std::string workbook::custom_property(const std::string &property_name) const +{ + return d_->custom_properties_.at(property_name); +} + workbook workbook::empty() { auto impl = new detail::workbook_impl();