shift relationship ids down by one after deleting one to maintain contiguity, fixes #104

This commit is contained in:
Thomas Fussell 2017-01-08 14:12:55 -05:00
parent e9c8116b0d
commit 44b11d342c
3 changed files with 44 additions and 6 deletions

View File

@ -102,9 +102,12 @@ public:
std::string register_relationship(const class relationship &rel); std::string register_relationship(const class relationship &rel);
/// <summary> /// <summary>
/// /// Delete the relationship with the given id from source part. Returns a mapping
/// of relationship IDs since IDs are shifted down. For example, if there are three
/// relationships for part a.xml like [rId1, rId2, rId3] and rId2 is deleted, the
/// resulting map would look like [rId3->rId2].
/// </summary> /// </summary>
void unregister_relationship(const uri &source, const std::string &rel_id); std::unordered_map<std::string, std::string> unregister_relationship(const uri &source, const std::string &rel_id);
// Content Types // Content Types

View File

@ -227,9 +227,38 @@ std::string manifest::register_relationship(const class relationship &rel)
return rel.id(); return rel.id();
} }
void manifest::unregister_relationship(const uri &source, const std::string &rel_id) std::unordered_map<std::string, std::string> manifest::unregister_relationship(const uri &source, const std::string &rel_id)
{ {
relationships_.at(source.path()).erase(rel_id); // This shouldn't happen, but just in case...
if (rel_id.substr(0, 3) != "rId" || rel_id.size() < 4)
{
throw xlnt::invalid_parameter();
}
std::unordered_map<std::string, std::string> id_map;
auto rel_index = static_cast<std::size_t>(std::stoull(rel_id.substr(3)));
auto &part_rels = relationships_.at(source.path());
for (auto i = rel_index; i <= part_rels.size() + 1; ++i)
{
auto old_id = "rId" + std::to_string(i);
// Don't re-add the relationship to be deleted
if (i > rel_index)
{
// Shift all relationships with IDs greater than the deleted one
// down by one (e.g. rId7->rId6).
auto new_id = "rId" + std::to_string(i - 1);
const auto &old_rel = part_rels.at(old_id);
register_relationship(xlnt::relationship(new_id, old_rel.type(),
old_rel.source(), old_rel.target(), old_rel.target_mode()));
id_map[old_id] = new_id;
}
part_rels.erase(old_id);
}
return id_map;
} }
bool manifest::has_default_type(const std::string &extension) const bool manifest::has_default_type(const std::string &extension) const

View File

@ -799,10 +799,16 @@ void workbook::remove_sheet(worksheet ws)
auto wb_rel = d_->manifest_.relationship(xlnt::path("/"), xlnt::relationship_type::office_document); auto wb_rel = d_->manifest_.relationship(xlnt::path("/"), xlnt::relationship_type::office_document);
auto ws_rel = d_->manifest_.relationship(wb_rel.target().path(), ws_rel_id); auto ws_rel = d_->manifest_.relationship(wb_rel.target().path(), ws_rel_id);
d_->manifest_.unregister_override_type(ws_rel.target().path()); d_->manifest_.unregister_override_type(ws_rel.target().path());
d_->manifest_.unregister_relationship(wb_rel.target(), ws_rel_id); auto rel_id_map = d_->manifest_.unregister_relationship(wb_rel.target(), ws_rel_id);
;
d_->sheet_title_rel_id_map_.erase(ws.title()); d_->sheet_title_rel_id_map_.erase(ws.title());
d_->worksheets_.erase(match_iter); d_->worksheets_.erase(match_iter);
// Shift sheet title->ID mappings down as a result of manifest::unregister_relationship above.
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;
}
} }
worksheet workbook::create_sheet(std::size_t index) worksheet workbook::create_sheet(std::size_t index)