From 4001a47ec0eb47855b63e956827e46be73d288e0 Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Tue, 6 Oct 2015 10:32:52 -0400 Subject: [PATCH] fix relative paths in relationships on round-trips. I really need to clean up relationship code --- include/xlnt/workbook/workbook.hpp | 3 ++ include/xlnt/writer/writer.hpp | 2 +- source/workbook.cpp | 73 +++++++++++++++++++++--------- source/writer.cpp | 17 +++++-- 4 files changed, 68 insertions(+), 27 deletions(-) diff --git a/include/xlnt/workbook/workbook.hpp b/include/xlnt/workbook/workbook.hpp index cecb0730..c4c03c38 100644 --- a/include/xlnt/workbook/workbook.hpp +++ b/include/xlnt/workbook/workbook.hpp @@ -115,6 +115,7 @@ public: worksheet create_sheet(std::size_t index); worksheet create_sheet(const std::string &title); worksheet create_sheet(std::size_t index, const std::string &title); + worksheet create_sheet(const std::string &title, const relationship &rel); //add void add_sheet(worksheet worksheet); @@ -172,6 +173,8 @@ public: std::vector get_relationships() const; private: + static std::size_t index_from_ws_filename(const std::string &ws_filename); + friend class worksheet; std::shared_ptr d_; }; diff --git a/include/xlnt/writer/writer.hpp b/include/xlnt/writer/writer.hpp index c7c30e78..c4692d72 100644 --- a/include/xlnt/writer/writer.hpp +++ b/include/xlnt/writer/writer.hpp @@ -61,7 +61,7 @@ public: static std::string write_worksheet_rels(worksheet ws); private: - static std::string write_relationships(const std::vector &relationships); + static std::string write_relationships(const std::vector &relationships, const std::string &dir = ""); }; } // namespace xlnt diff --git a/source/workbook.cpp b/source/workbook.cpp index f880d8f2..a528e9dd 100644 --- a/source/workbook.cpp +++ b/source/workbook.cpp @@ -180,8 +180,9 @@ worksheet workbook::create_sheet() } d_->worksheets_.push_back(detail::worksheet_impl(this, title)); - create_relationship("rId" + std::to_string(d_->relationships_.size() + 1), "worksheets/sheet" + std::to_string(d_->worksheets_.size()) + ".xml", relationship::type::worksheet); - return worksheet(&d_->worksheets_.back()); + create_relationship("rId" + std::to_string(d_->relationships_.size() + 1), "xl/worksheets/sheet" + std::to_string(d_->worksheets_.size()) + ".xml", relationship::type::worksheet); + + return worksheet(&d_->worksheets_.back()); } void workbook::add_sheet(xlnt::worksheet worksheet) @@ -311,7 +312,7 @@ bool workbook::load(const std::string &filename) for(auto relationship : workbook_relationships) { - create_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type()); + create_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type()); } pugi::xml_document doc; @@ -346,9 +347,18 @@ bool workbook::load(const std::string &filename) for(auto sheet_node : sheets_node.children("sheet")) { - std::string relation_id = sheet_node.attribute("r:id").as_string(); - auto ws = create_sheet(sheet_node.attribute("name").as_string()); - auto sheet_filename = get_relationship(relation_id).get_target_uri(); + std::string rel_id = sheet_node.attribute("r:id").as_string(); + auto rel = std::find_if(d_->relationships_.begin(), d_->relationships_.end(), + [&](relationship &rel) { return rel.get_id() == rel_id; }); + + if (rel == d_->relationships_.end()) + { + throw std::runtime_error("relationship not found"); + } + + auto ws = create_sheet(sheet_node.attribute("name").as_string(), *rel); + auto sheet_filename = rel->get_target_uri(); + xlnt::reader::read_worksheet(ws, f.read(sheet_filename).c_str(), shared_strings, number_format_ids); } @@ -400,14 +410,29 @@ worksheet workbook::create_sheet(std::size_t index) { create_sheet(); - if(index != d_->worksheets_.size()) - { - std::swap(d_->worksheets_[index], d_->worksheets_.back()); - } + if (index != d_->worksheets_.size() - 1) + { + std::swap(d_->worksheets_.back(), d_->worksheets_[index]); + d_->worksheets_.pop_back(); + } return worksheet(&d_->worksheets_[index]); } +worksheet workbook::create_sheet(const std::string &title, const relationship &rel) +{ + d_->worksheets_.push_back(detail::worksheet_impl(this, title)); + + auto index = index_from_ws_filename(rel.get_target_uri()); + if (index != d_->worksheets_.size() - 1) + { + std::swap(d_->worksheets_.back(), d_->worksheets_[index]); + d_->worksheets_.pop_back(); + } + + return worksheet(&d_->worksheets_[index]); +} + worksheet workbook::create_sheet(std::size_t index, const std::string &title) { auto ws = create_sheet(index); @@ -554,19 +579,9 @@ bool workbook::save(const std::string &filename) { if(relationship.get_type() == relationship::type::worksheet) { - std::string sheet_index_string = relationship.get_target_uri(); - sheet_index_string = sheet_index_string.substr(0, sheet_index_string.find('.')); - sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/')); - auto iter = sheet_index_string.end(); - iter--; - while (isdigit(*iter)) iter--; - auto first_digit = iter - sheet_index_string.begin(); - sheet_index_string = sheet_index_string.substr(first_digit + 1); - auto sheet_index = std::stoi(sheet_index_string) - 1; - + auto sheet_index = index_from_ws_filename(relationship.get_target_uri()); auto ws = get_sheet_by_index(sheet_index); - std::string sheet_uri = "xl/" + relationship.get_target_uri(); - f.writestr(sheet_uri, writer::write_worksheet(ws, shared_strings)); + f.writestr(relationship.get_target_uri(), writer::write_worksheet(ws, shared_strings)); } } @@ -665,4 +680,18 @@ void workbook::set_data_only(bool data_only) d_->data_only_ = data_only; } +std::size_t workbook::index_from_ws_filename(const std::string &ws_filename) +{ + std::string sheet_index_string(ws_filename); + sheet_index_string = sheet_index_string.substr(0, sheet_index_string.find('.')); + sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/')); + auto iter = sheet_index_string.end(); + iter--; + while (isdigit(*iter)) iter--; + auto first_digit = iter - sheet_index_string.begin(); + sheet_index_string = sheet_index_string.substr(first_digit + 1); + auto sheet_index = std::stoi(sheet_index_string) - 1; + return sheet_index; +} + } diff --git a/source/writer.cpp b/source/writer.cpp index ac3b78dc..c52d22fe 100644 --- a/source/writer.cpp +++ b/source/writer.cpp @@ -123,7 +123,7 @@ std::string writer::write_properties_app(const workbook &wb) std::string writer::write_workbook_rels(const workbook &wb) { - return write_relationships(wb.get_relationships()); + return write_relationships(wb.get_relationships(), "xl/"); } std::string writer::write_worksheet_rels(worksheet ws) @@ -131,7 +131,6 @@ std::string writer::write_worksheet_rels(worksheet ws) return write_relationships(ws.get_relationships()); } - std::string writer::write_workbook(const workbook &wb) { pugi::xml_document doc; @@ -571,18 +570,28 @@ std::string xlnt::writer::write_root_rels() return write_relationships(relationships); } -std::string writer::write_relationships(const std::vector &relationships) +std::string writer::write_relationships(const std::vector &relationships, const std::string &dir) { pugi::xml_document doc; + auto root_node = doc.append_child("Relationships"); root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("relationships").c_str()); for(auto relationship : relationships) { + auto target = relationship.get_target_uri(); + + if (dir != "" && target.substr(0, dir.size()) == dir) + { + target = target.substr(dir.size()); + } + auto app_props_node = root_node.append_child("Relationship"); + app_props_node.append_attribute("Id").set_value(relationship.get_id().c_str()); - app_props_node.append_attribute("Target").set_value(relationship.get_target_uri().c_str()); + app_props_node.append_attribute("Target").set_value(target.c_str()); app_props_node.append_attribute("Type").set_value(relationship.get_type_string().c_str()); + if(relationship.get_target_mode() == target_mode::external) { app_props_node.append_attribute("TargetMode").set_value("External");