keep refactoring serialization code

pull/36/head
Thomas Fussell 2015-10-29 19:37:07 -04:00
parent c884ad7f82
commit 75ec0f8eee
27 changed files with 1042 additions and 1058 deletions

View File

@ -21,7 +21,7 @@ project "xlnt.test"
"../../tests/runner-autogen.cpp"
}
links { "xlnt", "miniz" }
prebuildcommands { "../generate-tests.sh" }
prebuildcommands { "../../generate-tests.sh" }
flags { "Unicode" }
configuration "windows"
defines { "WIN32" }

View File

@ -37,7 +37,7 @@ class workbook;
class excel_serializer
{
public:
static std::string central_directory_signature();
static const std::string central_directory_signature();
static std::string repair_central_directory(const std::string &original);
excel_serializer(workbook &wb);
@ -46,9 +46,9 @@ public:
bool load_stream_workbook(std::istream &stream, bool guess_types = false, bool data_only = false);
bool load_virtual_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types = false, bool data_only = false);
bool save_workbook(workbook &wb, const std::string &filename, bool as_template = false);
bool save_virtual_workbook(xlnt::workbook &wb, std::vector<std::uint8_t> &bytes, bool as_template = false);
bool save_stream_workbook(xlnt::workbook &wb, std::ostream &stream, bool as_template = false);
bool save_workbook(const std::string &filename, bool as_template = false);
bool save_virtual_workbook(std::vector<std::uint8_t> &bytes, bool as_template = false);
bool save_stream_workbook(std::ostream &stream, bool as_template = false);
private:
void read_data(bool guess_types, bool data_only);

View File

@ -14,7 +14,7 @@ class manifest_serializer
public:
manifest_serializer(manifest &m);
bool read_mainfest(const xml_document &xml);
bool read_manifest(const xml_document &xml);
bool write_manifest(xml_document &xml);
private:

View File

@ -10,8 +10,9 @@ class xml_document;
class relationship_serializer
{
bool read_relationships(const xml_document &xml, const std::string &dir, std::vector<relationship> &relationships);
bool write_relationships(const std::vector<relationship> &relationships, const std::string &dir, xml_document &xml);
public:
static bool read_relationships(const xml_document &xml, const std::string &dir, std::vector<relationship> &relationships);
static bool write_relationships(const std::vector<relationship> &relationships, const std::string &dir, xml_document &xml);
};
} // namespace xlnt

View File

@ -26,11 +26,14 @@
#include <string>
namespace xlnt {
class theme;
class xml_document;
class theme_serializer
{
public:
theme read_theme(const xml_document &xml);
//theme read_theme(const xml_document &xml);
xml_document write_theme(const theme &theme_);
};

View File

@ -35,10 +35,14 @@ class worksheet;
class workbook;
class zip_file;
class xml_document;
class xml_node;
class workbook_serializer
{
public:
//TODO: does this go here?
static std::string determine_document_type(const manifest &manifest_);
workbook_serializer(workbook &wb);
void read_workbook(const xml_document &xml);
@ -48,17 +52,14 @@ public:
xml_document write_workbook() const;
xml_document write_properties_app() const;
xml_document write_properties_core() const;
private:
//workbook_view, sheets, sheet, defined_names
std::string determine_document_type(const manifest &manifest_);
using string_pair = std::pair<std::string, std::string>;
std::vector<string_pair> read_sheets(zip_file &archive);
std::vector<string_pair> detect_worksheets(zip_file &archive);
std::string write_defined_names(const workbook &wb);
bool write_named_ranges(xml_node &named_ranges_node);
workbook &wb_;
};

View File

@ -41,9 +41,8 @@ class worksheet_serializer
public:
worksheet_serializer(worksheet sheet);
bool read_worksheet(const xml_document &xml, const std::vector<std::string> &shared_strings, const relationship &rel, worksheet ws);
std::string read_dimension(const xml_node &dimension_node);
bool write_worksheet(const worksheet ws, const std::vector<std::string> &string_table, xml_document &xml);
bool read_worksheet(const xml_document &xml, const std::vector<std::string> &shared_strings, const relationship &rel);
bool write_worksheet(const std::vector<std::string> &string_table, xml_document &xml);
private:
worksheet sheet_;

View File

@ -22,6 +22,7 @@ public:
const std::vector<xml_node> &get_children() const;
bool has_child(const std::string &child_name) const;
xml_node &get_child(const std::string &child_name);
const xml_node &get_child(const std::string &child_name) const;
xml_node &add_child(const xml_node &child);
xml_node &add_child(const std::string &child_name);

View File

@ -70,6 +70,8 @@ public:
color get_color() const { return color_; }
bool has_family() const { return has_family_; }
int get_family() const { return family_; }
bool has_scheme() const { return has_scheme_; }
std::size_t hash() const

View File

@ -50,12 +50,6 @@ enum class border_style
class side
{
public:
enum class color_type
{
theme,
indexed
};
side();
std::size_t hash() const

View File

@ -49,6 +49,7 @@ class range;
class range_reference;
class relationship;
class style;
class theme;
class worksheet;
class zip_file;
@ -199,7 +200,7 @@ public:
void create_relationship(const std::string &id, const std::string &target, relationship::type type);
relationship get_relationship(const std::string &id) const;
std::vector<relationship> get_relationships() const;
const std::vector<relationship> &get_relationships() const;
void add_alignment(const alignment &a);
void add_border(const border &b);
@ -237,8 +238,8 @@ public:
void set_code_name(const std::string &code_name);
bool has_loaded_theme();
std::string get_loaded_theme();
bool has_loaded_theme() const;
const theme &get_loaded_theme() const;
const style &get_style(std::size_t style_id) const;
std::size_t add_style(const style &style_);
@ -246,6 +247,8 @@ public:
manifest &get_manifest();
const manifest &get_manifest() const;
const std::vector<relationship> &get_root_relationships() const;
private:
friend class worksheet;
std::shared_ptr<detail::workbook_impl> d_;

View File

@ -223,7 +223,7 @@ public:
// relationships
relationship create_relationship(relationship::type type, const std::string &target_uri);
std::vector<relationship> get_relationships();
const std::vector<relationship> &get_relationships() const;
// charts
//void add_chart(chart chart);
@ -262,7 +262,9 @@ public:
const range operator()(const cell_reference &top_left, const cell_reference &bottom_right) const;
// page
page_setup &get_page_setup();
const page_setup &get_page_setup() const;
margins &get_page_margins();
const margins &get_page_margins() const;
// auto filter

View File

@ -42,11 +42,9 @@ const std::string download_url = "https://github.com/tfussell/xlnt/archive/maste
#include "common/relationship.hpp"
#include "common/string_table.hpp"
#include "common/zip_file.hpp"
#include "reader/excel_reader.hpp"
#include "workbook/document_properties.hpp"
#include "workbook/named_range.hpp"
#include "workbook/workbook.hpp"
#include "worksheet/range.hpp"
#include "worksheet/range_reference.hpp"
#include "worksheet/worksheet.hpp"
#include "writer/workbook_writer.hpp"

View File

@ -13,7 +13,8 @@ struct workbook_impl
workbook_impl(const workbook_impl &other)
: active_sheet_index_(other.active_sheet_index_),
worksheets_(other.worksheets_),
relationships_(other.relationships_),
relationships_(other.relationships_),
root_relationships_(other.root_relationships_),
drawings_(other.drawings_),
properties_(other.properties_),
guess_types_(other.guess_types_),
@ -35,6 +36,8 @@ struct workbook_impl
std::copy(other.worksheets_.begin(), other.worksheets_.end(), back_inserter(worksheets_));
relationships_.clear();
std::copy(other.relationships_.begin(), other.relationships_.end(), std::back_inserter(relationships_));
root_relationships_.clear();
std::copy(other.root_relationships_.begin(), other.root_relationships_.end(), std::back_inserter(root_relationships_));
drawings_.clear();
std::copy(other.drawings_.begin(), other.drawings_.end(), back_inserter(drawings_));
properties_ = other.properties_;
@ -54,6 +57,7 @@ struct workbook_impl
std::size_t active_sheet_index_;
std::vector<worksheet_impl> worksheets_;
std::vector<relationship> relationships_;
std::vector<relationship> root_relationships_;
std::vector<drawing> drawings_;
document_properties properties_;
@ -72,6 +76,8 @@ struct workbook_impl
std::vector<number_format> number_formats_;
manifest manifest_;
theme theme_;
};
} // namespace detail

View File

