parse relationship mode and implement reading hyperlinks, closes #87

This commit is contained in:
Thomas Fussell 2016-11-30 01:05:47 +01:00
parent d9b1fef34f
commit a1ff8c0ed2
5 changed files with 59 additions and 11 deletions

View File

@ -368,6 +368,20 @@ struct value_traits<xlnt::border_side>
} }
}; // struct value_traits<xlnt::border_side> }; // struct value_traits<xlnt::border_side>
template <>
struct value_traits<xlnt::target_mode>
{
static xlnt::target_mode parse(std::string mode_string, const parser &)
{
return mode_string == "Internal" ? xlnt::target_mode::internal : xlnt::target_mode::external;
}
static std::string serialize (xlnt::target_mode mode, const serializer &)
{
return mode == xlnt::target_mode::internal ? "Internal" : "External";
}
}; // struct value_traits<xlnt::target_mode>
} }

View File

@ -56,7 +56,6 @@ struct hash<xml::qname>
namespace { namespace {
#ifndef NDEBUG #ifndef NDEBUG
#error NDEBUG
#define THROW_ON_INVALID_XML #define THROW_ON_INVALID_XML
#endif #endif
@ -160,10 +159,15 @@ std::vector<relationship> xlsx_consumer::read_relationships(const path &part)
while (in_element(xml::qname(xmlns, "Relationships"))) while (in_element(xml::qname(xmlns, "Relationships")))
{ {
expect_start_element(xml::qname(xmlns, "Relationship"), xml::content::simple); expect_start_element(xml::qname(xmlns, "Relationship"), xml::content::simple);
auto mode = parser.attribute_present("TargetMode")
? parser.attribute<xlnt::target_mode>("TargetMode")
: target_mode::internal;
relationships.emplace_back(parser.attribute("Id"), relationships.emplace_back(parser.attribute("Id"),
parser.attribute<xlnt::relationship::type>("Type"), source, parser.attribute<xlnt::relationship::type>("Type"), source,
xlnt::uri(parser.attribute("Target")), xlnt::uri(parser.attribute("Target")),
xlnt::target_mode::internal); mode);
expect_end_element(xml::qname(xmlns, "Relationship")); expect_end_element(xml::qname(xmlns, "Relationship"));
} }
@ -1567,6 +1571,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
static const auto &xmlns = constants::get_namespace("spreadsheetml"); static const auto &xmlns = constants::get_namespace("spreadsheetml");
static const auto &xmlns_mc = constants::get_namespace("mc"); static const auto &xmlns_mc = constants::get_namespace("mc");
static const auto &xmlns_x14ac = constants::get_namespace("x14ac"); static const auto &xmlns_x14ac = constants::get_namespace("x14ac");
static const auto &xmlns_r = constants::get_namespace("r");
auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(), auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
target_.d_->sheet_title_rel_id_map_.end(), target_.d_->sheet_title_rel_id_map_.end(),
@ -1596,7 +1601,14 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
skip_attributes({xml::qname(xmlns_mc, "Ignorable")}); skip_attributes({xml::qname(xmlns_mc, "Ignorable")});
xlnt::range_reference full_range; xlnt::range_reference full_range;
const auto &shared_strings = target_.get_shared_strings(); const auto &shared_strings = target_.get_shared_strings();
auto &manifest = target_.get_manifest();
const auto workbook_rel = manifest.get_relationship(path("/"), relationship::type::office_document);
const auto sheet_rel = manifest.get_relationship(workbook_rel.get_target().get_path(), rel_id);
path sheet_path(sheet_rel.get_source().get_path().parent().append(sheet_rel.get_target().get_path()));
auto hyperlinks = manifest.get_relationships(sheet_path, xlnt::relationship::type::hyperlink);
while (in_element(xml::qname(xmlns, "worksheet"))) while (in_element(xml::qname(xmlns, "worksheet")))
{ {
@ -1853,7 +1865,22 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
} }
else if (current_worksheet_element == xml::qname(xmlns, "hyperlinks")) // CT_Hyperlinks 0-1 else if (current_worksheet_element == xml::qname(xmlns, "hyperlinks")) // CT_Hyperlinks 0-1
{ {
skip_remaining_content(current_worksheet_element); while (in_element(xml::qname(xmlns, "hyperlinks")))
{
expect_start_element(xml::qname(xmlns, "hyperlink"), xml::content::simple);
auto cell = ws.get_cell(parser().attribute("ref"));
auto hyperlink_rel_id = parser().attribute(xml::qname(xmlns_r, "id"));
auto hyperlink_rel = std::find_if(hyperlinks.begin(), hyperlinks.end(),
[&](const relationship &r) { return r.get_id() == hyperlink_rel_id; });
if (hyperlink_rel != hyperlinks.end())
{
cell.set_hyperlink(hyperlink_rel->get_target().get_path().string());
}
expect_end_element(xml::qname(xmlns, "hyperlink"));
}
} }
else if (current_worksheet_element == xml::qname(xmlns, "printOptions")) // CT_PrintOptions 0-1 else if (current_worksheet_element == xml::qname(xmlns, "printOptions")) // CT_PrintOptions 0-1
{ {
@ -1922,11 +1949,6 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
expect_end_element(xml::qname(xmlns, "worksheet")); expect_end_element(xml::qname(xmlns, "worksheet"));
auto &manifest = target_.get_manifest();
const auto workbook_rel = manifest.get_relationship(path("/"), relationship::type::office_document);
const auto sheet_rel = manifest.get_relationship(workbook_rel.get_target().get_path(), rel_id);
path sheet_path(sheet_rel.get_source().get_path().parent().append(sheet_rel.get_target().get_path()));
if (manifest.has_relationship(sheet_path, xlnt::relationship::type::comments)) if (manifest.has_relationship(sheet_path, xlnt::relationship::type::comments))
{ {
auto comments_part = manifest.canonicalize( auto comments_part = manifest.canonicalize(

View File

@ -106,6 +106,8 @@ std::vector<relationship> manifest::get_relationships(const path &part, relation
{ {
std::vector<relationship> matches; std::vector<relationship> matches;
if (has_relationship(part, type))
{
for (const auto &rel : relationships_.at(part)) for (const auto &rel : relationships_.at(part))
{ {
if (rel.second.get_type() == type) if (rel.second.get_type() == type)
@ -113,6 +115,7 @@ std::vector<relationship> manifest::get_relationships(const path &part, relation
matches.push_back(rel.second); matches.push_back(rel.second);
} }
} }
}
return matches; return matches;
} }

View File

@ -79,4 +79,13 @@ public:
TS_ASSERT_EQUALS(wb2.get_active_sheet().get_cell("A1").get_value<std::string>(), "unicode!"); TS_ASSERT_EQUALS(wb2.get_active_sheet().get_cell("A1").get_value<std::string>(), "unicode!");
#endif #endif
} }
void test_read_hyperlink()
{
xlnt::workbook wb;
wb.load("data/20_with_hyperlink.xlsx");
TS_ASSERT(wb.get_active_sheet().get_cell("A1").has_hyperlink());
TS_ASSERT_EQUALS(wb.get_active_sheet().get_cell("A1").get_hyperlink(),
"https://fr.wikipedia.org/wiki/Ille-et-Vilaine");
}
}; };

Binary file not shown.