Skip to content

Commit

Permalink
implement xlsx relations properly
Browse files Browse the repository at this point in the history
  • Loading branch information
andiwand committed Dec 24, 2023
1 parent a3f42cd commit 3cfdf8f
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 148 deletions.
2 changes: 2 additions & 0 deletions src/odr/internal/ooxml/ooxml_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ std::optional<std::string> read_border_node(pugi::xml_node);

std::string read_text_property(pugi::xml_node);

using Relations = std::unordered_map<std::string, std::string>;

std::unordered_map<std::string, std::string>
parse_relationships(const pugi::xml_document &relations);
std::unordered_map<std::string, std::string>
Expand Down
62 changes: 32 additions & 30 deletions src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <odr/exceptions.hpp>

#include <odr/internal/abstract/filesystem.hpp>
#include <odr/internal/ooxml/ooxml_util.hpp>
#include <odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.hpp>
#include <odr/internal/util/xml_util.hpp>

Expand All @@ -15,41 +14,46 @@ Document::Document(std::shared_ptr<abstract::ReadableFilesystem> filesystem)
: common::TemplateDocument<Element>(FileType::office_open_xml_workbook,
DocumentType::spreadsheet,
std::move(filesystem)) {
m_workbook_xml = util::xml::parse(*m_filesystem, "xl/workbook.xml");
m_styles_xml = util::xml::parse(*m_filesystem, "xl/styles.xml");
auto workbook_path = common::Path("xl/workbook.xml");
auto [workbook_xml, workbook_relations] = parse_xml_(workbook_path);
auto [styles_xml, _] = parse_xml_("xl/styles.xml");

for (const auto &relationships :
parse_relationships(*m_filesystem, "xl/workbook.xml")) {
auto sheet_path = common::Path("xl").join(relationships.second);
auto sheet_xml = util::xml::parse(*m_filesystem, sheet_path);
for (pugi::xml_node sheet_node :
workbook_xml.document_element().child("sheets").children("sheet")) {
const char *id = sheet_node.attribute("r:id").value();
common::Path sheet_path =
workbook_path.parent().join(workbook_relations.at(id));
auto [sheet_xml, sheet_relationships] = parse_xml_(sheet_path);

if (auto drawing = sheet_xml.document_element().child("drawing")) {
auto sheet_relationships = parse_relationships(*m_filesystem, sheet_path);
auto drawing_path =
common::Path("xl/worksheets")
.join(sheet_relationships.at(drawing.attribute("r:id").value()));
auto drawing_xml = util::xml::parse(*m_filesystem, drawing_path);

m_sheets[relationships.first].sheet_path = std::move(drawing_path);
m_sheets[relationships.first].drawing_xml = std::move(drawing_xml);
auto drawing_path = sheet_path.parent().join(
sheet_relationships.at(drawing.attribute("r:id").value()));
parse_xml_(drawing_path);
}

m_sheets[relationships.first].sheet_path = std::move(sheet_path);
m_sheets[relationships.first].sheet_xml = std::move(sheet_xml);
}

if (m_filesystem->exists("xl/sharedStrings.xml")) {
m_shared_strings_xml =
util::xml::parse(*m_filesystem, "xl/sharedStrings.xml");
}
auto [shared_strings_xml, _] = parse_xml_("xl/sharedStrings.xml");

for (auto shared_string : m_shared_strings_xml.document_element()) {
m_shared_strings.push_back(shared_string);
for (auto shared_string : shared_strings_xml.document_element()) {
m_shared_strings.push_back(shared_string);
}
}

m_style_registry = StyleRegistry(m_styles_xml.document_element());
m_style_registry = StyleRegistry(styles_xml.document_element());

m_root_element = parse_tree(*this, m_workbook_xml.document_element());
m_root_element = parse_tree(*this, workbook_xml.document_element(),
workbook_path, workbook_relations);
}

std::pair<pugi::xml_document &, Relations &>
Document::parse_xml_(const common::Path &path) {
pugi::xml_document document = util::xml::parse(*m_filesystem, path);
Relations relations = parse_relationships(*m_filesystem, path);

auto result = m_xml.emplace(
path, std::make_pair(std::move(document), std::move(relations)));
return {result.first->second.first, result.first->second.second};
}

bool Document::is_editable() const noexcept { return false; }
Expand All @@ -67,11 +71,9 @@ void Document::save(const common::Path & /*path*/,
throw UnsupportedOperation();
}

pugi::xml_node Document::get_sheet_root(const std::string &ref) const {
if (auto it = m_sheets.find(ref); it != std::end(m_sheets)) {
return it->second.sheet_xml.document_element();
}
return {};
std::pair<const pugi::xml_document &, const Relations &>
Document::get_xml(const common::Path &path) const {
return m_xml.at(path);
}

pugi::xml_node Document::get_shared_string(std::size_t index) const {
Expand Down
21 changes: 8 additions & 13 deletions src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <string>
#include <unordered_map>

#include "odr/internal/ooxml/ooxml_util.hpp"
#include <pugixml.hpp>

namespace odr::internal::ooxml::spreadsheet {
Expand All @@ -26,26 +27,20 @@ class Document final : public common::TemplateDocument<Element> {
void save(const common::Path &path) const final;
void save(const common::Path &path, const char *password) const final;

pugi::xml_node get_sheet_root(const std::string &ref) const;
std::pair<const pugi::xml_document &, const Relations &>
get_xml(const common::Path &) const;
pugi::xml_node get_shared_string(std::size_t index) const;

private:
struct Sheet final {
common::Path sheet_path;
pugi::xml_document sheet_xml;
std::optional<common::Path> drawing_path;
pugi::xml_document drawing_xml;
};

pugi::xml_document m_workbook_xml;
pugi::xml_document m_styles_xml;
std::unordered_map<std::string, Sheet> m_sheets;
std::unordered_map<std::string, pugi::xml_document> m_drawings_xml;
pugi::xml_document m_shared_strings_xml;
std::unordered_map<common::Path, std::pair<pugi::xml_document, Relations>>
m_xml;

StyleRegistry m_style_registry;
std::vector<pugi::xml_node> m_shared_strings;

std::pair<pugi::xml_document &, Relations &>
parse_xml_(const common::Path &path);

friend class Element;
};

Expand Down
Loading

0 comments on commit 3cfdf8f

Please sign in to comment.