@ -1,7 +1,20 @@
#include <xlnt/s11n/excel_serializer.hpp>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/s11n/manifest_serializer.hpp>
#include <xlnt/s11n/relationship_serializer.hpp>
#include <xlnt/s11n/shared_strings_serializer.hpp>
#include <xlnt/s11n/style_serializer.hpp>
#include <xlnt/s11n/theme_serializer.hpp>
#include <xlnt/s11n/workbook_serializer.hpp>
#include <xlnt/s11n/worksheet_serializer.hpp>
#include <xlnt/s11n/xml_document.hpp>
#include <xlnt/s11n/xml_serializer.hpp>
#include <xlnt/workbook/document_properties.hpp>
#include <xlnt/workbook/manifest.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <detail/constants.hpp>
namespace {
@ -22,99 +35,69 @@ std::string::size_type find_string_in_string(const std::string &string, const st
return possible_match_index;
}
xlnt::workbook load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only)
bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xlnt::workbook &wb)
{
xlnt::workbook wb;
wb.set_guess_types(guess_types);
wb.set_data_only(data_only);
auto content_types = xlnt::read_content_types(archive);
auto type = xlnt::determine_document_type(content_types);
xlnt::manifest_serializer ms(wb.get_manifest());
ms.read_manifest(xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcContentTypes)));
if(type != "excel")
if(xlnt::workbook_serializer::determine_document_type(wb.get_manifest()) != "excel")
{
throw xlnt::invalid_file_exception("");
}
wb.clear();
auto workbook_relationships = read_relationships(archive, "xl/workbook.xml");
std::vector<xlnt::relationship> workbook_relationships;
xlnt::relationship_serializer::read_relationships(xlnt::xml_serializer::deserialize(archive.read("xl/_rels/workbook.xml.rels")), "", workbook_relationships);
for(auto relationship : workbook_relationships)
{
wb.create_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type());
}
pugi::xml_document doc;
doc.load(archive.read("xl/workbook.xml").c_str());
auto xml = xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcWorkbook));
auto root_node = doc.child("workbook");
auto &root_node = xml.root();
auto workbook_pr_node = root_node.child("workbookPr");
wb.get_properties().excel_base_date = (workbook_pr_node.attribute("date1904") != nullptr && workbook_pr_node.attribute("date1904").as_int() != 0) ? xlnt::calendar::mac_1904 : xlnt::calendar::windows_1900;
auto &workbook_pr_node = root_node.get_child("workbookPr");
wb.get_properties().excel_base_date = (workbook_pr_node.has_attribute("date1904") && workbook_pr_node.get_attribute("date1904") != "0") ? xlnt::calendar::mac_1904 : xlnt::calendar::windows_1900;
auto sheets_node = root_node.child("sheets");
xlnt::shared_strings_serializer shared_strings_serializer_;
std::vector<std::string> shared_strings;
shared_strings_serializer_.read_strings(xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcSharedString)), shared_strings);
xlnt::shared_strings_reader shared_strings_reader_;
auto shared_strings = shared_strings_reader_.read_strings(archive);
xlnt::style_serializer style_reader_(wb);
style_reader_.read_stylesheet(xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcStyles)));
xlnt::style_reader style_reader_(wb);
style_reader_.read_styles(archive);
auto &sheets_node = root_node.get_child("sheets");
for(const auto &border_ : style_reader_.get_borders())
for(auto sheet_node : sheets_node.get_children())
{
wb.add_border(border_);
}
for(const auto &fill_ : style_reader_.get_fills())
{
wb.add_fill(fill_);
}
for(const auto &font_ : style_reader_.get_fonts())
{
wb.add_font(font_);
}
for(const auto &number_format_ : style_reader_.get_number_formats())
{
wb.add_number_format(number_format_);
}
for(auto &color_rgb : style_reader_.get_colors())
{
wb.add_color(xlnt::color(xlnt::color::type::rgb, color_rgb));
}
for(const auto &style : style_reader_.get_styles())
{
wb.add_style(style);
}
for(auto sheet_node : sheets_node.children("sheet"))
{
auto rel = wb.get_relationship(sheet_node.attribute("r:id").as_string());
auto ws = wb.create_sheet(sheet_node.attribute("name").as_string(), rel);
auto rel = wb.get_relationship(sheet_node.get_attribute("r:id"));
auto ws = wb.create_sheet(sheet_node.get_attribute("name"), rel);
xlnt::read_worksheet(ws, archive, rel, shared_strings);
xlnt::worksheet_serializer worksheet_serializer(ws);
worksheet_serializer.read_worksheet(xlnt::xml_serializer::deserialize(archive.read(rel.get_target_uri())), shared_strings, rel);
}
return wb;
return true;
}
} // namespace
namespace xlnt {
std::string excel_reader::CentralDirectorySignature()
const std::string excel_serializer::central_directory_signature()
{
return "\x50\x4b\x05\x06";
}
std::string excel_reader::repair_central_directory(const std::string &original)
std::string excel_serializer::repair_central_directory(const std::string &original)
{
auto pos = find_string_in_string(original, CentralDirectorySignature());
auto pos = find_string_in_string(original, central_directory_signature());
if(pos != std::string::npos)
{
@ -124,104 +107,76 @@ std::string excel_reader::repair_central_directory(const std::string &original)
return original;
}
workbook excel_reader::load_workbook(std::istream &stream, bool guess_types, bool data_only)
bool excel_serializer::load_stream_workbook(std::istream &stream, bool guess_types, bool data_only)
{
std::vector<std::uint8_t> bytes((std::istream_iterator<char>(stream)),
std::istream_iterator<char>());
return load_workbook(bytes, guess_types, data_only);
return load_virtual_workbook(bytes, guess_types, data_only);
}
workbook excel_reader::load_workbook(const std::string &filename, bool guess_types, bool data_only)
bool excel_serializer::load_workbook(const std::string &filename, bool guess_types, bool data_only)
{
xlnt::zip_file archive;
try
{
archive.load(filename);
archive_.load(filename);
}
catch(std::runtime_error)
{
throw invalid_file_exception(filename);
}
return ::load_workbook(archive, guess_types, data_only);
return ::load_workbook(archive_, guess_types, data_only, wb_);
}
xlnt::workbook excel_reader::load_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types, bool data_only)
bool excel_serializer::load_virtual_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types, bool data_only)
{
xlnt::zip_file archive;
archive.load(bytes);
archive_.load(bytes);
return ::load_workbook(archive, guess_types, data_only);
return ::load_workbook(archive_, guess_types, data_only, wb_);
}
excel_writer::excel_writer(workbook &wb) : wb_(wb)
excel_serializer::excel_serializer(workbook &wb) : wb_(wb)
{
}
void excel_writer::save(const std::string &filename, bool as_template)
void excel_serializer::write_data(bool as_template)
{
zip_file archive;
write_data(archive, as_template);
archive.save(filename);
relationship_serializer relationship_serializer_;
xlnt::xml_document root_rels_xml;
relationship_serializer_.write_relationships(wb_.get_root_relationships(), "", root_rels_xml);
archive_.writestr(constants::ArcRootRels, xml_serializer::serialize(root_rels_xml));
xml_document workbook_rels_xml;
relationship_serializer_.write_relationships(wb_.get_relationships(), "", workbook_rels_xml);
archive_.writestr(constants::ArcWorkbookRels, xml_serializer::serialize(workbook_rels_xml));
xml_document properties_app_xml;
workbook_serializer workbook_serializer_(wb_);
archive_.writestr(constants::ArcApp, xml_serializer::serialize(workbook_serializer_.write_properties_app()));
archive_.writestr(constants::ArcCore, xml_serializer::serialize(workbook_serializer_.write_properties_core()));
theme_serializer theme_serializer_;
xml_document theme_xml = theme_serializer_.write_theme(wb_.get_loaded_theme());
archive_.writestr(constants::ArcTheme, xml_serializer::serialize(theme_xml));
archive_.writestr(constants::ArcWorkbook, xml_serializer::serialize(workbook_serializer_.write_workbook()));
style_serializer style_serializer_(wb_);
xml_document style_xml;
style_serializer_.write_stylesheet(style_xml);
archive_.writestr(constants::ArcStyles, xml_serializer::serialize(style_xml));
manifest_serializer manifest_serializer_(wb_.get_manifest());
xml_document manifest_xml;
manifest_serializer_.write_manifest(manifest_xml);
archive_.writestr(constants::ArcContentTypes, xml_serializer::serialize(manifest_xml));
write_worksheets();
}
void excel_writer::write_data(zip_file &archive, bool as_template)
{
archive.writestr(constants::ArcRootRels, write_root_rels(wb_));
archive.writestr(constants::ArcWorkbookRels, write_workbook_rels(wb_));
archive.writestr(constants::ArcApp, write_properties_app(wb_));
archive.writestr(constants::ArcCore, write_properties_core(wb_.get_properties()));
if(wb_.has_loaded_theme())
{
archive.writestr(constants::ArcTheme, wb_.get_loaded_theme());
}
else
{
archive.writestr(constants::ArcTheme, write_theme());
}
archive.writestr(constants::ArcWorkbook, write_workbook(wb_));
auto shared_strings = extract_all_strings(wb_);
write_charts(archive);
write_images(archive);
write_shared_strings(archive, shared_strings);
write_worksheets(archive, shared_strings);
write_chartsheets(archive);
write_external_links(archive);
style_writer style_writer_(wb_);
archive.writestr(constants::ArcStyles, style_writer_.write_table());
auto manifest = write_content_types(wb_, as_template);
archive.writestr(constants::ArcContentTypes, manifest);
}
void excel_writer::write_shared_strings(xlnt::zip_file &archive, const std::vector<std::string> &shared_strings)
{
archive.writestr(constants::ArcSharedString, ::xlnt::write_shared_strings(shared_strings));
}
void excel_writer::write_images(zip_file &/*archive*/)
{
}
void excel_writer::write_charts(zip_file &/*archive*/)
{
}
void excel_writer::write_chartsheets(zip_file &/*archive*/)
{
}
void excel_writer::write_worksheets(zip_file &archive, const std::vector<std::string> &shared_strings)
void excel_serializer::write_worksheets()
{
std::size_t index = 0;
@ -232,7 +187,10 @@ void excel_writer::write_worksheets(zip_file &archive, const std::vector<std::st
if(relationship.get_type() == relationship::type::worksheet &&
workbook::index_from_ws_filename(relationship.get_target_uri()) == index)
{
archive.writestr(relationship.get_target_uri(), write_worksheet(ws, shared_strings));
worksheet_serializer serializer_(ws);
xml_document xml;
serializer_.write_worksheet(shared_strings_, xml);
archive_.writestr(relationship.get_target_uri(), xml_serializer::serialize(xml));
break;
}
}
@ -241,27 +199,33 @@ void excel_writer::write_worksheets(zip_file &archive, const std::vector<std::st
}
}
void excel_writer::write_external_links(zip_file &/*archive*/)
void excel_serializer::write_external_links()
{
}
bool save_workbook(workbook &wb, const std::string &filename, bool as_template)
bool excel_serializer::save_stream_workbook(std::ostream &stream, bool as_template)
{
excel_writer writer(wb);
writer.save(filename, as_template);
write_data(as_template);
archive_.save(stream);
return true;
}
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template)
bool excel_serializer::save_workbook(const std::string &filename, bool as_template)
{
zip_file archive;
excel_writer writer(wb);
writer.write_data(archive, as_template);
std::vector<std::uint8_t> buffer;
archive.save(buffer);
write_data(as_template);
archive_.save(filename);
return true;
}
bool excel_serializer::save_virtual_workbook(std::vector<std::uint8_t> &bytes, bool as_template)
{
write_data(as_template);
archive_.save(bytes);
return buffer;
return true;
}
} // namespace xlnt

View File

@ -7,10 +7,27 @@
#include "detail/constants.hpp"
namespace xlnt {
bool relationship_serializer::read_relationships(const xml_document &xml, const std::string &dir, std::vector<relationship> &relationships)
{
return false;
auto root_node = xml.root();
root_node.set_name("Relationships");
for(auto relationship_node : root_node.get_children())
{
if(relationship_node.get_name() != "Relationship")
{
continue;
}
std::string id = relationship_node.get_attribute("Id");
std::string type = relationship_node.get_attribute("Type");
std::string target = relationship_node.get_attribute("Target");
relationships.push_back(xlnt::relationship(type, id, target));
}
return true;
}
bool relationship_serializer::write_relationships(const std::vector<relationship> &relationships, const std::string &dir, xml_document &xml)
@ -29,15 +46,15 @@ bool relationship_serializer::write_relationships(const std::vector<relationship
target = target.substr(dir.size());
}
auto app_props_node = root_node.add_child("Relationship");
auto relationship_node = root_node.add_child("Relationship");
app_props_node.add_attribute("Id", relationship.get_id());
app_props_node.add_attribute("Target", target);
app_props_node.add_attribute("Type", relationship.get_type_string());
relationship_node.add_attribute("Id", relationship.get_id());
relationship_node.add_attribute("Target", target);
relationship_node.add_attribute("Type", relationship.get_type_string());
if(relationship.get_target_mode() == target_mode::external)
{
app_props_node.add_attribute("TargetMode", "External");
relationship_node.add_attribute("TargetMode", "External");
}
}

View File

