fix styles -- Excel wanted to repair saved workbooks

This commit is contained in:
Thomas Fussell 2016-05-15 15:03:02 -04:00
parent 365e2f93fc
commit 135af6e6c9
19 changed files with 176 additions and 88 deletions

View File

@ -64,7 +64,8 @@ public:
extended_properties, extended_properties,
core_properties, core_properties,
office_document, office_document,
custom_xml custom_xml,
thumbnail
}; };
static type type_from_string(const std::string &type_string); static type type_from_string(const std::string &type_string);

View File

@ -67,11 +67,11 @@ protected:
private: private:
std::experimental::optional<side> start_; std::experimental::optional<side> start_;
std::experimental::optional<side> end_; std::experimental::optional<side> end_;
std::experimental::optional<side> left_; std::experimental::optional<side> left_ = side();
std::experimental::optional<side> right_; std::experimental::optional<side> right_ = side();
std::experimental::optional<side> top_; std::experimental::optional<side> top_ = side();
std::experimental::optional<side> bottom_; std::experimental::optional<side> bottom_ = side();
std::experimental::optional<side> diagonal_; std::experimental::optional<side> diagonal_ = side();
std::experimental::optional<side> vertical_; std::experimental::optional<side> vertical_;
std::experimental::optional<side> horizontal_; std::experimental::optional<side> horizontal_;

View File

@ -122,8 +122,8 @@ protected:
std::string to_hash_string() const override; std::string to_hash_string() const override;
private: private:
type type_ = type::none; type type_ = type::pattern;
pattern_type pattern_type_; pattern_type pattern_type_ = pattern_type::none;
gradient_type gradient_type_; gradient_type gradient_type_;
double rotation_ = 0; double rotation_ = 0;

View File

@ -95,18 +95,18 @@ private:
friend class style; friend class style;
std::string name_ = "Calibri"; std::string name_ = "Calibri";
std::size_t size_ = 11; std::size_t size_ = 12;
bool bold_ = false; bool bold_ = false;
bool italic_ = false; bool italic_ = false;
bool superscript_ = false; bool superscript_ = false;
bool subscript_ = false; bool subscript_ = false;
underline_style underline_ = underline_style::none; underline_style underline_ = underline_style::none;
bool strikethrough_ = false; bool strikethrough_ = false;
color color_; color color_ = color(xlnt::color::type::theme, 1);
bool has_family_ = false; bool has_family_ = true;
std::size_t family_; std::size_t family_ = 2;
bool has_scheme_ = false; bool has_scheme_ = true;
std::string scheme_; std::string scheme_ = "minor";
}; };
} // namespace xlnt } // namespace xlnt

View File

@ -54,6 +54,7 @@ class range;
class range_reference; class range_reference;
class relationship; class relationship;
class style; class style;
class style_serializer;
class text; class text;
class theme; class theme;
class worksheet; class worksheet;
@ -196,11 +197,13 @@ public:
style &get_style(const std::string &name); style &get_style(const std::string &name);
const style &get_style(const std::string &name) const; const style &get_style(const std::string &name) const;
style &create_style(const std::string &name); style &create_style(const std::string &name);
void clear_styles();
const std::vector<style> &get_styles() const; const std::vector<style> &get_styles() const;
manifest &get_manifest(); manifest &get_manifest();
const manifest &get_manifest() const; const manifest &get_manifest() const;
void create_root_relationship(const std::string &id, const std::string &target, relationship::type type);
const std::vector<relationship> &get_root_relationships() const; const std::vector<relationship> &get_root_relationships() const;
void add_shared_string(const text &shared, bool allow_duplicates=false); void add_shared_string(const text &shared, bool allow_duplicates=false);
@ -212,6 +215,10 @@ public:
private: private:
friend class worksheet; friend class worksheet;
friend class style_serializer;
std::string next_relationship_id() const;
std::unique_ptr<detail::workbook_impl> d_; std::unique_ptr<detail::workbook_impl> d_;
}; };

View File

