re-write workbook::reorder_relationships

Issue #279
This commit is contained in:
Crzyrndm 2018-07-10 17:29:26 +12:00
parent c0a90ccb7f
commit 322490b397

View File

@ -28,16 +28,6 @@
#include <functional>
#include <set>
#include <detail/constants.hpp>
#include <detail/default_case.hpp>
#include <detail/implementations/cell_impl.hpp>
#include <detail/implementations/workbook_impl.hpp>
#include <detail/implementations/worksheet_impl.hpp>
#include <detail/serialization/excel_thumbnail.hpp>
#include <detail/serialization/vector_streambuf.hpp>
#include <detail/serialization/open_stream.hpp>
#include <detail/serialization/xlsx_consumer.hpp>
#include <detail/serialization/xlsx_producer.hpp>
#include <xlnt/cell/cell.hpp>
#include <xlnt/packaging/manifest.hpp>
#include <xlnt/packaging/relationship.hpp>
@ -61,6 +51,16 @@
#include <xlnt/worksheet/header_footer.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <detail/constants.hpp>
#include <detail/default_case.hpp>
#include <detail/implementations/cell_impl.hpp>
#include <detail/implementations/workbook_impl.hpp>
#include <detail/implementations/worksheet_impl.hpp>
#include <detail/serialization/excel_thumbnail.hpp>
#include <detail/serialization/open_stream.hpp>
#include <detail/serialization/vector_streambuf.hpp>
#include <detail/serialization/xlsx_consumer.hpp>
#include <detail/serialization/xlsx_producer.hpp>
namespace {
@ -1025,7 +1025,8 @@ void workbook::remove_sheet(worksheet ws)
for (auto &title_rel_id_pair : d_->sheet_title_rel_id_map_)
{
title_rel_id_pair.second = rel_id_map.count(title_rel_id_pair.second) > 0
? rel_id_map[title_rel_id_pair.second] : title_rel_id_pair.second;
? rel_id_map[title_rel_id_pair.second]
: title_rel_id_pair.second;
}
update_sheet_properties();
@ -1563,69 +1564,69 @@ void workbook::update_sheet_properties()
}
}
namespace {
// true if a sheet index is != worksheet relationship index
bool needs_reorder(const std::unordered_map<std::string, std::string> &title_to_rels,
const std::vector<std::string> &titles,
std::vector<std::string> &relation_ids)
{
bool all_match = true;
for (std::size_t title_index = 0; title_index < titles.size(); ++title_index)
{
const auto &rel = title_to_rels.at(titles[title_index]);
relation_ids.push_back(rel);
const auto expected_rel_id = "rId" + std::to_string(title_index + 1);
if (rel != expected_rel_id)
{
all_match = false;
}
}
return !all_match; // if all are as expected, reorder not required
};
} // namespace
void workbook::reorder_relationships()
{
const auto wb_rel = manifest().relationship(path("/"), relationship_type::office_document);
const auto wb_path = wb_rel.target().path();
const auto relationships = manifest().relationships(wb_path);
std::unordered_map<std::string, relationship> rel_map;
const auto titles = sheet_titles();
const auto title_rel_id_map = d_->sheet_title_rel_id_map_;
bool needs_reorder = false;
for (const auto &rel : relationships)
{
rel_map[rel.id()] = rel;
if (rel.type() == relationship_type::worksheet)
{
for (auto title_index = std::size_t(0); title_index < titles.size(); ++title_index)
{
const auto title = titles[title_index];
if (title_rel_id_map.at(title) == rel.id())
{
const auto expected_rel_id = "rId" + std::to_string(title_index + 1);
if (expected_rel_id != rel.id())
{
needs_reorder = true;
}
break;
}
}
}
}
if (!needs_reorder)
// the relation ID corresponding to the title at the same index is copied into here
std::vector<std::string> worksheet_rel_ids;
worksheet_rel_ids.reserve(titles.size());
if (!needs_reorder(d_->sheet_title_rel_id_map_, titles, worksheet_rel_ids))
{
return;
}
for (const auto &rel : relationships)
// copy of existing relations
const auto wb_rel = manifest().relationship(path("/"), relationship_type::office_document);
const auto wb_path = wb_rel.target().path();
auto rel_copy = manifest().relationships(wb_path);
// clear existing relations
for (const auto &rel : rel_copy)
{
manifest().unregister_relationship(uri(wb_path.string()), rel.id());
}
for (auto index = std::size_t(0); index < rel_map.size(); ++index)
// create new relations
std::size_t index = 0;
auto new_id = [&index]() { return "rId" + std::to_string(++index); }; // ids start from 1
// worksheets first
while (index < worksheet_rel_ids.size())
{
auto rel_id = "rId" + std::to_string(index + 1);
auto old_rel_id = std::string();
auto rel_it = std::find_if(rel_copy.begin(), rel_copy.end(),
[&](const relationship &rel) { return rel.id() == worksheet_rel_ids[index]; });
if (index < titles.size())
{
auto title = titles[index];
old_rel_id = title_rel_id_map.at(title);
d_->sheet_title_rel_id_map_[title] = rel_id;
} else {
old_rel_id = "rId" + std::to_string(index - titles.size() + 2);
std::string rel_id = new_id();
d_->sheet_title_rel_id_map_.at(titles[index - 1]) = rel_id; // update title -> relation mapping
manifest().register_relationship(relationship(rel_id, rel_it->type(),
rel_it->source(), rel_it->target(), rel_it->target_mode()));
}
auto old_rel = rel_map[old_rel_id];
auto new_rel = relationship(rel_id, old_rel.type(),
old_rel.source(), old_rel.target(), old_rel.target_mode());
manifest().register_relationship(new_rel);
// then all the other relations in the same order they started (just new indices)
for (const auto& old_rel : rel_copy)
{
if (old_rel.type() == relationship_type::worksheet)
{
continue;
}
manifest().register_relationship(relationship(new_id(), old_rel.type(),
old_rel.source(), old_rel.target(), old_rel.target_mode()));
}
}