@ -526,28 +526,32 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
xml.add_namespace("mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
xml.add_namespace("x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
auto &style_sheet_node = doc.add_child("styleSheet");
xml.add_attribute("mc:Ignorable", "x14ac");
auto &style_sheet_node = xml.root();
style_sheet_node.set_name("styleSheet");
style_sheet_node.add_attribute("mc:Ignorable", "x14ac");
auto num_fmts_node = style_sheet_node.add_child("numFmts");
auto num_fmts = wb_.get_number_formats();
num_fmts_node.add_attribute("count", static_cast<int>(num_fmts.size()));
num_fmts_node.add_attribute("count", std::to_string(num_fmts.size()));
for(auto &num_fmt : num_fmts)
{
auto num_fmt_node = num_fmts_node.add_child("numFmt");
num_fmt_node.add_attribute("numFmtId", num_fmt.get_id());
num_fmt_node.add_attribute("numFmtId", std::to_string(num_fmt.get_id()));
num_fmt_node.add_attribute("formatCode", num_fmt.get_format_string());
}
auto fonts_node = style_sheet_node.add_child("fonts");
auto fonts = wb_.get_fonts();
if(fonts.empty())
{
fonts.push_back(font());
}
fonts_node.add_attribute("count", static_cast<int>(fonts.size()));
fonts_node.add_attribute("x14ac:knownFonts", 1);
fonts_node.add_attribute("count", std::to_string(fonts.size()));
//TODO: what does this do?
//fonts_node.add_attribute("x14ac:knownFonts", "1");
for(auto &f : fonts)
{
@ -556,13 +560,13 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
if(f.is_bold())
{
auto bold_node = font_node.add_child("b");
bold_node.add_attribute("val", 1);
bold_node.add_attribute("val", "1");
}
if(f.is_italic())
{
auto bold_node = font_node.add_child("i");
bold_node.add_attribute("val", 1);
bold_node.add_attribute("val", "1");
}
if(f.is_underline())
@ -582,21 +586,21 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
if(f.is_strikethrough())
{
auto bold_node = font_node.add_child("strike");
bold_node.add_attribute("val", 1);
bold_node.add_attribute("val", "1");
}
auto size_node = font_node.add_child("sz");
size_node.add_attribute("val", f.get_size());
size_node.add_attribute("val", std::to_string(f.get_size()));
auto color_node = font_node.add_child("color");
if(f.get_color().get_type() == color::type::indexed)
{
color_node.add_attribute("indexed", static_cast<unsigned int>(f.get_color().get_index()));
color_node.add_attribute("indexed", std::to_string(f.get_color().get_index()));
}
else if(f.get_color().get_type() == color::type::theme)
{
color_node.add_attribute("theme", static_cast<unsigned int>(f.get_color().get_theme()));
color_node.add_attribute("theme", std::to_string(f.get_color().get_theme()));
}
auto name_node = font_node.add_child("name");
@ -605,7 +609,7 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
if(f.has_family())
{
auto family_node = font_node.add_child("family");
family_node.add_attribute("val", 2);
family_node.add_attribute("val", std::to_string(f.get_family()));
}
if(f.has_scheme())
@ -617,7 +621,7 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
auto fills_node = style_sheet_node.add_child("fills");
const auto &fills = wb_.get_fills();
fills_node.add_attribute("count", static_cast<unsigned int>(fills.size()));
fills_node.add_attribute("count", std::to_string(fills.size()));
for(auto &fill_ : fills)
{
@ -631,13 +635,13 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
if(fill_.has_foreground_color())
{
auto fg_color_node = pattern_fill_node.add_child("fgColor");
auto &fg_color_node = pattern_fill_node.add_child("fgColor");
switch(fill_.get_foreground_color().get_type())
{
case color::type::auto_: fg_color_node.add_attribute("auto", fill_.get_foreground_color().get_auto()); break;
case color::type::theme: fg_color_node.add_attribute("theme", fill_.get_foreground_color().get_theme()); break;
case color::type::indexed: fg_color_node.add_attribute("indexed", fill_.get_foreground_color().get_index()); break;
case color::type::auto_: fg_color_node.add_attribute("auto", std::to_string(fill_.get_foreground_color().get_auto())); break;
case color::type::theme: fg_color_node.add_attribute("theme", std::to_string(fill_.get_foreground_color().get_theme())); break;
case color::type::indexed: fg_color_node.add_attribute("indexed", std::to_string(fill_.get_foreground_color().get_index())); break;
default: throw std::runtime_error("bad type");
}
}
@ -648,9 +652,9 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
switch(fill_.get_background_color().get_type())
{
case color::type::auto_: bg_color_node.add_attribute("auto", fill_.get_background_color().get_auto()); break;
case color::type::theme: bg_color_node.add_attribute("theme", fill_.get_background_color().get_theme()); break;
case color::type::indexed: bg_color_node.add_attribute("indexed", fill_.get_background_color().get_index()); break;
case color::type::auto_: bg_color_node.add_attribute("auto", std::to_string(fill_.get_background_color().get_auto())); break;
case color::type::theme: bg_color_node.add_attribute("theme", std::to_string(fill_.get_background_color().get_theme())); break;
case color::type::indexed: bg_color_node.add_attribute("indexed", std::to_string(fill_.get_background_color().get_index())); break;
default: throw std::runtime_error("bad type");
}
}
@ -666,27 +670,27 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
if(fill_.get_gradient_type_string() == "linear")
{
gradient_fill_node.add_attribute("degree", fill_.get_rotation());
gradient_fill_node.add_attribute("degree", std::to_string(fill_.get_rotation()));
}
else if(fill_.get_gradient_type_string() == "path")
{
gradient_fill_node.add_attribute("left", fill_.get_gradient_left());
gradient_fill_node.add_attribute("right", fill_.get_gradient_right());
gradient_fill_node.add_attribute("top", fill_.get_gradient_top());
gradient_fill_node.add_attribute("bottom", fill_.get_gradient_bottom());
gradient_fill_node.add_attribute("left", std::to_string(fill_.get_gradient_left()));
gradient_fill_node.add_attribute("right", std::to_string(fill_.get_gradient_right()));
gradient_fill_node.add_attribute("top", std::to_string(fill_.get_gradient_top()));
gradient_fill_node.add_attribute("bottom", std::to_string(fill_.get_gradient_bottom()));
auto start_node = gradient_fill_node.add_child("stop");
start_node.add_attribute("position", 0);
start_node.add_attribute("position", "0");
auto end_node = gradient_fill_node.add_child("stop");
end_node.add_attribute("position", 1);
end_node.add_attribute("position", "1");
}
}
}
auto borders_node = style_sheet_node.add_child("borders");
const auto &borders = wb_.get_borders();
borders_node.add_attribute("count", static_cast<unsigned int>(borders.size()));
borders_node.add_attribute("count", std::to_string(borders.size()));
for(const auto &border_ : borders)
{
@ -715,39 +719,41 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
if(side_.is_style_assigned())
{
auto style_attribute = side_node.add_attribute("style");
std::string style_string;
switch(side_.get_style())
{
case border_style::none: style_attribute.set_value("none"); break;
case border_style::dashdot : style_attribute.set_value("dashdot"); break;
case border_style::dashdotdot : style_attribute.set_value("dashdotdot"); break;
case border_style::dashed : style_attribute.set_value("dashed"); break;
case border_style::dotted : style_attribute.set_value("dotted"); break;
case border_style::double_ : style_attribute.set_value("double"); break;
case border_style::hair : style_attribute.set_value("hair"); break;
case border_style::medium : style_attribute.set_value("thin"); break;
case border_style::mediumdashdot: style_attribute.set_value("mediumdashdot"); break;
case border_style::mediumdashdotdot: style_attribute.set_value("mediumdashdotdot"); break;
case border_style::mediumdashed: style_attribute.set_value("mediumdashed"); break;
case border_style::slantdashdot: style_attribute.set_value("slantdashdot"); break;
case border_style::thick: style_attribute.set_value("thick"); break;
case border_style::thin: style_attribute.set_value("thin"); break;
case border_style::none: style_string = "none"; break;
case border_style::dashdot: style_string = "dashdot"; break;
case border_style::dashdotdot: style_string = "dashdotdot"; break;
case border_style::dashed: style_string = "dashed"; break;
case border_style::dotted: style_string = "dotted"; break;
case border_style::double_: style_string = "double"; break;
case border_style::hair: style_string = "hair"; break;
case border_style::medium: style_string = "thin"; break;
case border_style::mediumdashdot: style_string = "mediumdashdot"; break;
case border_style::mediumdashdotdot: style_string = "mediumdashdotdot"; break;
case border_style::mediumdashed: style_string = "mediumdashed"; break;
case border_style::slantdashdot: style_string = "slantdashdot"; break;
case border_style::thick: style_string = "thick"; break;
case border_style::thin: style_string = "thin"; break;
default: throw std::runtime_error("invalid style");
}
side_node.add_attribute("style", style_string);
}
if(side_.is_color_assigned())
{
auto color_node = side_node.add_child("color");
if(side_.get_color_type() == side::color_type::indexed)
if(side_.get_color().get_type() == color::type::indexed)
{
color_node.add_attribute("indexed", (int)side_.get_color());
color_node.add_attribute("indexed", std::to_string(side_.get_color().get_index()));
}
else if(side_.get_color_type() == side::color_type::theme)
else if(side_.get_color().get_type() == color::type::theme)
{
color_node.add_attribute("indexed", (int)side_.get_color());
color_node.add_attribute("theme", std::to_string(side_.get_color().get_theme()));
}
else
{
@ -758,40 +764,41 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
}
}
auto cell_style_xfs_node = style_sheet_node.add_child("cellStyleXfs");
cell_style_xfs_node.add_attribute("count", 1);
auto style_xf_node = cell_style_xfs_node.add_child("xf");
style_xf_node.add_attribute("numFmtId", 0);
style_xf_node.add_attribute("fontId", 0);
style_xf_node.add_attribute("fillId", 0);
style_xf_node.add_attribute("borderId", 0);
auto &cell_style_xfs_node = style_sheet_node.add_child("cellStyleXfs");
cell_style_xfs_node.add_attribute("count", "1");
auto &style_xf_node = cell_style_xfs_node.add_child("xf");
style_xf_node.add_attribute("numFmtId", "0");
style_xf_node.add_attribute("fontId", "0");
style_xf_node.add_attribute("fillId", "0");
style_xf_node.add_attribute("borderId", "0");
auto cell_xfs_node = style_sheet_node.add_child("cellXfs");
const auto &styles = wb_.get_styles();
cell_xfs_node.add_attribute("count", static_cast<int>(styles.size()));
cell_xfs_node.add_attribute("count", std::to_string(styles.size()));
for(auto &style : styles)
{
auto xf_node = cell_xfs_node.add_child("xf");
xf_node.add_attribute("numFmtId", style.get_number_format().get_id());
xf_node.add_attribute("fontId", (int)style.get_font_id());
xf_node.add_attribute("numFmtId", std::to_string(style.get_number_format().get_id()));
xf_node.add_attribute("fontId", std::to_string(style.get_font_id()));
if(style.fill_apply_)
{
xf_node.add_attribute("fillId", (int)style.get_fill_id());
xf_node.add_attribute("fillId", std::to_string(style.get_fill_id()));
}
if(style.border_apply_)
{
xf_node.add_attribute("borderId", (int)style.get_border_id());
xf_node.add_attribute("borderId", std::to_string(style.get_border_id()));
}
xf_node.add_attribute("applyNumberFormat", style.number_format_apply_ ? 1 : 0);
xf_node.add_attribute("applyFont", style.font_apply_ ? 1 : 0);
xf_node.add_attribute("applyFill", style.fill_apply_ ? 1 : 0);
xf_node.add_attribute("applyBorder", style.border_apply_ ? 1 : 0);
xf_node.add_attribute("applyAlignment", style.alignment_apply_ ? 1 : 0);
xf_node.add_attribute("applyProtection", style.protection_apply_ ? 1 : 0);
xf_node.add_attribute("applyNumberFormat", style.number_format_apply_ ? "1" : "0");
xf_node.add_attribute("applyFont", style.font_apply_ ? "1" : "0");
xf_node.add_attribute("applyFill", style.fill_apply_ ? "1" : "0");
xf_node.add_attribute("applyBorder", style.border_apply_ ? "1" : "0");
xf_node.add_attribute("applyAlignment", style.alignment_apply_ ? "1" : "0");
xf_node.add_attribute("applyProtection", style.protection_apply_ ? "1" : "0");
if(style.alignment_apply_)
{
@ -847,22 +854,22 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
if(style.alignment_.get_wrap_text())
{
alignment_node.add_attribute("wrapText", 1);
alignment_node.add_attribute("wrapText", "1");
}
}
}
auto cell_styles_node = style_sheet_node.add_child("cellStyles");
cell_styles_node.add_attribute("count", 1);
cell_styles_node.add_attribute("count", "1");
auto cell_style_node = cell_styles_node.add_child("cellStyle");
cell_style_node.add_attribute("name", "Normal");
cell_style_node.add_attribute("xfId", 0);
cell_style_node.add_attribute("builtinId", 0);
cell_style_node.add_attribute("xfId", "0");
cell_style_node.add_attribute("builtinId", "0");
style_sheet_node.add_child("dxfs").add_attribute("count", 0);
style_sheet_node.add_child("dxfs").add_attribute("count", "0");
auto table_styles_node = style_sheet_node.add_child("tableStyles");
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("defaultPivotStyle", "PivotStyleMedium9");

View File

@ -0,0 +1,356 @@
#include <xlnt/s11n/theme_serializer.hpp>
#include <xlnt/s11n/xml_document.hpp>
#include <xlnt/s11n/xml_node.hpp>
#include <detail/constants.hpp>
namespace xlnt {
//I have no idea what this stuff is. I hope it was worth it.
xml_document theme_serializer::write_theme(const theme &theme_)
{
xml_document xml;
xml.add_namespace("a", constants::Namespaces.at("drawingml"));
auto &theme_node = xml.root();
theme_node.set_name("a:theme");
theme_node.add_attribute("name", "Office Theme");
auto &theme_elements_node = theme_node.add_child("a:themeElements");
auto &clr_scheme_node = theme_elements_node.add_child("a:clrScheme");
clr_scheme_node.add_attribute("name", "Office");
struct scheme_element
{
std::string name;
std::string sub_element_name;
std::string val;
};
std::vector<scheme_element> scheme_elements =
{
{"a:dk1", "a:sysClr", "windowText"},
{"a:lt1", "a:sysClr", "window"},
{"a:dk2", "a:srgbClr", "1F497D"},
{"a:lt2", "a:srgbClr", "EEECE1"},
{"a:accent1", "a:srgbClr", "4F81BD"},
{"a:accent2", "a:srgbClr", "C0504D"},
{"a:accent3", "a:srgbClr", "9BBB59"},
{"a:accent4", "a:srgbClr", "8064A2"},
{"a:accent5", "a:srgbClr", "4BACC6"},
{"a:accent6", "a:srgbClr", "F79646"},
{"a:hlink", "a:srgbClr", "0000FF"},
{"a:folHlink", "a:srgbClr", "800080"},
};
for(auto element : scheme_elements)
{
auto element_node = clr_scheme_node.add_child(element.name);
element_node.add_child(element.sub_element_name).add_attribute("val", element.val);
if(element.name == "a:dk1")
{
element_node.get_child(element.sub_element_name).add_attribute("lastClr", "000000");
}
else if(element.name == "a:lt1")
{
element_node.get_child(element.sub_element_name).add_attribute("lastClr", "FFFFFF");
}
}
struct font_scheme
{
bool typeface;
std::string script;
std::string major;
std::string minor;
};
std::vector<font_scheme> font_schemes =
{
{true, "a:latin", "Cambria", "Calibri"},
{true, "a:ea", "", ""},
{true, "a:cs", "", ""},
{false, "Jpan", "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf", "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf"},
{false, "Hang", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95"},
{false, "Hans", "\xe5\xae\x8b\xe4\xbd\x93", "\xe5\xae\x8b\xe4\xbd\x93"},
{false, "Hant", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94"},
{false, "Arab", "Times New Roman", "Arial"},
{false, "Hebr", "Times New Roman", "Arial"},
{false, "Thai", "Tahoma", "Tahoma"},
{false, "Ethi", "Nyala", "Nyala"},
{false, "Beng", "Vrinda", "Vrinda"},
{false, "Gujr", "Shruti", "Shruti"},
{false, "Khmr", "MoolBoran", "DaunPenh"},
{false, "Knda", "Tunga", "Tunga"},
{false, "Guru", "Raavi", "Raavi"},
{false, "Cans", "Euphemia", "Euphemia"},
{false, "Cher", "Plantagenet Cherokee", "Plantagenet Cherokee"},
{false, "Yiii", "Microsoft Yi Baiti", "Microsoft Yi Baiti"},
{false, "Tibt", "Microsoft Himalaya", "Microsoft Himalaya"},
{false, "Thaa", "MV Boli", "MV Boli"},
{false, "Deva", "Mangal", "Mangal"},
{false, "Telu", "Gautami", "Gautami"},
{false, "Taml", "Latha", "Latha"},
{false, "Syrc", "Estrangelo Edessa", "Estrangelo Edessa"},
{false, "Orya", "Kalinga", "Kalinga"},
{false, "Mlym", "Kartika", "Kartika"},
{false, "Laoo", "DokChampa", "DokChampa"},
{false, "Sinh", "Iskoola Pota", "Iskoola Pota"},
{false, "Mong", "Mongolian Baiti", "Mongolian Baiti"},
{false, "Viet", "Times New Roman", "Arial"},
{false, "Uigh", "Microsoft Uighur", "Microsoft Uighur"}
};
auto font_scheme_node = theme_elements_node.add_child("a:fontScheme");
font_scheme_node.add_attribute("name", "Office");
auto major_fonts_node = font_scheme_node.add_child("a:majorFont");
auto minor_fonts_node = font_scheme_node.add_child("a:minorFont");
for(auto scheme : font_schemes)
{
if(scheme.typeface)
{
auto &major_font_node = major_fonts_node.add_child(scheme.script);
major_font_node.add_attribute("typeface", scheme.major);
auto &minor_font_node = minor_fonts_node.add_child(scheme.script);
minor_font_node.add_attribute("typeface", scheme.minor);
}
else
{
auto &major_font_node = major_fonts_node.add_child("a:font");
major_font_node.add_attribute("script", scheme.script);
major_font_node.add_attribute("typeface", scheme.major);
auto &minor_font_node = minor_fonts_node.add_child("a:font");
minor_font_node.add_attribute("script", scheme.script);
minor_font_node.add_attribute("typeface", scheme.minor);
}
}
auto format_scheme_node = theme_elements_node.add_child("a:fmtScheme");
format_scheme_node.add_attribute("name", "Office");
auto fill_style_list_node = format_scheme_node.add_child("a:fillStyleLst");
fill_style_list_node.add_child("a:solidFill").add_child("a:schemeClr").add_attribute("val", "phClr");
auto grad_fill_node = fill_style_list_node.add_child("a:gradFill");
grad_fill_node.add_attribute("rotWithShape", "1");
auto grad_fill_list = grad_fill_node.add_child("a:gsLst");
auto gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", 0);
auto scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:tint").add_attribute("val", "50000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "300000");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "35000");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:tint").add_attribute("val", "37000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "300000");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "100000");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:tint").add_attribute("val", "15000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "350000");
auto lin_node = grad_fill_node.add_child("a:lin");
lin_node.add_attribute("ang", "16200000");
lin_node.add_attribute("scaled", "1");
grad_fill_node = fill_style_list_node.add_child("a:gradFill");
grad_fill_node.add_attribute("rotWithShape", "1");
grad_fill_list = grad_fill_node.add_child("a:gsLst");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "0");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:shade").add_attribute("val", "51000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "130000");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "80000");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:shade").add_attribute("val", "93000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "130000");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "100000");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:shade").add_attribute("val", "94000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "135000");
lin_node = grad_fill_node.add_child("a:lin");
lin_node.add_attribute("ang", "16200000");
lin_node.add_attribute("scaled", "0");
auto line_style_list_node = format_scheme_node.add_child("a:lnStyleLst");
auto ln_node = line_style_list_node.add_child("a:ln");
ln_node.add_attribute("w", "9525");
ln_node.add_attribute("cap", "flat");
ln_node.add_attribute("cmpd", "sng");
ln_node.add_attribute("algn", "ctr");
auto solid_fill_node = ln_node.add_child("a:solidFill");
scheme_color_node = solid_fill_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:shade").add_attribute("val", "95000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "105000");
ln_node.add_child("a:prstDash").add_attribute("val", "solid");
ln_node = line_style_list_node.add_child("a:ln");
ln_node.add_attribute("w", "25400");
ln_node.add_attribute("cap", "flat");
ln_node.add_attribute("cmpd", "sng");
ln_node.add_attribute("algn", "ctr");
solid_fill_node = ln_node.add_child("a:solidFill");
scheme_color_node = solid_fill_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
ln_node.add_child("a:prstDash").add_attribute("val", "solid");
ln_node = line_style_list_node.add_child("a:ln");
ln_node.add_attribute("w", "38100");
ln_node.add_attribute("cap", "flat");
ln_node.add_attribute("cmpd", "sng");
ln_node.add_attribute("algn", "ctr");
solid_fill_node = ln_node.add_child("a:solidFill");
scheme_color_node = solid_fill_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
ln_node.add_child("a:prstDash").add_attribute("val", "solid");
auto effect_style_list_node = format_scheme_node.add_child("a:effectStyleLst");
auto effect_style_node = effect_style_list_node.add_child("a:effectStyle");
auto effect_list_node = effect_style_node.add_child("a:effectLst");
auto outer_shadow_node = effect_list_node.add_child("a:outerShdw");
outer_shadow_node.add_attribute("blurRad", "40000");
outer_shadow_node.add_attribute("dist", "20000");
outer_shadow_node.add_attribute("dir", "5400000");
outer_shadow_node.add_attribute("rotWithShape", "0");
auto srgb_clr_node = outer_shadow_node.add_child("a:srgbClr");
srgb_clr_node.add_attribute("val", "000000");
srgb_clr_node.add_child("a:alpha").add_attribute("val", "38000");
effect_style_node = effect_style_list_node.add_child("a:effectStyle");
effect_list_node = effect_style_node.add_child("a:effectLst");
outer_shadow_node = effect_list_node.add_child("a:outerShdw");
outer_shadow_node.add_attribute("blurRad", "40000");
outer_shadow_node.add_attribute("dist", "23000");
outer_shadow_node.add_attribute("dir", "5400000");
outer_shadow_node.add_attribute("rotWithShape", "0");
srgb_clr_node = outer_shadow_node.add_child("a:srgbClr");
srgb_clr_node.add_attribute("val", "000000");
srgb_clr_node.add_child("a:alpha").add_attribute("val", "35000");
effect_style_node = effect_style_list_node.add_child("a:effectStyle");
effect_list_node = effect_style_node.add_child("a:effectLst");
outer_shadow_node = effect_list_node.add_child("a:outerShdw");
outer_shadow_node.add_attribute("blurRad", "40000");
outer_shadow_node.add_attribute("dist", "23000");
outer_shadow_node.add_attribute("dir", "5400000");
outer_shadow_node.add_attribute("rotWithShape", "0");
srgb_clr_node = outer_shadow_node.add_child("a:srgbClr");
srgb_clr_node.add_attribute("val", "000000");
srgb_clr_node.add_child("a:alpha").add_attribute("val", "35000");
auto scene3d_node = effect_style_node.add_child("a:scene3d");
auto camera_node = scene3d_node.add_child("a:camera");
camera_node.add_attribute("prst", "orthographicFront");
auto rot_node = camera_node.add_child("a:rot");
rot_node.add_attribute("lat", "0");
rot_node.add_attribute("lon", "0");
rot_node.add_attribute("rev", "0");
auto light_rig_node = scene3d_node.add_child("a:lightRig");
light_rig_node.add_attribute("rig", "threePt");
light_rig_node.add_attribute("dir", "t");
rot_node = light_rig_node.add_child("a:rot");
rot_node.add_attribute("lat", "0");
rot_node.add_attribute("lon", "0");
rot_node.add_attribute("rev", "1200000");
auto bevel_node = effect_style_node.add_child("a:sp3d").add_child("a:bevelT");
bevel_node.add_attribute("w", "63500");
bevel_node.add_attribute("h", "25400");
auto bg_fill_style_list_node = format_scheme_node.add_child("a:bgFillStyleLst");
bg_fill_style_list_node.add_child("a:solidFill").add_child("a:schemeClr").add_attribute("val", "phClr");
grad_fill_node = bg_fill_style_list_node.add_child("a:gradFill");
grad_fill_node.add_attribute("rotWithShape", "1");
grad_fill_list = grad_fill_node.add_child("a:gsLst");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "0");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:tint").add_attribute("val", "40000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "350000");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "40000");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:tint").add_attribute("val", "45000");
scheme_color_node.add_child("a:shade").add_attribute("val", "99000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "350000");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "100000");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:shade").add_attribute("val", "20000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "255000");
auto path_node = grad_fill_node.add_child("a:path");
path_node.add_attribute("path", "circle");
auto fill_to_rect_node = path_node.add_child("a:fillToRect");
fill_to_rect_node.add_attribute("l", "50000");
fill_to_rect_node.add_attribute("t", "-80000");
fill_to_rect_node.add_attribute("r", "50000");
fill_to_rect_node.add_attribute("b", "180000");
grad_fill_node = bg_fill_style_list_node.add_child("a:gradFill");
grad_fill_node.add_attribute("rotWithShape", "1");
grad_fill_list = grad_fill_node.add_child("a:gsLst");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "0");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:tint").add_attribute("val", "80000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "300000");
gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", "100000");
scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:shade").add_attribute("val", "30000");
scheme_color_node.add_child("a:satMod").add_attribute("val", "200000");
path_node = grad_fill_node.add_child("a:path");
path_node.add_attribute("path", "circle");
fill_to_rect_node = path_node.add_child("a:fillToRect");
fill_to_rect_node.add_attribute("l", "50000");
fill_to_rect_node.add_attribute("t", "50000");
fill_to_rect_node.add_attribute("r", "50000");
fill_to_rect_node.add_attribute("b", "50000");
theme_node.add_child("a:objectDefaults");
theme_node.add_child("a:extraClrSchemeLst");
return xml;
}
} // namespace xlnt