@ -25,9 +25,20 @@
#include <iterator> #include <iterator>
#include <vector> #include <vector>
#include <detail/worksheet_impl.hpp>
#include <xlnt/packaging/app_properties.hpp>
#include <xlnt/packaging/document_properties.hpp>
#include <xlnt/packaging/manifest.hpp>
#include <xlnt/workbook/theme.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/sheet_view.hpp>
namespace xlnt { namespace xlnt {
namespace detail { namespace detail {
struct worksheet_impl;
struct workbook_impl struct workbook_impl
{ {
workbook_impl(); workbook_impl();

View File

@ -20,14 +20,20 @@
// //
// @license: http://www.opensource.org/licenses/mit-license.php // @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <xlnt/workbook/named_range.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/sheet_view.hpp>
#include <xlnt/worksheet/column_properties.hpp> #include <xlnt/worksheet/column_properties.hpp>
#include <xlnt/worksheet/row_properties.hpp> #include <xlnt/worksheet/row_properties.hpp>
#include "cell_impl.hpp" #include <detail/cell_impl.hpp>
namespace xlnt { namespace xlnt {

View File

@ -26,7 +26,9 @@
namespace xlnt { namespace xlnt {
document_properties::document_properties() document_properties::document_properties()
: created(1900, 1, 1), modified(1900, 1, 1), excel_base_date(calendar::windows_1900) : created(1900, 1, 1),
modified(1900, 1, 1),
excel_base_date(calendar::windows_1900)
{ {
} }

View File

@ -81,6 +81,10 @@ relationship::type relationship::type_from_string(const std::string &type_string
{ {
return type::custom_xml; return type::custom_xml;
} }
else if (type_string == "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail")
{
return type::thumbnail;
}
return type::invalid; return type::invalid;
} }
@ -109,6 +113,8 @@ std::string relationship::type_to_string(type t)
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"; return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
case type::custom_xml: case type::custom_xml:
return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml"; return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
case type::thumbnail:
return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
default: default:
return "??"; return "??";
} }

View File

@ -106,6 +106,13 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
} }
xlnt::relationship_serializer relationship_serializer_(archive); xlnt::relationship_serializer relationship_serializer_(archive);
auto root_relationships = relationship_serializer_.read_relationships("");
for (const auto &relationship : root_relationships)
{
wb.create_root_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type());
}
auto workbook_relationships = relationship_serializer_.read_relationships(xlnt::constants::ArcWorkbook()); auto workbook_relationships = relationship_serializer_.read_relationships(xlnt::constants::ArcWorkbook());
for (const auto &relationship : workbook_relationships) for (const auto &relationship : workbook_relationships)
@ -247,9 +254,13 @@ void excel_serializer::write_data(bool /*as_template*/)
theme_serializer theme_serializer_; theme_serializer theme_serializer_;
archive_.writestr(constants::ArcTheme(), theme_serializer_.write_theme(workbook_.get_loaded_theme()).to_string()); archive_.writestr(constants::ArcTheme(), theme_serializer_.write_theme(workbook_.get_loaded_theme()).to_string());
archive_.writestr( if (!workbook_.get_shared_strings().empty())
constants::ArcSharedString(), {
xml_serializer::serialize(xlnt::shared_strings_serializer::write_shared_strings(workbook_.get_shared_strings()))); const auto &strings = workbook_.get_shared_strings();
auto shared_strings_xml = xlnt::shared_strings_serializer::write_shared_strings(strings);
archive_.writestr(constants::ArcSharedString(), xml_serializer::serialize(shared_strings_xml));
}
archive_.writestr(constants::ArcWorkbook(), xml_serializer::serialize(workbook_serializer_.write_workbook())); archive_.writestr(constants::ArcWorkbook(), xml_serializer::serialize(workbook_serializer_.write_workbook()));

View File

@ -95,8 +95,8 @@ bool relationship_serializer::write_relationships(const std::vector<relationship
auto relationship_node = root_node.add_child("Relationship"); auto relationship_node = root_node.add_child("Relationship");
relationship_node.add_attribute("Id", relationship.get_id()); relationship_node.add_attribute("Id", relationship.get_id());
relationship_node.add_attribute("Target", relationship.get_target_uri());
relationship_node.add_attribute("Type", relationship.get_type_string()); relationship_node.add_attribute("Type", relationship.get_type_string());
relationship_node.add_attribute("Target", relationship.get_target_uri());
if (relationship.get_target_mode() == target_mode::external) if (relationship.get_target_mode() == target_mode::external)
{ {

View File

@ -25,6 +25,7 @@
#include <unordered_set> #include <unordered_set>
#include <xlnt/serialization/style_serializer.hpp> #include <xlnt/serialization/style_serializer.hpp>
#include <detail/workbook_impl.hpp>
#include <xlnt/cell/cell.hpp> #include <xlnt/cell/cell.hpp>
#include <xlnt/serialization/xml_document.hpp> #include <xlnt/serialization/xml_document.hpp>
#include <xlnt/serialization/xml_node.hpp> #include <xlnt/serialization/xml_node.hpp>
@ -395,6 +396,11 @@ bool style_serializer::read_stylesheet(const xml_document &xml)
read_styles(stylesheet_node.get_child("cellStyles"), stylesheet_node.get_child("cellStyleXfs")); read_styles(stylesheet_node.get_child("cellStyles"), stylesheet_node.get_child("cellStyleXfs"));
read_formats(stylesheet_node.get_child("cellXfs")); read_formats(stylesheet_node.get_child("cellXfs"));
if (!styles_.empty())
{
workbook_.clear_styles();
}
for (const auto &ns : styles_) for (const auto &ns : styles_)
{ {
workbook_.create_style(ns.get_name()) = ns; workbook_.create_style(ns.get_name()) = ns;
@ -407,7 +413,7 @@ bool style_serializer::read_stylesheet(const xml_document &xml)
for (const auto &s : formats_) for (const auto &s : formats_)
{ {
workbook_.add_format(s); workbook_.d_->formats_.push_back(s);
} }
return true; return true;
@ -758,27 +764,7 @@ color style_serializer::read_color(const xml_node &color_node)
void style_serializer::initialize_vectors() void style_serializer::initialize_vectors()
{ {
bool any_style = false; formats_.assign(workbook_.get_formats().begin(), workbook_.get_formats().end());
for (auto ws : workbook_)
{
for (auto row : ws)
{
for (auto cell : row)
{
if (cell.has_format())
{
any_style = true;
}
}
}
}
if (any_style)
{
formats_.assign(workbook_.get_formats().begin(), workbook_.get_formats().end());
}
colors_.clear(); colors_.clear();
borders_.clear(); borders_.clear();
fills_.clear(); fills_.clear();
@ -1123,24 +1109,18 @@ bool style_serializer::write_formattable(const formattable &xf, xml_node xf_node
auto font_id = std::distance(fonts_.begin(), std::find(fonts_.begin(), fonts_.end(), xf.get_font())); auto font_id = std::distance(fonts_.begin(), std::find(fonts_.begin(), fonts_.end(), xf.get_font()));
xf_node.add_attribute("fontId", std::to_string(font_id)); xf_node.add_attribute("fontId", std::to_string(font_id));
if (xf.fill_applied()) auto fill_id = std::distance(fills_.begin(), std::find(fills_.begin(), fills_.end(), xf.get_fill()));
{ xf_node.add_attribute("fillId", std::to_string(fill_id));
auto fill_id = std::distance(fills_.begin(), std::find(fills_.begin(), fills_.end(), xf.get_fill()));
xf_node.add_attribute("fillId", std::to_string(fill_id));
}
if (xf.border_applied()) auto border_id = std::distance(borders_.begin(), std::find(borders_.begin(), borders_.end(), xf.get_border()));
{ xf_node.add_attribute("borderId", std::to_string(border_id));
auto border_id = std::distance(borders_.begin(), std::find(borders_.begin(), borders_.end(), xf.get_border()));
xf_node.add_attribute("borderId", std::to_string(border_id));
}
xf_node.add_attribute("applyNumberFormat", xf.number_format_applied() ? "1" : "0"); if(xf.number_format_applied()) xf_node.add_attribute("applyNumberFormat", "1");
xf_node.add_attribute("applyFill", xf.fill_applied() ? "1" : "0"); if(xf.fill_applied()) xf_node.add_attribute("applyFill", "1");
xf_node.add_attribute("applyFont", xf.font_applied() ? "1" : "0"); if(xf.font_applied()) xf_node.add_attribute("applyFont", "1");
xf_node.add_attribute("applyBorder", xf.border_applied() ? "1" : "0"); if(xf.border_applied()) xf_node.add_attribute("applyBorder", "1");
xf_node.add_attribute("applyAlignment", xf.alignment_applied() ? "1" : "0"); if(xf.alignment_applied()) xf_node.add_attribute("applyAlignment", "1");
xf_node.add_attribute("applyProtection", xf.protection_applied() ? "1" : "0"); if(xf.protection_applied()) xf_node.add_attribute("applyProtection", "1");
if (xf.alignment_applied()) if (xf.alignment_applied())
{ {
@ -1205,6 +1185,8 @@ bool style_serializer::write_formattable(const formattable &xf, xml_node xf_node
} }
} }
//TODO protection
return true; return true;
} }
@ -1270,8 +1252,8 @@ bool write_dxfs(xlnt::xml_node &dxfs_node)
bool write_table_styles(xlnt::xml_node &table_styles_node) bool write_table_styles(xlnt::xml_node &table_styles_node)
{ {
table_styles_node.add_attribute("count", "0"); table_styles_node.add_attribute("count", "0");
table_styles_node.add_attribute("defaultTableStyle", "TableStyleMedium2"); table_styles_node.add_attribute("defaultTableStyle", "TableStyleMedium9");
table_styles_node.add_attribute("defaultPivotStyle", "PivotStyleMedium9"); table_styles_node.add_attribute("defaultPivotStyle", "PivotStyleMedium7");
return true; return true;
} }
@ -1309,8 +1291,11 @@ xml_document style_serializer::write_stylesheet()
root_node.add_attribute("mc:Ignorable", "x14ac"); root_node.add_attribute("mc:Ignorable", "x14ac");
doc.add_namespace("x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"); doc.add_namespace("x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
auto number_formats_node = root_node.add_child("numFmts"); if (number_formats_.size() > 1 || !(number_formats_.front() == number_format::general()))
write_number_formats(number_formats_node); {
auto number_formats_node = root_node.add_child("numFmts");
write_number_formats(number_formats_node);
}
auto fonts_node = root_node.add_child("fonts"); auto fonts_node = root_node.add_child("fonts");
write_fonts(fonts_node); write_fonts(fonts_node);

View File

@ -29,6 +29,19 @@ public:
return wb; return wb;
} }
void test_temp()
{
xlnt::workbook wb;
wb.load("/Users/thomas/Desktop/Workbook1.xlsx");
//xlnt::worksheet ws = wb.get_active_sheet();
//ws.get_cell("A1").set_value(5);
//ws.get_cell("B2").set_value("string data");
//ws.get_cell("C3").set_formula("=RAND()");
//ws.merge_cells("C3:C4");
//ws.freeze_panes("B2");
wb.save("/Users/thomas/Desktop/Workbook1-rt.xlsx");
}
void test_read_standard_workbook() void test_read_standard_workbook()
{ {

View File

@ -46,6 +46,7 @@ public:
void test_write_workbook_rels() void test_write_workbook_rels()
{ {
xlnt::workbook wb; xlnt::workbook wb;
wb.add_shared_string(xlnt::text());
xlnt::zip_file archive; xlnt::zip_file archive;
xlnt::relationship_serializer serializer(archive); xlnt::relationship_serializer serializer(archive);
serializer.write_relationships(wb.get_relationships(), "xl/workbook.xml"); serializer.write_relationships(wb.get_relationships(), "xl/workbook.xml");

View File

@ -220,8 +220,8 @@ xml_document workbook_serializer::write_properties_app() const
auto heading_pairs_node = root_node.add_child("HeadingPairs"); auto heading_pairs_node = root_node.add_child("HeadingPairs");
auto heading_pairs_vector_node = heading_pairs_node.add_child("vt:vector"); auto heading_pairs_vector_node = heading_pairs_node.add_child("vt:vector");
heading_pairs_vector_node.add_attribute("baseType", "variant");
heading_pairs_vector_node.add_attribute("size", "2"); heading_pairs_vector_node.add_attribute("size", "2");
heading_pairs_vector_node.add_attribute("baseType", "variant");
heading_pairs_vector_node.add_child("vt:variant").add_child("vt:lpstr").set_text("Worksheets"); heading_pairs_vector_node.add_child("vt:variant").add_child("vt:lpstr").set_text("Worksheets");
heading_pairs_vector_node.add_child("vt:variant") heading_pairs_vector_node.add_child("vt:variant")
.add_child("vt:i4") .add_child("vt:i4")
@ -229,8 +229,8 @@ xml_document workbook_serializer::write_properties_app() const
auto titles_of_parts_node = root_node.add_child("TitlesOfParts"); auto titles_of_parts_node = root_node.add_child("TitlesOfParts");
auto titles_of_parts_vector_node = titles_of_parts_node.add_child("vt:vector"); auto titles_of_parts_vector_node = titles_of_parts_node.add_child("vt:vector");
titles_of_parts_vector_node.add_attribute("baseType", "lpstr");
titles_of_parts_vector_node.add_attribute("size", std::to_string(workbook_.get_sheet_names().size())); titles_of_parts_vector_node.add_attribute("size", std::to_string(workbook_.get_sheet_names().size()));
titles_of_parts_vector_node.add_attribute("baseType", "lpstr");
for (auto ws : workbook_) for (auto ws : workbook_)
{ {

View File

@ -35,7 +35,7 @@ namespace xlnt {
std::string xml_serializer::serialize(const xml_document &xml) std::string xml_serializer::serialize(const xml_document &xml)
{ {
std::ostringstream ss; std::ostringstream ss;
xml.d_->doc.save(ss, " ", pugi::format_default, pugi::encoding_utf8); xml.d_->doc.save(ss, " ", pugi::format_default, pugi::encoding_utf8);
return ss.str(); return ss.str();
} }

View File

@ -20,27 +20,44 @@ public:
auto stylesheet_xml = style_serializer.write_stylesheet().to_string(); auto stylesheet_xml = style_serializer.write_stylesheet().to_string();
const std::string expected = const std::string expected =
"<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" mc:Ignorable=\"x14ac\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\">" "<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:mc=\"http://schemas.openxmlformats.org/markup-compatibility/2006\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\" mc:Ignorable=\"x14ac\">"
" <numFmts count=\"1\">"
" <numFmt numFmtId=\"0\" formatCode=\"General\" />"
" </numFmts>"
" <fonts count=\"1\">" " <fonts count=\"1\">"
" <font>" " <font>"
" <sz val=\"11\" />" " <sz val=\"12\"/>"
" <color indexed=\"0\" />" " <color theme=\"1\"/>"
" <name val=\"Calibri\" />" " <name val=\"Calibri\"/>"
" <family val=\"2\"/>"
" <scheme val=\"minor\"/>"
" </font>" " </font>"
" </fonts>" " </fonts>"
" <fills count=\"0\" />" " <fills count=\"1\">"
" <borders count=\"0\" />" " <fill>"
" <cellStyleXfs count=\"0\" />" " <patternFill patternType=\"none\"/>"
" <cellXfs count=\"0\" />" " </fill>"
" <cellStyles count=\"0\" />" " </fills>"
" <dxfs count=\"0\" />" " <borders count=\"1\">"
" <tableStyles count=\"0\" defaultTableStyle=\"TableStyleMedium2\" defaultPivotStyle=\"PivotStyleMedium9\" />" " <border>"
" <left/>"
" <right/>"
" <top/>"
" <bottom/>"
" <diagonal/>"
" </border>"
" </borders>"
" <cellStyleXfs count=\"1\">"
" <xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\"/>"
" </cellStyleXfs>"
" <cellXfs count=\"1\">"
" <xf numFmtId=\"0\" fontId=\"0\" fillId=\"0\" borderId=\"0\" xfId=\"0\"/>"
" </cellXfs>"
" <cellStyles count=\"1\">"
" <cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\"/>"
" </cellStyles>"
" <dxfs count=\"0\"/>"
" <tableStyles count=\"0\" defaultTableStyle=\"TableStyleMedium9\" defaultPivotStyle=\"PivotStyleMedium7\"/>"
" <extLst>" " <extLst>"
" <ext uri=\"{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}\" xmlns:x14=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\">" " <ext xmlns:x14=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/main\" uri=\"{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}\">"
" <x14:slicerStyles defaultSlicerStyle=\"SlicerStyleLight1\" />" " <x14:slicerStyles defaultSlicerStyle=\"SlicerStyleLight1\"/>"
" </ext>" " </ext>"
" </extLst>" " </extLst>"
"</styleSheet>"; "</styleSheet>";

View File

@ -70,9 +70,8 @@ workbook::workbook() : d_(new detail::workbook_impl())
{ {
create_sheet("Sheet"); create_sheet("Sheet");
create_relationship("rId2", "sharedStrings.xml", relationship::type::shared_strings); create_relationship("rId2", "styles.xml", relationship::type::styles);
create_relationship("rId3", "styles.xml", relationship::type::styles); create_relationship("rId3", "theme/theme1.xml", relationship::type::theme);
create_relationship("rId4", "theme/theme1.xml", relationship::type::theme);
d_->encoding_ = encoding::utf8; d_->encoding_ = encoding::utf8;
@ -82,11 +81,11 @@ workbook::workbook() : d_(new detail::workbook_impl())
d_->manifest_.add_override_type("/xl/workbook.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"); d_->manifest_.add_override_type("/xl/workbook.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
d_->manifest_.add_override_type("/xl/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml"); d_->manifest_.add_override_type("/xl/theme/theme1.xml", "application/vnd.openxmlformats-officedocument.theme+xml");
d_->manifest_.add_override_type("/xl/styles.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"); d_->manifest_.add_override_type("/xl/styles.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml");
d_->manifest_.add_override_type("/xl/sharedStrings.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml");
d_->manifest_.add_override_type("/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml"); d_->manifest_.add_override_type("/docProps/core.xml", "application/vnd.openxmlformats-package.core-properties+xml");
d_->manifest_.add_override_type("/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml"); d_->manifest_.add_override_type("/docProps/app.xml", "application/vnd.openxmlformats-officedocument.extended-properties+xml");
add_format(format()); add_format(format());
create_style("Normal");
} }
workbook::workbook(encoding e) : workbook() workbook::workbook(encoding e) : workbook()
@ -268,6 +267,11 @@ void workbook::create_relationship(const std::string &id, const std::string &tar
d_->relationships_.push_back(relationship(type, id, target)); d_->relationships_.push_back(relationship(type, id, target));
} }
void workbook::create_root_relationship(const std::string &id, const std::string &target, relationship::type type)
{
d_->root_relationships_.push_back(relationship(type, id, target));
}
relationship workbook::get_relationship(const std::string &id) const relationship workbook::get_relationship(const std::string &id) const
{ {
for (auto &rel : d_->relationships_) for (auto &rel : d_->relationships_)
@ -646,6 +650,11 @@ std::size_t workbook::add_format(const format &style)
return d_->formats_.size() - 1; return d_->formats_.size() - 1;
} }
void workbook::clear_styles()
{
d_->styles_.clear();
}
void workbook::clear_formats() void workbook::clear_formats()
{ {
d_->formats_.clear(); d_->formats_.clear();
@ -697,6 +706,12 @@ const std::vector<text> &workbook::get_shared_strings() const
void workbook::add_shared_string(const text &shared, bool allow_duplicates) void workbook::add_shared_string(const text &shared, bool allow_duplicates)
{ {
if (d_->shared_strings_.empty())
{
create_relationship(next_relationship_id(), "sharedStrings.xml", relationship::type::shared_strings);
d_->manifest_.add_override_type("/xl/sharedStrings.xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml");
}
if (!allow_duplicates) if (!allow_duplicates)
{ {
//TODO: inefficient, use a set or something? //TODO: inefficient, use a set or something?
@ -761,4 +776,17 @@ const style &workbook::get_style(const std::string &name) const
[&name](const style &s) { return s.get_name() == name; }); [&name](const style &s) { return s.get_name() == name; });
} }
std::string workbook::next_relationship_id() const
{
std::size_t i = 1;
while (std::find_if(d_->relationships_.begin(), d_->relationships_.end(),
[i](const relationship &r) { return r.get_id() == "rId" + std::to_string(i); }) != d_->relationships_.end())
{
i++;
}
return "rId" + std::to_string(i);
}
} // namespace xlnt } // namespace xlnt

View File

@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"> <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Target="worksheets/sheet1.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"/> <Relationship Id="rId1" Target="worksheets/sheet1.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"/>
<Relationship Id="rId2" Target="sharedStrings.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"/> <Relationship Id="rId2" Target="styles.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"/>
<Relationship Id="rId3" Target="styles.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"/> <Relationship Id="rId3" Target="theme/theme1.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"/>
<Relationship Id="rId4" Target="theme/theme1.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"/> <Relationship Id="rId4" Target="sharedStrings.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"/>
</Relationships> </Relationships>