View File

@ -1,11 +1,15 @@
#include <xlnt/s11n/workbook_serializer.hpp>
#include <xlnt/common/datetime.hpp>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/s11n/xml_document.hpp>
#include <xlnt/s11n/xml_node.hpp>
#include <xlnt/workbook/document_properties.hpp>
#include <xlnt/workbook/manifest.hpp>
#include <xlnt/workbook/named_range.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include "detail/constants.hpp"
@ -66,15 +70,15 @@ std::vector<std::pair<std::string, std::string>> workbook_serializer::read_sheet
auto with_ns = [&](const std::string &base) { return ns.empty() ? base : ns + ":" + base; };
auto root_node = doc.child(with_ns("workbook").c_str());
auto sheets_node = root_node.child(with_ns("sheets").c_str());
auto root_node = doc.get_child(with_ns("workbook"));
auto sheets_node = root_node.get_child(with_ns("sheets"));
std::vector<std::pair<std::string, std::string>> sheets;
// store temp because pugixml iteration uses the internal char array multiple times
auto sheet_element_name = with_ns("sheet");
for(auto sheet_node : sheets_node.children(sheet_element_name.c_str()))
for(auto sheet_node : sheets_node.children(sheet_element_name))
{
std::string id = sheet_node.attribute("r:id").as_string();
std::string name = sheet_node.attribute("name").as_string();
@ -112,53 +116,6 @@ void workbook_serializer::read_properties_core(const xml_document &xml)
}
}
std::string workbook_serializer::read_dimension(const std::string &xml_string)
{
pugi::xml_document doc;
doc.load(xml_string.c_str());
auto root_node = doc.child("worksheet");
auto dimension_node = root_node.child("dimension");
std::string dimension = dimension_node.attribute("ref").as_string();
return dimension;
}
std::vector<relationship> workbook_serializer::read_relationships(zip_file &archive, const std::string &filename)
{
auto filename_separator_index = filename.find_last_of('/');
auto basename = filename.substr(filename_separator_index + 1);
auto dirname = filename.substr(0, filename_separator_index);
auto rels_filename = dirname + "/_rels/" + basename + ".rels";
pugi::xml_document doc;
auto content = archive.read(rels_filename);
doc.load(content.c_str());
auto root_node = doc.child("Relationships");
std::vector<relationship> relationships;
for(auto relationship : root_node.children("Relationship"))
{
std::string id = relationship.attribute("Id").as_string();
std::string type = relationship.attribute("Type").as_string();
std::string target = relationship.attribute("Target").as_string();
if(target[0] != '/' && target.substr(0, 2) != "..")
{
target = dirname + "/" + target;
}
if(target[0] == '/')
{
target = target.substr(1);
}
relationships.push_back(xlnt::relationship(type, id, target));
}
return relationships;
}
std::string workbook_serializer::determine_document_type(const manifest &manifest)
{
if(!manifest.has_override_type(constants::ArcWorkbook))
@ -184,22 +141,27 @@ std::string workbook_serializer::determine_document_type(const manifest &manifes
return "unsupported";
}
/// <summary>
/// Return a list of worksheets.
/// content types has a list of paths but no titles
/// workbook has a list of titles and relIds but no paths
/// workbook_rels has a list of relIds and paths but no titles
/// </summary>
std::vector<std::pair<std::string, std::string>> workbook_serializer::detect_worksheets(zip_file &archive)
{
static const std::string ValidWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
auto content_types = read_content_types(archive);
std::vector<std::string> valid_sheets;
for(const auto &content_type : content_types)
for(const auto &content_type : wb_.get_manifest().get_override_types())
{
if(content_type.second == ValidWorksheet)
if(content_type.get_content_type() == ValidWorksheet)
{
valid_sheets.push_back(content_type.first);
valid_sheets.push_back(content_type.get_part_name());
}
}
auto workbook_relationships = read_relationships(archive, "xl/workbook.xml");
auto &workbook_relationships = wb_.get_relationships();
std::vector<std::pair<std::string, std::string>> result;
for(const auto &ws : read_sheets(archive))
@ -216,456 +178,80 @@ std::vector<std::pair<std::string, std::string>> workbook_serializer::detect_wor
return result;
}
std::string workbook_serializer::write_shared_strings(const std::vector<std::string> &string_table)
xml_document workbook_serializer::write_properties_core() const
{
pugi::xml_document doc;
auto root_node = doc.append_child("sst");
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
root_node.append_attribute("uniqueCount").set_value((int)string_table.size());
auto &props = wb_.get_properties();
for(auto string : string_table)
xml_document xml;
xml.add_namespace("cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
xml.add_namespace("dc", "http://purl.org/dc/elements/1.1/");
xml.add_namespace("dcmitype", "http://purl.org/dc/dcmitype/");
xml.add_namespace("dcterms", "http://purl.org/dc/terms/");
xml.add_namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
auto &root_node = xml.root();
root_node.set_name("cp:coreProperties");
root_node.add_child("dc:creator").set_text(props.creator);
root_node.add_child("cp:lastModifiedBy").set_text(props.last_modified_by);
root_node.add_child("dcterms:created").set_text(datetime_to_w3cdtf(props.created));
root_node.get_child("dcterms:created").add_attribute("xsi:type", "dcterms:W3CDTF");
root_node.add_child("dcterms:modified").set_text(datetime_to_w3cdtf(props.modified));
root_node.get_child("dcterms:modified").add_attribute("xsi:type", "dcterms:W3CDTF");
root_node.add_child("dc:title").set_text(props.title);
root_node.add_child("dc:description");
root_node.add_child("dc:subject");
root_node.add_child("cp:keywords");
root_node.add_child("cp:category");
return xml;
}
xml_document workbook_serializer::write_properties_app() const
{
xml_document xml;
xml.add_namespace("xmlns", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
xml.add_namespace("xmlns:vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
auto &root_node = xml.root();
root_node.set_name("Properties");
root_node.add_child("Application").set_text("Microsoft Excel");
root_node.add_child("DocSecurity").set_text("0");
root_node.add_child("ScaleCrop").set_text("false");
root_node.add_child("Company");
root_node.add_child("LinksUpToDate").set_text("false");
root_node.add_child("SharedDoc").set_text("false");
root_node.add_child("HyperlinksChanged").set_text("false");
root_node.add_child("AppVersion").set_text("12.0000");
auto heading_pairs_node = root_node.add_child("HeadingPairs");
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_child("vt:variant").add_child("vt:lpstr").set_text("Worksheets");
heading_pairs_vector_node.add_child("vt:variant").add_child("vt:i4").set_text(std::to_string(wb_.get_sheet_names().size()));
auto titles_of_parts_node = root_node.add_child("TitlesOfParts");
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(wb_.get_sheet_names().size()));
for(auto ws : wb_)
{
root_node.append_child("si").append_child("t").text().set(string.c_str());
titles_of_parts_vector_node.add_child("vt:lpstr").set_text(ws.get_title());
}
std::stringstream ss;
doc.save(ss);
return ss.str();
return xml;
}
std::string workbook_serializer::write_properties_core(const document_properties &prop)
{
pugi::xml_document doc;
auto root_node = doc.append_child("cp:coreProperties");
root_node.append_attribute("xmlns:cp").set_value("http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
root_node.append_attribute("xmlns:dc").set_value("http://purl.org/dc/elements/1.1/");
root_node.append_attribute("xmlns:dcmitype").set_value("http://purl.org/dc/dcmitype/");
root_node.append_attribute("xmlns:dcterms").set_value("http://purl.org/dc/terms/");
root_node.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance");
root_node.append_child("dc:creator").text().set(prop.creator.c_str());
root_node.append_child("cp:lastModifiedBy").text().set(prop.last_modified_by.c_str());
root_node.append_child("dcterms:created").text().set(datetime_to_w3cdtf(prop.created).c_str());
root_node.child("dcterms:created").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
root_node.append_child("dcterms:modified").text().set(datetime_to_w3cdtf(prop.modified).c_str());
root_node.child("dcterms:modified").append_attribute("xsi:type").set_value("dcterms:W3CDTF");
root_node.append_child("dc:title").text().set(prop.title.c_str());
root_node.append_child("dc:description");
root_node.append_child("dc:subject");
root_node.append_child("cp:keywords");
root_node.append_child("cp:category");
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string workbook_serializer::write_worksheet_rels(worksheet ws)
{
return write_relationships(ws.get_relationships(), "");
}
std::string workbook_serializer::write_theme()
{
pugi::xml_document doc;
auto theme_node = doc.append_child("a:theme");
theme_node.append_attribute("xmlns:a").set_value(constants::Namespaces.at("drawingml").c_str());
theme_node.append_attribute("name").set_value("Office Theme");
auto theme_elements_node = theme_node.append_child("a:themeElements");
auto clr_scheme_node = theme_elements_node.append_child("a:clrScheme");
clr_scheme_node.append_attribute("name").set_value("Office");
struct scheme_element
{
std::string name;
std::string sub_element_name;
std::string val;
};
std::vector<scheme_element> scheme_elements =
{
{"a:dk1", "a:sysClr", "windowText"},
{"a:lt1", "a:sysClr", "window"},
{"a:dk2", "a:srgbClr", "1F497D"},
{"a:lt2", "a:srgbClr", "EEECE1"},
{"a:accent1", "a:srgbClr", "4F81BD"},
{"a:accent2", "a:srgbClr", "C0504D"},
{"a:accent3", "a:srgbClr", "9BBB59"},
{"a:accent4", "a:srgbClr", "8064A2"},
{"a:accent5", "a:srgbClr", "4BACC6"},
{"a:accent6", "a:srgbClr", "F79646"},
{"a:hlink", "a:srgbClr", "0000FF"},
{"a:folHlink", "a:srgbClr", "800080"},
};
for(auto element : scheme_elements)
{
auto element_node = clr_scheme_node.append_child(element.name.c_str());
element_node.append_child(element.sub_element_name.c_str()).append_attribute("val").set_value(element.val.c_str());
if(element.name == "a:dk1")
{
element_node.child(element.sub_element_name.c_str()).append_attribute("lastClr").set_value("000000");
}
else if(element.name == "a:lt1")
{
element_node.child(element.sub_element_name.c_str()).append_attribute("lastClr").set_value("FFFFFF");
}
}
struct font_scheme
{
bool typeface;
std::string script;
std::string major;
std::string minor;
};
std::vector<font_scheme> font_schemes =
{
{true, "a:latin", "Cambria", "Calibri"},
{true, "a:ea", "", ""},
{true, "a:cs", "", ""},
{false, "Jpan", "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf", "\xef\xbc\xad\xef\xbc\xb3 \xef\xbc\xb0\xe3\x82\xb4\xe3\x82\xb7\xe3\x83\x83\xe3\x82\xaf"},
{false, "Hang", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95", "\xeb\xa7\x91\xec\x9d\x80 \xea\xb3\xa0\xeb\x94\x95"},
{false, "Hans", "\xe5\xae\x8b\xe4\xbd\x93", "\xe5\xae\x8b\xe4\xbd\x93"},
{false, "Hant", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94", "\xe6\x96\xb0\xe7\xb4\xb0\xe6\x98\x8e\xe9\xab\x94"},
{false, "Arab", "Times New Roman", "Arial"},
{false, "Hebr", "Times New Roman", "Arial"},
{false, "Thai", "Tahoma", "Tahoma"},
{false, "Ethi", "Nyala", "Nyala"},
{false, "Beng", "Vrinda", "Vrinda"},
{false, "Gujr", "Shruti", "Shruti"},
{false, "Khmr", "MoolBoran", "DaunPenh"},
{false, "Knda", "Tunga", "Tunga"},
{false, "Guru", "Raavi", "Raavi"},
{false, "Cans", "Euphemia", "Euphemia"},
{false, "Cher", "Plantagenet Cherokee", "Plantagenet Cherokee"},
{false, "Yiii", "Microsoft Yi Baiti", "Microsoft Yi Baiti"},
{false, "Tibt", "Microsoft Himalaya", "Microsoft Himalaya"},
{false, "Thaa", "MV Boli", "MV Boli"},
{false, "Deva", "Mangal", "Mangal"},
{false, "Telu", "Gautami", "Gautami"},
{false, "Taml", "Latha", "Latha"},
{false, "Syrc", "Estrangelo Edessa", "Estrangelo Edessa"},
{false, "Orya", "Kalinga", "Kalinga"},
{false, "Mlym", "Kartika", "Kartika"},
{false, "Laoo", "DokChampa", "DokChampa"},
{false, "Sinh", "Iskoola Pota", "Iskoola Pota"},
{false, "Mong", "Mongolian Baiti", "Mongolian Baiti"},
{false, "Viet", "Times New Roman", "Arial"},
{false, "Uigh", "Microsoft Uighur", "Microsoft Uighur"}
};
auto font_scheme_node = theme_elements_node.append_child("a:fontScheme");
font_scheme_node.append_attribute("name").set_value("Office");
auto major_fonts_node = font_scheme_node.append_child("a:majorFont");
auto minor_fonts_node = font_scheme_node.append_child("a:minorFont");
for(auto scheme : font_schemes)
{
pugi::xml_node major_font_node, minor_font_node;
if(scheme.typeface)
{
major_font_node = major_fonts_node.append_child(scheme.script.c_str());
minor_font_node = minor_fonts_node.append_child(scheme.script.c_str());
}
else
{
major_font_node = major_fonts_node.append_child("a:font");
major_font_node.append_attribute("script").set_value(scheme.script.c_str());
minor_font_node = minor_fonts_node.append_child("a:font");
minor_font_node.append_attribute("script").set_value(scheme.script.c_str());
}
major_font_node.append_attribute("typeface").set_value(scheme.major.c_str());
minor_font_node.append_attribute("typeface").set_value(scheme.minor.c_str());
}
auto format_scheme_node = theme_elements_node.append_child("a:fmtScheme");
format_scheme_node.append_attribute("name").set_value("Office");
auto fill_style_list_node = format_scheme_node.append_child("a:fillStyleLst");
fill_style_list_node.append_child("a:solidFill").append_child("a:schemeClr").append_attribute("val").set_value("phClr");
auto grad_fill_node = fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
auto grad_fill_list = grad_fill_node.append_child("a:gsLst");
auto gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
auto scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(50000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(35000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(37000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(15000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
auto lin_node = grad_fill_node.append_child("a:lin");
lin_node.append_attribute("ang").set_value(16200000);
lin_node.append_attribute("scaled").set_value(1);
grad_fill_node = fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(51000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(130000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(80000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(93000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(130000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(94000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(135000);
lin_node = grad_fill_node.append_child("a:lin");
lin_node.append_attribute("ang").set_value(16200000);
lin_node.append_attribute("scaled").set_value(0);
auto line_style_list_node = format_scheme_node.append_child("a:lnStyleLst");
auto ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(9525);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
auto solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(95000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(105000);
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(25400);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
ln_node = line_style_list_node.append_child("a:ln");
ln_node.append_attribute("w").set_value(38100);
ln_node.append_attribute("cap").set_value("flat");
ln_node.append_attribute("cmpd").set_value("sng");
ln_node.append_attribute("algn").set_value("ctr");
solid_fill_node = ln_node.append_child("a:solidFill");
scheme_color_node = solid_fill_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid");
auto effect_style_list_node = format_scheme_node.append_child("a:effectStyleLst");
auto effect_style_node = effect_style_list_node.append_child("a:effectStyle");
auto effect_list_node = effect_style_node.append_child("a:effectLst");
auto outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(20000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
auto srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(38000);
effect_style_node = effect_style_list_node.append_child("a:effectStyle");
effect_list_node = effect_style_node.append_child("a:effectLst");
outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(23000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(35000);
effect_style_node = effect_style_list_node.append_child("a:effectStyle");
effect_list_node = effect_style_node.append_child("a:effectLst");
outer_shadow_node = effect_list_node.append_child("a:outerShdw");
outer_shadow_node.append_attribute("blurRad").set_value(40000);
outer_shadow_node.append_attribute("dist").set_value(23000);
outer_shadow_node.append_attribute("dir").set_value(5400000);
outer_shadow_node.append_attribute("rotWithShape").set_value(0);
srgb_clr_node = outer_shadow_node.append_child("a:srgbClr");
srgb_clr_node.append_attribute("val").set_value("000000");
srgb_clr_node.append_child("a:alpha").append_attribute("val").set_value(35000);
auto scene3d_node = effect_style_node.append_child("a:scene3d");
auto camera_node = scene3d_node.append_child("a:camera");
camera_node.append_attribute("prst").set_value("orthographicFront");
auto rot_node = camera_node.append_child("a:rot");
rot_node.append_attribute("lat").set_value(0);
rot_node.append_attribute("lon").set_value(0);
rot_node.append_attribute("rev").set_value(0);
auto light_rig_node = scene3d_node.append_child("a:lightRig");
light_rig_node.append_attribute("rig").set_value("threePt");
light_rig_node.append_attribute("dir").set_value("t");
rot_node = light_rig_node.append_child("a:rot");
rot_node.append_attribute("lat").set_value(0);
rot_node.append_attribute("lon").set_value(0);
rot_node.append_attribute("rev").set_value(1200000);
auto bevel_node = effect_style_node.append_child("a:sp3d").append_child("a:bevelT");
bevel_node.append_attribute("w").set_value(63500);
bevel_node.append_attribute("h").set_value(25400);
auto bg_fill_style_list_node = format_scheme_node.append_child("a:bgFillStyleLst");
bg_fill_style_list_node.append_child("a:solidFill").append_child("a:schemeClr").append_attribute("val").set_value("phClr");
grad_fill_node = bg_fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(40000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(40000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(45000);
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(99000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(350000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(20000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(255000);
auto path_node = grad_fill_node.append_child("a:path");
path_node.append_attribute("path").set_value("circle");
auto fill_to_rect_node = path_node.append_child("a:fillToRect");
fill_to_rect_node.append_attribute("l").set_value(50000);
fill_to_rect_node.append_attribute("t").set_value(-80000);
fill_to_rect_node.append_attribute("r").set_value(50000);
fill_to_rect_node.append_attribute("b").set_value(180000);
grad_fill_node = bg_fill_style_list_node.append_child("a:gradFill");
grad_fill_node.append_attribute("rotWithShape").set_value(1);
grad_fill_list = grad_fill_node.append_child("a:gsLst");
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(0);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:tint").append_attribute("val").set_value(80000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(300000);
gs_node = grad_fill_list.append_child("a:gs");
gs_node.append_attribute("pos").set_value(100000);
scheme_color_node = gs_node.append_child("a:schemeClr");
scheme_color_node.append_attribute("val").set_value("phClr");
scheme_color_node.append_child("a:shade").append_attribute("val").set_value(30000);
scheme_color_node.append_child("a:satMod").append_attribute("val").set_value(200000);
path_node = grad_fill_node.append_child("a:path");
path_node.append_attribute("path").set_value("circle");
fill_to_rect_node = path_node.append_child("a:fillToRect");
fill_to_rect_node.append_attribute("l").set_value(50000);
fill_to_rect_node.append_attribute("t").set_value(50000);
fill_to_rect_node.append_attribute("r").set_value(50000);
fill_to_rect_node.append_attribute("b").set_value(50000);
theme_node.append_child("a:objectDefaults");
theme_node.append_child("a:extraClrSchemeLst");
std::stringstream ss;
doc.print(ss);
return ss.str();
}
std::string write_properties_app(const workbook &wb)
{
pugi::xml_document doc;
auto root_node = doc.append_child("Properties");
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
root_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
root_node.append_child("Application").text().set("Microsoft Excel");
root_node.append_child("DocSecurity").text().set("0");
root_node.append_child("ScaleCrop").text().set("false");
root_node.append_child("Company");
root_node.append_child("LinksUpToDate").text().set("false");
root_node.append_child("SharedDoc").text().set("false");
root_node.append_child("HyperlinksChanged").text().set("false");
root_node.append_child("AppVersion").text().set("12.0000");
auto heading_pairs_node = root_node.append_child("HeadingPairs");
auto heading_pairs_vector_node = heading_pairs_node.append_child("vt:vector");
heading_pairs_vector_node.append_attribute("baseType").set_value("variant");
heading_pairs_vector_node.append_attribute("size").set_value("2");
heading_pairs_vector_node.append_child("vt:variant").append_child("vt:lpstr").text().set("Worksheets");
heading_pairs_vector_node.append_child("vt:variant").append_child("vt:i4").text().set(std::to_string(wb.get_sheet_names().size()).c_str());
auto titles_of_parts_node = root_node.append_child("TitlesOfParts");
auto titles_of_parts_vector_node = titles_of_parts_node.append_child("vt:vector");
titles_of_parts_vector_node.append_attribute("baseType").set_value("lpstr");
titles_of_parts_vector_node.append_attribute("size").set_value(std::to_string(wb.get_sheet_names().size()).c_str());
for(auto ws : wb)
{
titles_of_parts_vector_node.append_child("vt:lpstr").text().set(ws.get_title().c_str());
}
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string write_root_rels(const workbook &)
{
std::vector<relationship> relationships;
relationships.push_back(relationship(relationship::type::extended_properties, "rId3", "docProps/app.xml"));
relationships.push_back(relationship(relationship::type::core_properties, "rId2", "docProps/core.xml"));
relationships.push_back(relationship(relationship::type::office_document, "rId1", "xl/workbook.xml"));
return write_relationships(relationships, "");
}
std::string write_workbook(const workbook &wb)
xml_document workbook_serializer::write_workbook() const
{
std::size_t num_visible = 0;
for(auto ws : wb)
for(auto ws : wb_)
{
if(ws.get_page_setup().get_sheet_state() == xlnt::page_setup::sheet_state::visible)
{
@ -675,41 +261,44 @@ std::string write_workbook(const workbook &wb)
if(num_visible == 0)
{
throw value_error();
throw xlnt::value_error();
}
pugi::xml_document doc;
auto root_node = doc.append_child("workbook");
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
root_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
xml_document xml;
auto file_version_node = root_node.append_child("fileVersion");
file_version_node.append_attribute("appName").set_value("xl");
file_version_node.append_attribute("lastEdited").set_value("4");
file_version_node.append_attribute("lowestEdited").set_value("4");
file_version_node.append_attribute("rupBuild").set_value("4505");
xml.add_namespace("xmlns", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
xml.add_namespace("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
auto workbook_pr_node = root_node.append_child("workbookPr");
workbook_pr_node.append_attribute("codeName").set_value("ThisWorkbook");
workbook_pr_node.append_attribute("defaultThemeVersion").set_value("124226");
workbook_pr_node.append_attribute("date1904").set_value(wb.get_properties().excel_base_date == calendar::mac_1904 ? 1 : 0);
auto &root_node = xml.root();
root_node.set_name("workbook");
auto book_views_node = root_node.append_child("bookViews");
auto workbook_view_node = book_views_node.append_child("workbookView");
workbook_view_node.append_attribute("activeTab").set_value("0");
workbook_view_node.append_attribute("autoFilterDateGrouping").set_value("1");
workbook_view_node.append_attribute("firstSheet").set_value("0");
workbook_view_node.append_attribute("minimized").set_value("0");
workbook_view_node.append_attribute("showHorizontalScroll").set_value("1");
workbook_view_node.append_attribute("showSheetTabs").set_value("1");
workbook_view_node.append_attribute("showVerticalScroll").set_value("1");
workbook_view_node.append_attribute("tabRatio").set_value("600");
workbook_view_node.append_attribute("visibility").set_value("visible");
auto &file_version_node = root_node.add_child("fileVersion");
file_version_node.add_attribute("appName", "xl");
file_version_node.add_attribute("lastEdited", "4");
file_version_node.add_attribute("lowestEdited", "4");
file_version_node.add_attribute("rupBuild", "4505");
auto sheets_node = root_node.append_child("sheets");
auto defined_names_node = root_node.append_child("definedNames");
auto &workbook_pr_node = root_node.add_child("workbookPr");
workbook_pr_node.add_attribute("codeName", "ThisWorkbook");
workbook_pr_node.add_attribute("defaultThemeVersion", "124226");
workbook_pr_node.add_attribute("date1904", wb_.get_properties().excel_base_date == calendar::mac_1904 ? "1" : "0");
for(auto relationship : wb.get_relationships())
auto book_views_node = root_node.add_child("bookViews");
auto workbook_view_node = book_views_node.add_child("workbookView");
workbook_view_node.add_attribute("activeTab", "0");
workbook_view_node.add_attribute("autoFilterDateGrouping", "1");
workbook_view_node.add_attribute("firstSheet", "0");
workbook_view_node.add_attribute("minimized", "0");
workbook_view_node.add_attribute("showHorizontalScroll", "1");
workbook_view_node.add_attribute("showSheetTabs", "1");
workbook_view_node.add_attribute("showVerticalScroll", "1");
workbook_view_node.add_attribute("tabRatio", "600");
workbook_view_node.add_attribute("visibility", "visible");
auto sheets_node = root_node.add_child("sheets");
auto defined_names_node = root_node.add_child("definedNames");
for(auto relationship : wb_.get_relationships())
{
if(relationship.get_type() == relationship::type::worksheet)
{
@ -723,55 +312,41 @@ std::string write_workbook(const workbook &wb)
sheet_index_string = sheet_index_string.substr(static_cast<std::string::size_type>(first_digit + 1));
std::size_t sheet_index = static_cast<std::size_t>(std::stoll(sheet_index_string) - 1);
auto ws = wb.get_sheet_by_index(sheet_index);
auto ws = wb_.get_sheet_by_index(sheet_index);
auto sheet_node = sheets_node.append_child("sheet");
sheet_node.append_attribute("name").set_value(ws.get_title().c_str());
sheet_node.append_attribute("r:id").set_value(relationship.get_id().c_str());
sheet_node.append_attribute("sheetId").set_value(std::to_string(sheet_index + 1).c_str());
auto sheet_node = sheets_node.add_child("sheet");
sheet_node.add_attribute("name", ws.get_title());
sheet_node.add_attribute("r:id", relationship.get_id());
sheet_node.add_attribute("sheetId", std::to_string(sheet_index + 1));
if(ws.has_auto_filter())
{
auto defined_name_node = defined_names_node.append_child("definedName");
defined_name_node.append_attribute("name").set_value("_xlnm._FilterDatabase");
defined_name_node.append_attribute("hidden").set_value(1);
defined_name_node.append_attribute("localSheetId").set_value(0);
auto &defined_name_node = defined_names_node.add_child("definedName");
defined_name_node.add_attribute("name", "_xlnm._FilterDatabase");
defined_name_node.add_attribute("hidden", "1");
defined_name_node.add_attribute("localSheetId", "0");
std::string name = "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string();
defined_name_node.text().set(name.c_str());
defined_name_node.set_text(name);
}
}
}
auto calc_pr_node = root_node.append_child("calcPr");
calc_pr_node.append_attribute("calcId").set_value("124519");
calc_pr_node.append_attribute("calcMode").set_value("auto");
calc_pr_node.append_attribute("fullCalcOnLoad").set_value("1");
auto calc_pr_node = root_node.add_child("calcPr");
calc_pr_node.add_attribute("calcId", "124519");
calc_pr_node.add_attribute("calcMode", "auto");
calc_pr_node.add_attribute("fullCalcOnLoad", "1");
std::stringstream ss;
doc.save(ss);
return ss.str();
}
std::string workbook_serializer::write_workbook_rels(const workbook &wb)
{
return write_relationships(wb.get_relationships(), "xl/");
return xml;
}
std::string workbook_serializer::write_defined_names(const xlnt::workbook &wb)
bool workbook_serializer::write_named_ranges(xlnt::xml_node &named_ranges_node)
{
pugi::xml_document doc;
auto names = doc.root().append_child("names");
for(auto named_range : wb.get_named_ranges())
for(auto &named_range : wb_.get_named_ranges())
{
names.append_child(named_range.get_name().c_str());
named_ranges_node.add_child(named_range.get_name());
}
std::ostringstream stream;
doc.save(stream);
return stream.str();
return true;
}
} // namespace xlnt

View File

@ -1,8 +1,11 @@
#include <sstream>
#include <xlnt/s11n/worksheet_serializer.hpp>
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/cell_reference.hpp>
#include <xlnt/s11n/xml_document.hpp>
#include <xlnt/s11n/xml_node.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/range_reference.hpp>
@ -18,10 +21,193 @@ bool is_integral(long double d)
} // namepsace
namespace xlnt {
bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector<std::string> &string_table, xml_document &xml)
bool worksheet_serializer::read_worksheet(const xml_document &xml, const std::vector<std::string> &string_table, const relationship &rel)
{
ws.get_cell("A1");
auto &root_node = xml.root();
auto &dimension_node = root_node.get_child("dimension");
std::string dimension = dimension_node.get_attribute("ref");
auto full_range = xlnt::range_reference(dimension);
auto sheet_data_node = root_node.get_child("sheetData");
if(root_node.has_child("mergeCells"))
{
auto merge_cells_node = root_node.get_child("mergeCells");
auto count = std::stoull(merge_cells_node.get_attribute("count"));
for(auto merge_cell_node : merge_cells_node.get_children())
{
if(merge_cell_node.get_name() != "mergeCell")
{
continue;
}
sheet_.merge_cells(merge_cell_node.get_attribute("ref"));
count--;
}
if(count != 0)
{
throw std::runtime_error("mismatch between count and actual number of merged cells");
}
}
for(auto row_node : sheet_data_node.get_children())
{
if(row_node.get_name() != "row")
{
continue;
}
auto row_index = static_cast<row_t>(std::stoull(row_node.get_attribute("r")));
if(row_node.get_attribute("ht") != nullptr)
{
sheet_.get_row_properties(row_index).height = std::stold(row_node.get_attribute("ht"));
}
std::string span_string = row_node.get_attribute("spans");
auto colon_index = span_string.find(':');
column_t min_column = 0;
column_t max_column = 0;
if(colon_index != std::string::npos)
{
min_column = static_cast<column_t>(std::stoll(span_string.substr(0, colon_index)));
max_column = static_cast<column_t>(std::stoll(span_string.substr(colon_index + 1)));
}
else
{
min_column = static_cast<column_t>(full_range.get_top_left().get_column_index());
max_column = static_cast<column_t>(full_range.get_bottom_right().get_column_index());
}
for(column_t i = min_column; i <= max_column; i++)
{
std::string address = xlnt::cell_reference::column_string_from_index(i) + std::to_string(row_index);
xml_node cell_node;
bool cell_found = false;
for(auto &check_cell_node : row_node.get_children())
{
if(check_cell_node.get_name() != "c")
{
continue;
}
if(check_cell_node.has_attribute("r") && check_cell_node.get_attribute("r") == address)
{
cell_node = check_cell_node;
cell_found = true;
break;
}
}
if(cell_found)
{
bool has_value = cell_node.has_child("v");
std::string value_string = has_value ? cell_node.get_child("v").get_text() : "";
bool has_type = cell_node.get_attribute("t") != nullptr;
std::string type = has_type ? cell_node.get_attribute("t") : "";
bool has_style = cell_node.get_attribute("s") != nullptr;
int style_id = has_style ? std::stoull(cell_node.get_attribute("s")) : 0;
bool has_formula = cell_node.has_child("f");
bool has_shared_formula = has_formula && cell_node.get_child("f").has_attribute("t") && cell_node.get_child("f").get_attribute("t") == "shared";
auto cell = sheet_.get_cell(address);
if(has_formula && !has_shared_formula && !sheet_.get_parent().get_data_only())
{
std::string formula = cell_node.get_child("f").get_text();
cell.set_formula(formula);
}
if(has_type && type == "inlineStr") // inline string
{
std::string inline_string = cell_node.get_child("is").get_child("t").get_text();
cell.set_value(inline_string);
}
else if(has_type && type == "s" && !has_formula) // shared string
{
auto shared_string_index = std::stoull(value_string);
auto shared_string = string_table.at(shared_string_index);
cell.set_value(shared_string);
}
else if(has_type && type == "b") // boolean
{
cell.set_value(value_string != "0");
}
else if(has_type && type == "str")
{
cell.set_value(value_string);
}
else if(has_value && !value_string.empty())
{
if(!value_string.empty() && value_string[0] == '#')
{
cell.set_error(value_string);
}
else
{
cell.set_value(std::stold(value_string));
}
}
if(has_style)
{
cell.set_style_id(style_id);
}
}
}
}
auto &cols_node = root_node.get_child("cols");
for(auto col_node : cols_node.get_children())
{
if(col_node.get_name() != "col")
{
continue;
}
auto min = static_cast<column_t>(std::stoull(col_node.get_attribute("min")));
auto max = static_cast<column_t>(std::stoull(col_node.get_attribute("max")));
auto width = std::stold(col_node.get_attribute("width"));
auto column_style = std::stoull(col_node.get_attribute("style"));
bool custom = col_node.get_attribute("customWidth") == "1";
for(auto column = min; column <= max; column++)
{
if(!sheet_.has_column_properties(column))
{
sheet_.add_column_properties(column, column_properties());
}
sheet_.get_column_properties(min).width = width;
sheet_.get_column_properties(min).style = column_style;
sheet_.get_column_properties(min).custom = custom;
}
}
if(root_node.has_child("autoFilter"))
{
auto &auto_filter_node = root_node.get_child("autoFilter");
xlnt::range_reference ref(auto_filter_node.get_attribute("ref"));
sheet_.auto_filter(ref);
}
return true;
}
bool worksheet_serializer::write_worksheet(const std::vector<std::string> &string_table, xml_document &xml)
{
sheet_.get_cell("A1");
xml.add_namespace("", constants::Namespaces.at("spreadsheetml"));
xml.add_namespace("r", constants::Namespaces.at("r"));
@ -31,10 +217,10 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
auto &sheet_pr_node = root_node.add_child("sheetPr");
if(!ws.get_page_setup().is_default())
if(!sheet_.get_page_setup().is_default())
{
auto &page_set_up_pr_node = sheet_pr_node.add_child("pageSetUpPr");
page_set_up_pr_node.add_attribute("fitToPage", ws.get_page_setup().fit_to_page() ? "1" : "0");
page_set_up_pr_node.add_attribute("fitToPage", sheet_.get_page_setup().fit_to_page() ? "1" : "0");
}
auto &outline_pr_node = sheet_pr_node.add_child("outlinePr");
@ -43,7 +229,7 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
outline_pr_node.add_attribute("summaryRight", "1");
auto &dimension_node = root_node.add_child("dimension");
dimension_node.add_attribute("ref", ws.calculate_dimension().to_string());
dimension_node.add_attribute("ref", sheet_.calculate_dimension().to_string());
auto &sheet_views_node = root_node.add_child("sheetViews");
auto &sheet_view_node = sheet_views_node.add_child("sheetView");
@ -51,23 +237,23 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
std::string active_pane = "bottomRight";
if(ws.has_frozen_panes())
if(sheet_.has_frozen_panes())
{
auto pane_node = sheet_view_node.add_child("pane");
if(ws.get_frozen_panes().get_column_index() > 1)
if(sheet_.get_frozen_panes().get_column_index() > 1)
{
pane_node.add_attribute("xSplit", std::to_string(ws.get_frozen_panes().get_column_index() - 1));
pane_node.add_attribute("xSplit", std::to_string(sheet_.get_frozen_panes().get_column_index() - 1));
active_pane = "topRight";
}
if(ws.get_frozen_panes().get_row() > 1)
if(sheet_.get_frozen_panes().get_row() > 1)
{
pane_node.add_attribute("ySplit", std::to_string(ws.get_frozen_panes().get_row() - 1));
pane_node.add_attribute("ySplit", std::to_string(sheet_.get_frozen_panes().get_row() - 1));
active_pane = "bottomLeft";
}
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
if(sheet_.get_frozen_panes().get_row() > 1 && sheet_.get_frozen_panes().get_column_index() > 1)
{
auto top_right_node = sheet_view_node.add_child("selection");
top_right_node.add_attribute("pane", "topRight");
@ -76,24 +262,24 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
active_pane = "bottomRight";
}
pane_node.add_attribute("topLeftCell", ws.get_frozen_panes().to_string());
pane_node.add_attribute("topLeftCell", sheet_.get_frozen_panes().to_string());
pane_node.add_attribute("activePane", active_pane);
pane_node.add_attribute("state", "frozen");
}
auto selection_node = sheet_view_node.add_child("selection");
if(ws.has_frozen_panes())
if(sheet_.has_frozen_panes())
{
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
if(sheet_.get_frozen_panes().get_row() > 1 && sheet_.get_frozen_panes().get_column_index() > 1)
{
selection_node.add_attribute("pane", "bottomRight");
}
else if(ws.get_frozen_panes().get_row() > 1)
else if(sheet_.get_frozen_panes().get_row() > 1)
{
selection_node.add_attribute("pane", "bottomLeft");
}
else if(ws.get_frozen_panes().get_column_index() > 1)
else if(sheet_.get_frozen_panes().get_column_index() > 1)
{
selection_node.add_attribute("pane", "topRight");
}
@ -109,9 +295,9 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
bool has_column_properties = false;
for(auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++)
for(auto column = sheet_.get_lowest_column(); column <= sheet_.get_highest_column(); column++)
{
if(ws.has_column_properties(column))
if(sheet_.has_column_properties(column))
{
has_column_properties = true;
break;
@ -122,9 +308,9 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
{
auto cols_node = root_node.add_child("cols");
for(auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++)
for(auto column = sheet_.get_lowest_column(); column <= sheet_.get_highest_column(); column++)
{
const auto &props = ws.get_column_properties(column);
const auto &props = sheet_.get_column_properties(column);
auto col_node = cols_node.add_child("col");
@ -140,7 +326,7 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
auto sheet_data_node = root_node.add_child("sheetData");
for(auto row : ws.rows())
for(auto row : sheet_.rows())
{
row_t min = static_cast<row_t>(row.num_cells());
row_t max = 0;
@ -167,10 +353,10 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
row_node.add_attribute("r", std::to_string(row.front().get_row()));
row_node.add_attribute("spans", (std::to_string(min) + ":" + std::to_string(max)));
if(ws.has_row_properties(row.front().get_row()))
if(sheet_.has_row_properties(row.front().get_row()))
{
row_node.add_attribute("customHeight", "1");
auto height = ws.get_row_properties(row.front().get_row()).height;
auto height = sheet_.get_row_properties(row.front().get_row()).height;
if(height == std::floor(height))
{
@ -228,14 +414,14 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
{
cell_node.add_attribute("t", "inlineStr");
auto inline_string_node = cell_node.add_child("is");
inline_string_node.add_child("t").text().set(cell.get_value<std::string>());
inline_string_node.add_child("t").set_text(cell.get_value<std::string>());
}
}
else
{
cell_node.add_attribute("t", "s");
auto value_node = cell_node.add_child("v");
value_node.text().set(match_index);
value_node.set_text(std::to_string(match_index));
}
}
else
@ -246,22 +432,23 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
{
cell_node.add_attribute("t", "b");
auto value_node = cell_node.add_child("v");
value_node.text().set(cell.get_value<bool>() ? 1 : 0);
value_node.set_text(cell.get_value<bool>() ? "1" : "0");
}
else if(cell.get_data_type() == cell::type::numeric)
{
if(cell.has_formula())
{
cell_node.add_child("f").text().set(cell.get_formula());
cell_node.add_child("v").text().set(cell.to_string());
cell_node.add_child("f").set_text(cell.get_formula());
cell_node.add_child("v").set_text(cell.to_string());
continue;
}
cell_node.add_attribute("t", "n");
auto value_node = cell_node.add_child("v");
if(is_integral(cell.get_value<long double>()))
{
value_node.text().set(cell.get_value<long long>());
value_node.set_text(std::to_string(cell.get_value<long long>()));
}
else
{
@ -269,50 +456,49 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
ss.precision(20);
ss << cell.get_value<long double>();
ss.str();
value_node.text().set(ss.str());
value_node.set_text(ss.str());
}
}
}
else if(cell.has_formula())
{
cell_node.add_child("f").text().set(cell.get_formula());
cell_node.add_child("f").set_text(cell.get_formula());
cell_node.add_child("v");
continue;
}
}
//if(cell.has_style())
if(cell.has_style())
{
auto style_id = cell.get_style_id();
cell_node.add_attribute("s", (int)style_id);
cell_node.add_attribute("s", std::to_string(cell.get_style_id()));
}
}
}
}
if(ws.has_auto_filter())
if(sheet_.has_auto_filter())
{
auto auto_filter_node = root_node.add_child("autoFilter");
auto_filter_node.add_attribute("ref", ws.get_auto_filter().to_string());
auto_filter_node.add_attribute("ref", sheet_.get_auto_filter().to_string());
}
if(!ws.get_merged_ranges().empty())
if(!sheet_.get_merged_ranges().empty())
{
auto merge_cells_node = root_node.add_child("mergeCells");
merge_cells_node.add_attribute("count", (unsigned int)ws.get_merged_ranges().size());
merge_cells_node.add_attribute("count", std::to_string(sheet_.get_merged_ranges().size()));
for(auto merged_range : ws.get_merged_ranges())
for(auto merged_range : sheet_.get_merged_ranges())
{
auto merge_cell_node = merge_cells_node.add_child("mergeCell");
merge_cell_node.add_attribute("ref", merged_range.to_string());
}
}
if(!ws.get_relationships().empty())
if(!sheet_.get_relationships().empty())
{
auto hyperlinks_node = root_node.add_child("hyperlinks");
for(auto relationship : ws.get_relationships())
for(const auto &relationship : sheet_.get_relationships())
{
auto hyperlink_node = hyperlinks_node.add_child("hyperlink");
hyperlink_node.add_attribute("display", relationship.get_target_uri());
@ -321,48 +507,45 @@ bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector
}
}
if(!ws.get_page_setup().is_default())
if(!sheet_.get_page_setup().is_default())
{
auto print_options_node = root_node.add_child("printOptions");
print_options_node.add_attribute("horizontalCentered", ws.get_page_setup().get_horizontal_centered() ? 1 : 0);
print_options_node.add_attribute("verticalCentered", ws.get_page_setup().get_vertical_centered() ? 1 : 0);
print_options_node.add_attribute("horizontalCentered", sheet_.get_page_setup().get_horizontal_centered() ? "1" : "0");
print_options_node.add_attribute("verticalCentered", sheet_.get_page_setup().get_vertical_centered() ? "1" : "0");
}
auto page_margins_node = root_node.add_child("pageMargins");
page_margins_node.add_attribute("left", ws.get_page_margins().get_left());
page_margins_node.add_attribute("right", ws.get_page_margins().get_right());
page_margins_node.add_attribute("top", ws.get_page_margins().get_top());
page_margins_node.add_attribute("bottom", ws.get_page_margins().get_bottom());
page_margins_node.add_attribute("header", ws.get_page_margins().get_header());
page_margins_node.add_attribute("footer", ws.get_page_margins().get_footer());
page_margins_node.add_attribute("left", std::to_string(sheet_.get_page_margins().get_left()));
page_margins_node.add_attribute("right", std::to_string(sheet_.get_page_margins().get_right()));
page_margins_node.add_attribute("top", std::to_string(sheet_.get_page_margins().get_top()));
page_margins_node.add_attribute("bottom", std::to_string(sheet_.get_page_margins().get_bottom()));
page_margins_node.add_attribute("header", std::to_string(sheet_.get_page_margins().get_header()));
page_margins_node.add_attribute("footer", std::to_string(sheet_.get_page_margins().get_footer()));
if(!ws.get_page_setup().is_default())
if(!sheet_.get_page_setup().is_default())
{
auto page_setup_node = root_node.add_child("pageSetup");
std::string orientation_string = ws.get_page_setup().get_orientation() == page_setup::orientation::landscape ? "landscape" : "portrait";
std::string orientation_string = sheet_.get_page_setup().get_orientation() == page_setup::orientation::landscape ? "landscape" : "portrait";
page_setup_node.add_attribute("orientation", orientation_string);
page_setup_node.add_attribute("paperSize", (int)ws.get_page_setup().get_paper_size());
page_setup_node.add_attribute("fitToHeight", ws.get_page_setup().fit_to_height() ? 1 : 0);
page_setup_node.add_attribute("fitToWidth", ws.get_page_setup().fit_to_width() ? 1 : 0);
page_setup_node.add_attribute("paperSize", std::to_string(static_cast<int>(sheet_.get_page_setup().get_paper_size())));
page_setup_node.add_attribute("fitToHeight", sheet_.get_page_setup().fit_to_height() ? "1" : "0");
page_setup_node.add_attribute("fitToWidth", sheet_.get_page_setup().fit_to_width() ? "1" : "0");
}
if(!ws.get_header_footer().is_default())
if(!sheet_.get_header_footer().is_default())
{
auto header_footer_node = root_node.add_child("headerFooter");
auto odd_header_node = header_footer_node.add_child("oddHeader");
std::string header_text = "&L&\"Calibri,Regular\"&K000000Left Header Text&C&\"Arial,Regular\"&6&K445566Center Header Text&R&\"Arial,Bold\"&8&K112233Right Header Text";
odd_header_node.text().set(header_text);
odd_header_node.set_text(header_text);
auto odd_footer_node = header_footer_node.add_child("oddFooter");
std::string footer_text = "&L&\"Times New Roman,Regular\"&10&K445566Left Footer Text_x000D_And &D and &T&C&\"Times New Roman,Bold\"&12&K778899Center Footer Text &Z&F on &A&R&\"Times New Roman,Italic\"&14&KAABBCCRight Footer Text &P of &N";
odd_footer_node.text().set(footer_text);
odd_footer_node.set_text(footer_text);
}
std::stringstream ss;
doc.save(ss);
return ss.str();
return true;
}
} // namespace xlnt

View File

@ -68,13 +68,13 @@ void xml_node::add_attribute(const std::string &name, const std::string &value)
bool xml_node::has_attribute(const std::string &attribute_name) const
{
return std::find(attributes_.begin(), attributes_.end(),
return std::find_if(attributes_.begin(), attributes_.end(),
[&](const string_pair &p) { return p.first == attribute_name; }) != attributes_.end();
}
std::string xml_node::get_attribute(const std::string &attribute_name) const
{
auto match = std::find(attributes_.begin(), attributes_.end(),
auto match = std::find_if(attributes_.begin(), attributes_.end(),
[&](const string_pair &p) { return p.first == attribute_name; });
if(match == attributes_.end())
@ -87,16 +87,29 @@ std::string xml_node::get_attribute(const std::string &attribute_name) const
bool xml_node::has_child(const std::string &child_name) const
{
return std::find(children_.begin(), children_.end(),
return std::find_if(children_.begin(), children_.end(),
[&](const xml_node &n) { return n.get_name() == child_name; }) != children_.end();
}
xml_node &xml_node::get_child(const std::string &child_name)
{
auto match = std::find_if(children_.begin(), children_.end(),
[&](const xml_node &n) { return n.get_name() == child_name; });
if(match == children_.end())
{
throw std::runtime_error("child doesn't exist: " + child_name);
}
return *match;
}
const xml_node &xml_node::get_child(const std::string &child_name) const
{
auto match = std::find(children_.begin(), children_.end(),
auto match = std::find_if(children_.begin(), children_.end(),
[&](const xml_node &n) { return n.get_name() == child_name; });
if(match == attributes_.end())
if(match == children_.end())
{
throw std::runtime_error("child doesn't exist: " + child_name);
}

View File

@ -12,19 +12,21 @@
#include <xlnt/common/relationship.hpp>
#include <xlnt/common/zip_file.hpp>
#include <xlnt/drawing/drawing.hpp>
#include <xlnt/reader/excel_reader.hpp>
#include <xlnt/s11n/excel_serializer.hpp>
#include <xlnt/styles/alignment.hpp>
#include <xlnt/styles/border.hpp>
#include <xlnt/styles/fill.hpp>
#include <xlnt/styles/font.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/styles/protection.hpp>
#include <xlnt/styles/style.hpp>
#include <xlnt/workbook/document_properties.hpp>
#include <xlnt/workbook/manifest.hpp>
#include <xlnt/workbook/named_range.hpp>
#include <xlnt/workbook/theme.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/writer/excel_writer.hpp>
#include "detail/cell_impl.hpp"
#include "detail/include_pugixml.hpp"
@ -243,22 +245,25 @@ range workbook::get_named_range(const std::string &name)
bool workbook::load(std::istream &stream)
{
*this = excel_reader::load_workbook(stream);
excel_serializer serializer_(*this);
serializer_.load_stream_workbook(stream);
return true;
}
bool workbook::load(const std::vector<unsigned char> &data)
{
*this = excel_reader::load_workbook(data);
excel_serializer serializer_(*this);
serializer_.load_virtual_workbook(data);
return true;
}
bool workbook::load(const std::string &filename)
{
*this = excel_reader::load_workbook(filename);
excel_serializer serializer_(*this);
serializer_.load_workbook(filename);
return true;
}
@ -446,13 +451,18 @@ void workbook::clear()
bool workbook::save(std::vector<unsigned char> &data)
{
data = save_virtual_workbook(*this);
excel_serializer serializer(*this);
serializer.save_virtual_workbook(data);
return true;
}
bool workbook::save(const std::string &filename)
{
return save_workbook(*this, filename);
excel_serializer serializer(*this);
serializer.save_workbook(filename);
return true;
}
bool workbook::operator==(std::nullptr_t) const
@ -465,7 +475,7 @@ bool workbook::operator==(const workbook &rhs) const
return d_.get() == rhs.d_.get();
}
std::vector<relationship> xlnt::workbook::get_relationships() const
const std::vector<relationship> &xlnt::workbook::get_relationships() const
{
return d_->relationships_;
}
@ -570,14 +580,14 @@ void workbook::set_code_name(const std::string &/*code_name*/)
}
bool workbook::has_loaded_theme()
bool workbook::has_loaded_theme() const
{
return false;
}
std::string workbook::get_loaded_theme()
const theme &workbook::get_loaded_theme() const
{
return "";
return d_->theme_;
}
std::vector<named_range> workbook::get_named_ranges() const
@ -847,4 +857,16 @@ const manifest &workbook::get_manifest() const
return d_->manifest_;
}
const std::vector<relationship> &workbook::get_root_relationships() const
{
if(d_->root_relationships_.empty())
{
d_->root_relationships_.push_back(relationship(relationship::type::extended_properties, "rId3", "docProps/app.xml"));
d_->root_relationships_.push_back(relationship(relationship::type::core_properties, "rId2", "docProps/core.xml"));
d_->root_relationships_.push_back(relationship(relationship::type::office_document, "rId1", "xl/workbook.xml"));
}
return d_->root_relationships_;
}
} // namespace xlnt

View File

@ -330,7 +330,7 @@ const range worksheet::get_squared_range(column_t min_col, row_t min_row, column
return get_range(reference);
}
std::vector<relationship> worksheet::get_relationships()
const std::vector<relationship> &worksheet::get_relationships() const
{
return d_->relationships_;
}

View File

@ -1,7 +1,6 @@
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/cell_reference.hpp>
#include <xlnt/common/zip_file.hpp>
#include <xlnt/reader/worksheet_reader.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range_reference.hpp>
@ -14,158 +13,4 @@ namespace {
} // namespace
namespace xlnt {
void read_worksheet(worksheet ws, zip_file &archive, const relationship &rel, const std::vector<std::string> &string_table)
{
pugi::xml_document doc;
doc.load(archive.read(rel.get_target_uri()).c_str());
auto root_node = doc.child("worksheet");
auto dimension_node = root_node.child("dimension");
std::string dimension = dimension_node.attribute("ref").as_string();
auto full_range = xlnt::range_reference(dimension);
auto sheet_data_node = root_node.child("sheetData");
auto merge_cells_node = root_node.child("mergeCells");
if(merge_cells_node != nullptr)
{
int count = merge_cells_node.attribute("count").as_int();
for(auto merge_cell_node : merge_cells_node.children("mergeCell"))
{
ws.merge_cells(merge_cell_node.attribute("ref").as_string());
count--;
}
if(count != 0)
{
throw std::runtime_error("mismatch between count and actual number of merged cells");
}
}
for(auto row_node : sheet_data_node.children("row"))
{
auto row_index = static_cast<row_t>(row_node.attribute("r").as_uint());
if(row_node.attribute("ht") != nullptr)
{
ws.get_row_properties(row_index).height = row_node.attribute("ht").as_double();
}
std::string span_string = row_node.attribute("spans").as_string();
auto colon_index = span_string.find(':');
column_t min_column = 0;
column_t max_column = 0;
if(colon_index != std::string::npos)
{
min_column = static_cast<column_t>(std::stoll(span_string.substr(0, colon_index)));
max_column = static_cast<column_t>(std::stoll(span_string.substr(colon_index + 1)));
}
else
{
min_column = static_cast<column_t>(full_range.get_top_left().get_column_index());
max_column = static_cast<column_t>(full_range.get_bottom_right().get_column_index());
}
for(column_t i = min_column; i <= max_column; i++)
{
std::string address = xlnt::cell_reference::column_string_from_index(i) + std::to_string(row_index);
auto cell_node = row_node.find_child_by_attribute("c", "r", address.c_str());
if(cell_node != nullptr)
{
bool has_value = cell_node.child("v") != nullptr;
std::string value_string = has_value ? cell_node.child("v").text().as_string() : "";
bool has_type = cell_node.attribute("t") != nullptr;
std::string type = has_type ? cell_node.attribute("t").as_string() : "";
bool has_style = cell_node.attribute("s") != nullptr;
int style_id = has_style ? cell_node.attribute("s").as_int() : 0;
bool has_formula = cell_node.child("f") != nullptr;
bool has_shared_formula = has_formula && cell_node.child("f").attribute("t") != nullptr && std::string(cell_node.child("f").attribute("t").as_string()) == "shared";
auto cell = ws.get_cell(address);
if(has_formula && !has_shared_formula && !ws.get_parent().get_data_only())
{
std::string formula = cell_node.child("f").text().as_string();
cell.set_formula(formula);
}
if(has_type && type == "inlineStr") // inline string
{
std::string inline_string = cell_node.child("is").child("t").text().as_string();
cell.set_value(inline_string);
}
else if(has_type && type == "s" && !has_formula) // shared string
{
auto shared_string_index = std::stoull(value_string);
auto shared_string = string_table.at(shared_string_index);
cell.set_value(shared_string);
}
else if(has_type && type == "b") // boolean
{
cell.set_value(value_string != "0");
}
else if(has_type && type == "str")
{
cell.set_value(value_string);
}
else if(has_value && !value_string.empty())
{
if(!value_string.empty() && value_string[0] == '#')
{
cell.set_error(value_string);
}
else
{
cell.set_value(std::stold(value_string));
}
}
if(has_style)
{
cell.set_style_id(style_id);
}
}
}
}
auto cols_node = root_node.child("cols");
for(auto col_node : cols_node.children("col"))
{
column_t min = col_node.attribute("min").as_uint();
column_t max = col_node.attribute("max").as_uint();
double width = col_node.attribute("width").as_double();
std::size_t column_style = col_node.attribute("style").as_ullong();
bool custom = col_node.attribute("customWidth").as_bool();
for(auto column = min; column <= max; column++)
{
if(!ws.has_column_properties(column))
{
ws.add_column_properties(column, column_properties());
}
ws.get_column_properties(min).width = width;
ws.get_column_properties(min).style = column_style;
ws.get_column_properties(min).custom = custom;
}
}
auto auto_filter_node = root_node.child("autoFilter");
if(auto_filter_node != nullptr)
{
xlnt::range_reference ref(auto_filter_node.attribute("ref").as_string());
ws.auto_filter(ref);
}
}
} // namespace xlnt

View File

@ -19,11 +19,6 @@
#include <xlnt/worksheet/worksheet.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/writer/excel_writer.hpp>
#include <xlnt/reader/excel_reader.hpp>
#include <xlnt/common/xml_tree.hpp>
class test_cell : public CxxTest::TestSuite
{
private:
@ -37,7 +32,8 @@ public:
void test_debug()
{
auto wb = xlnt::excel_reader::load_workbook("/Users/thomas/Development/xlnt/samples/formatting.xlsx");
xlnt::workbook wb;
wb.load("/Users/thomas/Development/xlnt/samples/formatting.xlsx");
wb.save("/Users/thomas/Development/xlnt/samples/formatting-rt.xlsx");
wb.save("/Users/thomas/Development/xlnt/samples/formatting-rt.zip");
}
@ -94,7 +90,6 @@ public:
TS_ASSERT(cell.get_row() == 1);
TS_ASSERT(cell.get_reference() == "A1");
TS_ASSERT(!cell.has_value());
TS_ASSERT(cell.get_xf_index() == 0);
TS_ASSERT(!cell.has_comment());
}
@ -179,7 +174,7 @@ public:
auto ws = wb_guess_types.create_sheet();
auto cell = ws.get_cell(xlnt::cell_reference(1, 1));
for(auto error_code : xlnt::cell::ErrorCodes)
for(auto error_code : xlnt::cell::error_codes())
{
cell.set_value(error_code.first);
TS_ASSERT(cell.get_data_type() == xlnt::cell::type::error);

View File

@ -3,8 +3,7 @@
#include <iostream>
#include <cxxtest/TestSuite.h>
#include <xlnt/reader/workbook_reader.hpp>
#include <xlnt/writer/workbook_writer.hpp>
#include <xlnt/s11n/workbook_serializer.hpp>
#include "helpers/path_helper.hpp"
#include "helpers/helper.hpp"
@ -16,7 +15,9 @@ public:
{
xlnt::zip_file archive(PathHelper::GetDataDirectory() + "/genuine/empty.xlsx");
auto content = archive.read("docProps/core.xml");
auto prop = xlnt::read_properties_core(content);
xlnt::workbook wb;
xlnt::workbook_serializer serializer(wb);
auto prop = serializer.read_properties_core(content);
TS_ASSERT_EQUALS(prop.creator, "*.*");
TS_ASSERT_EQUALS(prop.last_modified_by, "Charlie Clark");
TS_ASSERT_EQUALS(prop.created, xlnt::datetime(2010, 4, 9, 20, 43, 12));

View File

@ -5,10 +5,6 @@
#include <cxxtest/TestSuite.h>
#include <xlnt/reader/excel_reader.hpp>
#include <xlnt/reader/workbook_reader.hpp>
#include <xlnt/reader/worksheet_reader.hpp>
#include "helpers/path_helper.hpp"
class test_read : public CxxTest::TestSuite