#include #include #include #include #include #include #include #include #include #include #include #include #include namespace { /// /// Returns true if d is exactly equal to an integer. /// bool is_integral(long double d) { return d == static_cast(d); } /// /// Serializes document and writes to to the archive at archive_path. /// void write_document_to_archive(const pugi::xml_document &document, const xlnt::path &archive_path, xlnt::zip_file &archive) { std::ostringstream out_stream; document.save(out_stream); archive.write_string(out_stream.str(), archive_path); } std::string fill(const std::string &string, std::size_t length = 2) { if (string.size() >= length) { return string; } return std::string(length - string.size(), '0') + string; } std::string datetime_to_w3cdtf(const xlnt::datetime &dt) { return std::to_string(dt.year) + "-" + fill(std::to_string(dt.month)) + "-" + fill(std::to_string(dt.day)) + "T" + fill(std::to_string(dt.hour)) + ":" + fill(std::to_string(dt.minute)) + ":" + fill(std::to_string(dt.second)) + "Z"; } /// /// Returns the string representation of the relationship type. /// std::string to_string(xlnt::relationship::type t) { switch (t) { case xlnt::relationship::type::office_document: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"; case xlnt::relationship::type::thumbnail: return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"; case xlnt::relationship::type::calculation_chain: return "http://purl.oclc.org/ooxml/officeDocument/relationships/calcChain"; case xlnt::relationship::type::extended_properties: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"; case xlnt::relationship::type::core_properties: return "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"; case xlnt::relationship::type::worksheet: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"; case xlnt::relationship::type::shared_string_table: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"; case xlnt::relationship::type::styles: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"; case xlnt::relationship::type::theme: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"; case xlnt::relationship::type::hyperlink: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"; case xlnt::relationship::type::chartsheet: return "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"; default: return "??"; } } std::string to_string(xlnt::font::underline_style underline_style) { switch (underline_style) { case xlnt::font::underline_style::double_: return "double"; case xlnt::font::underline_style::double_accounting: return "doubleAccounting"; case xlnt::font::underline_style::single: return "single"; case xlnt::font::underline_style::single_accounting: return "singleAccounting"; default: case xlnt::font::underline_style::none: return "none"; } } std::string to_string(xlnt::pattern_fill_type fill_type) { switch (fill_type) { case xlnt::pattern_fill_type::darkdown: return "darkdown"; case xlnt::pattern_fill_type::darkgray: return "darkgray"; case xlnt::pattern_fill_type::darkgrid: return "darkgrid"; case xlnt::pattern_fill_type::darkhorizontal: return "darkhorizontal"; case xlnt::pattern_fill_type::darktrellis: return "darkhorizontal"; case xlnt::pattern_fill_type::darkup: return "darkup"; case xlnt::pattern_fill_type::darkvertical: return "darkvertical"; case xlnt::pattern_fill_type::gray0625: return "gray0625"; case xlnt::pattern_fill_type::gray125: return "gray125"; case xlnt::pattern_fill_type::lightdown: return "lightdown"; case xlnt::pattern_fill_type::lightgray: return "lightgray"; case xlnt::pattern_fill_type::lightgrid: return "lightgrid"; case xlnt::pattern_fill_type::lighthorizontal: return "lighthorizontal"; case xlnt::pattern_fill_type::lighttrellis: return "lighttrellis"; case xlnt::pattern_fill_type::lightup: return "lightup"; case xlnt::pattern_fill_type::lightvertical: return "lightvertical"; case xlnt::pattern_fill_type::mediumgray: return "mediumgray"; case xlnt::pattern_fill_type::solid: return "solid"; default: case xlnt::pattern_fill_type::none: return "none"; } } std::string to_string(xlnt::gradient_fill_type fill_type) { return fill_type == xlnt::gradient_fill_type::linear ? "linear" : "path"; } std::string to_string(xlnt::border_style border_style) { switch (border_style) { case xlnt::border_style::dashdot: return "dashdot"; case xlnt::border_style::dashdotdot: return "dashdotdot"; case xlnt::border_style::dashed: return "dashed"; case xlnt::border_style::dotted: return "dotted"; case xlnt::border_style::double_: return "double"; case xlnt::border_style::hair: return "hair"; case xlnt::border_style::medium: return "medium"; case xlnt::border_style::mediumdashdot: return "mediumdashdot"; case xlnt::border_style::mediumdashdotdot: return "mediumdashdotdot"; case xlnt::border_style::mediumdashed: return "mediumdashed"; case xlnt::border_style::slantdashdot: return "slantdashdot"; case xlnt::border_style::thick: return "thick"; case xlnt::border_style::thin: return "thin"; default: case xlnt::border_style::none: return "none"; } } std::string to_string(xlnt::vertical_alignment vertical_alignment) { switch (vertical_alignment) { case xlnt::vertical_alignment::bottom: return "bottom"; case xlnt::vertical_alignment::center: return "center"; case xlnt::vertical_alignment::justify: return "justify"; case xlnt::vertical_alignment::top: return "top"; default: case xlnt::vertical_alignment::none: return "none"; } } std::string to_string(xlnt::horizontal_alignment horizontal_alignment) { switch (horizontal_alignment) { case xlnt::horizontal_alignment::center: return "center"; case xlnt::horizontal_alignment::center_continuous: return "center-continous"; case xlnt::horizontal_alignment::general: return "general"; case xlnt::horizontal_alignment::justify: return "justify"; case xlnt::horizontal_alignment::left: return "left"; case xlnt::horizontal_alignment::right: return "right"; default: case xlnt::horizontal_alignment::none: return "none"; } } std::string to_string(xlnt::border_side side) { switch (side) { case xlnt::border_side::bottom: return "bottom"; case xlnt::border_side::top: return "top"; case xlnt::border_side::start: return "left"; case xlnt::border_side::end: return "right"; case xlnt::border_side::horizontal: return "horizontal"; case xlnt::border_side::vertical: return "vertical"; default: case xlnt::border_side::diagonal: return "diagonal"; } } void write_relationships(const std::vector &relationships, pugi::xml_node root) { auto relationships_node = root.append_child("Relationships"); relationships_node.append_attribute("xmlns").set_value(xlnt::constants::get_namespace("relationships").c_str()); for (const auto &relationship : relationships) { auto relationship_node = relationships_node.append_child("Relationship"); relationship_node.append_attribute("Id").set_value(relationship.get_id().c_str()); relationship_node.append_attribute("Type").set_value(to_string(relationship.get_type()).c_str()); relationship_node.append_attribute("Target").set_value(relationship.get_target().get_path().string().c_str()); if (relationship.get_target_mode() == xlnt::target_mode::external) { relationship_node.append_attribute("TargetMode").set_value("External"); } } } bool write_color(const xlnt::color &color, pugi::xml_node color_node) { switch (color.get_type()) { case xlnt::color::type::theme: color_node.append_attribute("theme") .set_value(std::to_string(color.get_theme().get_index()).c_str()); break; case xlnt::color::type::indexed: color_node.append_attribute("indexed") .set_value(std::to_string(color.get_indexed().get_index()).c_str()); break; case xlnt::color::type::rgb: default: color_node.append_attribute("rgb") .set_value(color.get_rgb().get_hex_string().c_str()); break; } return true; } bool write_dxfs(pugi::xml_node &dxfs_node) { dxfs_node.append_attribute("count").set_value("0"); return true; } bool write_table_styles(pugi::xml_node &table_styles_node) { table_styles_node.append_attribute("count").set_value("0"); table_styles_node.append_attribute("defaultTableStyle").set_value("TableStyleMedium9"); table_styles_node.append_attribute("defaultPivotStyle").set_value("PivotStyleMedium7"); return true; } bool write_colors(const std::vector &colors, pugi::xml_node &colors_node) { auto indexed_colors_node = colors_node.append_child("indexedColors"); for (auto &c : colors) { auto rgb_color_node = indexed_colors_node.append_child("rgbColor"); auto rgb_attribute = rgb_color_node.append_attribute("rgb"); rgb_attribute.set_value(c.get_rgb().get_hex_string().c_str()); } return true; } } // namespace namespace xlnt { namespace detail { xlsx_producer::xlsx_producer(const workbook &target) : source_(target) { } void xlsx_producer::write(const path &destination) { populate_archive(); destination_.save(destination); } void xlsx_producer::write(std::ostream &destination) { populate_archive(); destination_.save(destination); } void xlsx_producer::write(std::vector &destination) { populate_archive(); destination_.save(destination); } // Part Writing Methods void xlsx_producer::populate_archive() { write_manifest(); for (auto &rel : source_.impl().manifest_.get_relationships(path("/"))) { pugi::xml_document document; bool write_document = true; switch (rel.get_type()) { case relationship::type::core_properties: write_core_properties(rel, document.root()); break; case relationship::type::extended_properties: write_extended_properties(rel, document.root()); break; case relationship::type::custom_properties: write_custom_properties(rel, document.root()); break; case relationship::type::office_document: write_workbook(rel, document.root()); break; case relationship::type::thumbnail: write_thumbnail(rel); write_document = false; break; default: break; } if (write_document) { write_document_to_archive(document, rel.get_target().get_path(), destination_); } } // Unknown Parts void write_unknown_parts(); void write_unknown_relationships(); } // Package Parts void xlsx_producer::write_manifest() { pugi::xml_document content_types_document; auto types_node = content_types_document.append_child("Types"); types_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/package/2006/content-types"); for (const auto &extension : source_.get_manifest().get_extensions_with_default_types()) { auto default_node = types_node.append_child("Default"); default_node.append_attribute("Extension").set_value(extension.c_str()); auto content_type = source_.get_manifest().get_default_type(extension); default_node.append_attribute("ContentType").set_value(content_type.c_str()); } for (const auto &part : source_.get_manifest().get_parts_with_overriden_types()) { auto override_node = types_node.append_child("Override"); override_node.append_attribute("PartName").set_value(part.resolve(path("/")).string().c_str()); auto content_type = source_.get_manifest().get_override_type(part); override_node.append_attribute("ContentType").set_value(content_type.c_str()); } for (const auto &part : source_.get_manifest().get_parts()) { auto part_rels = source_.get_manifest().get_relationships(part); if (part_rels.empty()) continue; pugi::xml_document part_rels_document; write_relationships(part_rels, part_rels_document.root()); path parent = part.parent(); if (parent.is_absolute()) { parent = path(parent.string().substr(1)); } path rels_path(parent.append("_rels").append(part.filename() + ".rels").string()); write_document_to_archive(part_rels_document, rels_path, destination_); } write_document_to_archive(content_types_document, path("[Content_Types].xml"), destination_); } void xlsx_producer::write_extended_properties(const relationship &rel, pugi::xml_node root) { auto properties_node = root.append_child("Properties"); properties_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"); properties_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"); properties_node.append_child("Application").text().set(source_.get_application().c_str()); properties_node.append_child("DocSecurity").text().set(std::to_string(source_.get_doc_security()).c_str()); properties_node.append_child("ScaleCrop").text().set(source_.get_scale_crop() ? "true" : "false"); auto heading_pairs_node = properties_node.append_child("HeadingPairs"); auto heading_pairs_vector_node = heading_pairs_node.append_child("vt:vector"); heading_pairs_vector_node.append_attribute("size").set_value("2"); heading_pairs_vector_node.append_attribute("baseType").set_value("variant"); 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(source_.get_sheet_titles().size()).c_str()); auto titles_of_parts_node = properties_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("size").set_value(std::to_string(source_.get_sheet_titles().size()).c_str()); titles_of_parts_vector_node.append_attribute("baseType").set_value("lpstr"); for (auto ws : source_) { titles_of_parts_vector_node.append_child("vt:lpstr").text().set(ws.get_title().c_str()); } auto company_node = properties_node.append_child("Company"); if (!source_.get_company().empty()) { company_node.text().set(source_.get_company().c_str()); } properties_node.append_child("LinksUpToDate").text().set(source_.links_up_to_date() ? "true" : "false"); properties_node.append_child("SharedDoc").text().set(source_.is_shared_doc() ? "true" : "false"); properties_node.append_child("HyperlinksChanged").text().set(source_.hyperlinks_changed() ? "true" : "false"); properties_node.append_child("AppVersion").text().set(source_.get_app_version().c_str()); } void xlsx_producer::write_core_properties(const relationship &rel, pugi::xml_node root) { auto core_properties_node = root.append_child("cp:coreProperties"); core_properties_node.append_attribute("xmlns:cp").set_value("http://schemas.openxmlformats.org/package/2006/metadata/core-properties"); core_properties_node.append_attribute("xmlns:dc").set_value("http://purl.org/dc/elements/1.1/"); core_properties_node.append_attribute("xmlns:dcterms").set_value("http://purl.org/dc/terms/"); core_properties_node.append_attribute("xmlns:dcmitype").set_value("http://purl.org/dc/dcmitype/"); core_properties_node.append_attribute("xmlns:xsi").set_value("http://www.w3.org/2001/XMLSchema-instance"); core_properties_node.append_child("dc:creator").text().set(source_.get_creator().c_str()); core_properties_node.append_child("cp:lastModifiedBy").text().set(source_.get_last_modified_by().c_str()); core_properties_node.append_child("dcterms:created").text().set(datetime_to_w3cdtf(source_.get_created()).c_str()); core_properties_node.child("dcterms:created").append_attribute("xsi:type").set_value("dcterms:W3CDTF"); core_properties_node.append_child("dcterms:modified").text().set(datetime_to_w3cdtf(source_.get_modified()).c_str()); core_properties_node.child("dcterms:modified").append_attribute("xsi:type").set_value("dcterms:W3CDTF"); if (!source_.get_title().empty()) { core_properties_node.append_child("dc:title").text().set(source_.get_title().c_str()); } /* core_properties_node.append_child("dc:description"); core_properties_node.append_child("dc:subject"); core_properties_node.append_child("cp:keywords"); core_properties_node.append_child("cp:category"); */ } void xlsx_producer::write_custom_properties(const relationship &rel, pugi::xml_node root) { /*auto properties_node = */root.append_child("Properties"); } // Write SpreadsheetML-Specific Package Parts void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root) { std::size_t num_visible = 0; bool any_defined_names = false; for (auto ws : source_) { if (!ws.has_page_setup() || ws.get_page_setup().get_sheet_state() == sheet_state::visible) { num_visible++; } if (ws.has_auto_filter()) { any_defined_names = true; } } if (num_visible == 0) { throw no_visible_worksheets(); } auto workbook_node = root.append_child("workbook"); workbook_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); workbook_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships"); if (source_.x15_enabled()) { workbook_node.append_attribute("xmlns:mc").set_value("http://schemas.openxmlformats.org/markup-compatibility/2006"); workbook_node.append_attribute("mc:Ignorable").set_value("x15"); workbook_node.append_attribute("xmlns:x15").set_value("http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"); } if (source_.has_file_version()) { auto file_version_node = workbook_node.append_child("fileVersion"); file_version_node.append_attribute("appName").set_value(source_.get_app_name().c_str()); file_version_node.append_attribute("lastEdited").set_value(std::to_string(source_.get_last_edited()).c_str()); file_version_node.append_attribute("lowestEdited").set_value(std::to_string(source_.get_lowest_edited()).c_str()); file_version_node.append_attribute("rupBuild").set_value(std::to_string(source_.get_rup_build()).c_str()); } if (source_.has_properties()) { auto workbook_pr_node = workbook_node.append_child("workbookPr"); if (source_.has_code_name()) { workbook_pr_node.append_attribute("codeName").set_value(source_.get_code_name().c_str()); } /* workbook_pr_node.append_attribute("defaultThemeVersion").set_value("124226"); workbook_pr_node.append_attribute("date1904").set_value(source_.get_base_date() == calendar::mac_1904 ? "1" : "0"); */ } if (source_.has_absolute_path()) { auto alternate_content_node = workbook_node.append_child("mc:AlternateContent"); alternate_content_node.append_attribute("xmlns:mc").set_value("http://schemas.openxmlformats.org/markup-compatibility/2006"); auto choice_node = alternate_content_node.append_child("mc:Choice"); choice_node.append_attribute("Requires").set_value("x15"); auto abs_path_node = choice_node.append_child("x15ac:absPath"); std::string absolute_path = source_.get_absolute_path().string(); abs_path_node.append_attribute("url").set_value(absolute_path.c_str()); abs_path_node.append_attribute("xmlns:x15ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2010/11/ac"); } if (source_.has_view()) { auto book_views_node = workbook_node.append_child("bookViews"); auto workbook_view_node = book_views_node.append_child("workbookView"); const auto &view = source_.get_view(); //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"); workbook_view_node.append_attribute("xWindow").set_value(std::to_string(view.x_window).c_str()); workbook_view_node.append_attribute("yWindow").set_value(std::to_string(view.y_window).c_str()); workbook_view_node.append_attribute("windowWidth").set_value(std::to_string(view.window_width).c_str()); workbook_view_node.append_attribute("windowHeight").set_value(std::to_string(view.window_height).c_str()); workbook_view_node.append_attribute("tabRatio").set_value(std::to_string(view.tab_ratio).c_str()); } auto sheets_node = workbook_node.append_child("sheets"); pugi::xml_node defined_names_node; if (any_defined_names) { defined_names_node = workbook_node.append_child("definedNames"); } for (const auto ws : source_) { auto sheet_rel_id = source_.d_->sheet_title_rel_id_map_[ws.get_title()]; auto sheet_rel = source_.d_->manifest_.get_relationship(rel.get_source().get_path(), sheet_rel_id); auto sheet_node = sheets_node.append_child("sheet"); sheet_node.append_attribute("name").set_value(ws.get_title().c_str()); sheet_node.append_attribute("sheetId").set_value(std::to_string(ws.get_id()).c_str()); if (ws.has_page_setup() && ws.get_sheet_state() == xlnt::sheet_state::hidden) { sheet_node.append_attribute("state").set_value("hidden"); } sheet_node.append_attribute("r:id").set_value(sheet_rel_id.c_str()); 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(write_bool(true).c_str()); defined_name_node.append_attribute("localSheetId").set_value("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()); } } if (source_.has_calculation_properties()) { auto calc_pr_node = workbook_node.append_child("calcPr"); calc_pr_node.append_attribute("calcId").set_value("150000"); //calc_pr_node.append_attribute("calcMode").set_value("auto"); //calc_pr_node.append_attribute("fullCalcOnLoad").set_value("1"); calc_pr_node.append_attribute("concurrentCalc").set_value("0"); } if (!source_.get_named_ranges().empty()) { auto defined_names_node = workbook_node.append_child("definedNames"); for (auto &named_range : source_.get_named_ranges()) { auto defined_name_node = defined_names_node.append_child("s:definedName"); defined_name_node.append_attribute("xmlns:s").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); defined_name_node.append_attribute("name").set_value(named_range.get_name().c_str()); const auto &target = named_range.get_targets().front(); std::string target_string = "'" + target.first.get_title(); target_string.push_back('\''); target_string.push_back('!'); target_string.append(target.second.to_string()); defined_name_node.text().set(target_string.c_str()); } } if (source_.has_arch_id()) { auto ext_lst_node = workbook_node.append_child("extLst"); auto ext_node = ext_lst_node.append_child("ext"); ext_node.append_attribute("uri").set_value("{7523E5D3-25F3-A5E0-1632-64F254C22452}"); ext_node.append_attribute("xmlns:mx").set_value("http://schemas.microsoft.com/office/mac/excel/2008/main"); auto arch_id_node = ext_node.append_child("mx:ArchID"); arch_id_node.append_attribute("Flags").set_value("2"); } for (const auto &child_rel : source_.get_manifest().get_relationships(rel.get_target().get_path())) { pugi::xml_document document; switch (child_rel.get_type()) { case relationship::type::calculation_chain: write_calculation_chain(child_rel, document.root()); break; case relationship::type::chartsheet: write_chartsheet(child_rel, document.root()); break; case relationship::type::connections: write_connections(child_rel, document.root()); break; case relationship::type::custom_xml_mappings: write_custom_xml_mappings(child_rel, document.root()); break; case relationship::type::dialogsheet: write_dialogsheet(child_rel, document.root()); break; case relationship::type::external_workbook_references: write_external_workbook_references(child_rel, document.root()); break; case relationship::type::metadata: write_metadata(child_rel, document.root()); break; case relationship::type::pivot_table: write_pivot_table(child_rel, document.root()); break; case relationship::type::shared_string_table: write_shared_string_table(child_rel, document.root()); break; case relationship::type::shared_workbook_revision_headers: write_shared_workbook_revision_headers(child_rel, document.root()); break; case relationship::type::styles: write_styles(child_rel, document.root()); break; case relationship::type::theme: write_theme(child_rel, document.root()); break; case relationship::type::volatile_dependencies: write_volatile_dependencies(child_rel, document.root()); break; case relationship::type::worksheet: write_worksheet(child_rel, document.root()); break; default: break; } path archive_path(child_rel.get_source().get_path().parent().append(child_rel.get_target().get_path())); write_document_to_archive(document, archive_path, destination_); } } // Write Workbook Relationship Target Parts void xlsx_producer::write_calculation_chain(const relationship &rel, pugi::xml_node root) { /*auto calc_chain_node = */root.append_child("calcChain"); } void xlsx_producer::write_chartsheet(const relationship &rel, pugi::xml_node root) { /*auto chartsheet_node = */root.append_child("chartsheet"); } void xlsx_producer::write_connections(const relationship &rel, pugi::xml_node root) { /*auto connections_node = */root.append_child("connections"); } void xlsx_producer::write_custom_xml_mappings(const relationship &rel, pugi::xml_node root) { /*auto map_info_node = */root.append_child("MapInfo"); } void xlsx_producer::write_dialogsheet(const relationship &rel, pugi::xml_node root) { /*auto dialogsheet_node = */root.append_child("dialogsheet"); } void xlsx_producer::write_external_workbook_references(const relationship &rel, pugi::xml_node root) { /*auto external_link_node = */root.append_child("externalLink"); } void xlsx_producer::write_metadata(const relationship &rel, pugi::xml_node root) { /*auto metadata_node = */root.append_child("metadata"); } void xlsx_producer::write_pivot_table(const relationship &rel, pugi::xml_node root) { /*auto pivot_table_definition_node = */root.append_child("pivotTableDefinition"); } void xlsx_producer::write_shared_string_table(const relationship &rel, pugi::xml_node root) { auto sst_node = root.append_child("sst"); sst_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); sst_node.append_attribute("count").set_value(std::to_string(source_.get_shared_strings().size()).c_str()); sst_node.append_attribute("uniqueCount").set_value(std::to_string(source_.get_shared_strings().size()).c_str()); for (const auto &string : source_.get_shared_strings()) { if (string.get_runs().size() == 1 && !string.get_runs().at(0).has_formatting()) { sst_node.append_child("si").append_child("t").text().set(string.get_plain_string().c_str()); } else { auto string_item_node = sst_node.append_child("si"); for (const auto &run : string.get_runs()) { auto rich_text_run_node = string_item_node.append_child("r"); if (run.has_formatting()) { auto run_properties_node = rich_text_run_node.append_child("rPr"); if (run.has_size()) { run_properties_node.append_child("sz").append_attribute("val").set_value(std::to_string(run.get_size()).c_str()); } if (run.has_color()) { run_properties_node.append_child("color").append_attribute("rgb").set_value(run.get_color().c_str()); } if (run.has_font()) { run_properties_node.append_child("rFont").append_attribute("val").set_value(run.get_font().c_str()); } if (run.has_family()) { run_properties_node.append_child("family").append_attribute("val").set_value(std::to_string(run.get_family()).c_str()); } if (run.has_scheme()) { run_properties_node.append_child("scheme").append_attribute("val").set_value(run.get_scheme().c_str()); } } auto text_node = rich_text_run_node.append_child("t"); text_node.text().set(run.get_string().c_str()); } } } } void xlsx_producer::write_shared_workbook_revision_headers(const relationship &rel, pugi::xml_node root) { /*auto headers_node = */root.append_child("headers"); } void xlsx_producer::write_shared_workbook(const relationship &rel, pugi::xml_node root) { /*auto revisions_node = */root.append_child("revisions"); } void xlsx_producer::write_shared_workbook_user_data(const relationship &rel, pugi::xml_node root) { /*auto users_node = */root.append_child("users"); } void xlsx_producer::write_styles(const relationship &rel, pugi::xml_node root) { auto stylesheet_node = root.append_child("styleSheet"); // Namespaces stylesheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); if (source_.x15_enabled()) { stylesheet_node.append_attribute("xmlns:mc").set_value("http://schemas.openxmlformats.org/markup-compatibility/2006"); stylesheet_node.append_attribute("mc:Ignorable").set_value("x14ac"); stylesheet_node.append_attribute("xmlns:x14ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"); } const auto &stylesheet = source_.impl().stylesheet_; // Number Formats if (!stylesheet.number_formats.empty()) { auto number_formats_node = stylesheet_node.append_child("numFmts"); const auto &number_formats = stylesheet.number_formats; number_formats_node.append_attribute("count").set_value(std::to_string(number_formats.size()).c_str()); for (const auto &num_fmt : number_formats) { auto num_fmt_node = number_formats_node.append_child("numFmt"); num_fmt_node.append_attribute("numFmtId").set_value(std::to_string(num_fmt.get_id()).c_str()); num_fmt_node.append_attribute("formatCode").set_value(num_fmt.get_format_string().c_str()); } } // Fonts if (!stylesheet.fonts.empty()) { auto fonts_node = stylesheet_node.append_child("fonts"); const auto &fonts = stylesheet.fonts; fonts_node.append_attribute("count").set_value(std::to_string(fonts.size()).c_str()); if (source_.x15_enabled()) { fonts_node.append_attribute("x14ac:knownFonts").set_value(std::to_string(fonts.size()).c_str()); } for (const auto ¤t_font : fonts) { auto font_node = fonts_node.append_child("font"); if (current_font.bold()) { auto bold_node = font_node.append_child("b"); bold_node.append_attribute("val").set_value(write_bool(true).c_str()); } if (current_font.italic()) { auto italic_node = font_node.append_child("i"); italic_node.append_attribute("val").set_value(write_bool(true).c_str()); } if (current_font.underlined()) { auto underline_node = font_node.append_child("u"); underline_node.append_attribute("val").set_value(to_string(current_font.underline()).c_str()); } if (current_font.strikethrough()) { auto strike_node = font_node.append_child("strike"); strike_node.append_attribute("val").set_value(write_bool(true).c_str()); } auto size_node = font_node.append_child("sz"); size_node.append_attribute("val").set_value(std::to_string(current_font.size()).c_str()); if (current_font.color()) { auto color_node = font_node.append_child("color"); write_color(*current_font.color(), color_node); } auto name_node = font_node.append_child("name"); name_node.append_attribute("val").set_value(current_font.name().c_str()); if (current_font.family()) { auto family_node = font_node.append_child("family"); family_node.append_attribute("val").set_value(std::to_string(*current_font.family()).c_str()); } if (current_font.scheme()) { auto scheme_node = font_node.append_child("scheme"); scheme_node.append_attribute("val").set_value(current_font.scheme()->c_str()); } } } // Fills if (!stylesheet.fills.empty()) { auto fills_node = stylesheet_node.append_child("fills"); const auto &fills = stylesheet.fills; fills_node.append_attribute("count").set_value(std::to_string(fills.size()).c_str()); for (auto &fill_ : fills) { auto fill_node = fills_node.append_child("fill"); if (fill_.type() == xlnt::fill_type::pattern) { const auto &pattern = fill_.pattern_fill(); auto pattern_fill_node = fill_node.append_child("patternFill"); pattern_fill_node.append_attribute("patternType").set_value(to_string(pattern.type()).c_str()); if (pattern.foreground()) { write_color(*pattern.foreground(), pattern_fill_node.append_child("fgColor")); } if (pattern.background()) { write_color(*pattern.background(), pattern_fill_node.append_child("bgColor")); } } else if (fill_.type() == xlnt::fill_type::gradient) { const auto &gradient = fill_.gradient_fill(); auto gradient_fill_node = fill_node.append_child("gradientFill"); auto gradient_fill_type_string = to_string(gradient.type()); gradient_fill_node.append_attribute("gradientType").set_value(gradient_fill_type_string.c_str()); if (gradient.degree() != 0) { gradient_fill_node.append_attribute("degree").set_value(gradient.degree()); } if (gradient.left() != 0) { gradient_fill_node.append_attribute("left").set_value(gradient.left()); } if (gradient.right() != 0) { gradient_fill_node.append_attribute("right").set_value(gradient.right()); } if (gradient.top() != 0) { gradient_fill_node.append_attribute("top").set_value(gradient.top()); } if (gradient.bottom() != 0) { gradient_fill_node.append_attribute("bottom").set_value(gradient.bottom()); } for (const auto &stop : gradient.stops()) { auto stop_node = gradient_fill_node.append_child("stop"); stop_node.append_attribute("position").set_value(stop.first); write_color(stop.second, stop_node.append_child("color")); } } } } // Borders if (!stylesheet.borders.empty()) { auto borders_node = stylesheet_node.append_child("borders"); const auto &borders = stylesheet.borders; borders_node.append_attribute("count").set_value(std::to_string(borders.size()).c_str()); for (const auto ¤t_border : borders) { auto border_node = borders_node.append_child("border"); if (current_border.diagonal()) { auto up = *current_border.diagonal() == diagonal_direction::both || *current_border.diagonal() == diagonal_direction::up; border_node.append_attribute("diagonalUp").set_value(up ? "true" : "false"); auto down = *current_border.diagonal() == diagonal_direction::both || *current_border.diagonal() == diagonal_direction::down; border_node.append_attribute("diagonalDown").set_value(down ? "true" : "false"); } for (const auto &side : xlnt::border::all_sides()) { if (current_border.side(side)) { const auto current_side = *current_border.side(side); auto side_name = to_string(side); auto side_node = border_node.append_child(side_name.c_str()); if (current_side.style()) { auto style_string = to_string(*current_side.style()); side_node.append_attribute("style").set_value(style_string.c_str()); } if (current_side.color()) { auto color_node = side_node.append_child("color"); write_color(*current_side.color(), color_node); } } } } } // Formats & Styles auto cell_style_xfs_node = stylesheet_node.append_child("cellStyleXfs"); auto cell_xfs_node = stylesheet_node.append_child("cellXfs"); cell_xfs_node.append_attribute("count").set_value(std::to_string(stylesheet.formats.size()).c_str()); // Formats for (auto ¤t_format : stylesheet.formats) { auto xf_node = cell_xfs_node.append_child("xf"); xf_node.append_attribute("numFmtId").set_value(std::to_string(current_format.number_format().get_id()).c_str()); auto font_id = std::distance(stylesheet.fonts.begin(), std::find(stylesheet.fonts.begin(), stylesheet.fonts.end(), current_format.font())); xf_node.append_attribute("fontId").set_value(std::to_string(font_id).c_str()); auto fill_id = std::distance(stylesheet.fills.begin(), std::find(stylesheet.fills.begin(), stylesheet.fills.end(), current_format.fill())); xf_node.append_attribute("fillId").set_value(std::to_string(fill_id).c_str()); auto border_id = std::distance(stylesheet.borders.begin(), std::find(stylesheet.borders.begin(), stylesheet.borders.end(), current_format.border())); xf_node.append_attribute("borderId").set_value(std::to_string(border_id).c_str()); if (current_format.number_format_applied()) xf_node.append_attribute("applyNumberFormat").set_value(write_bool(true).c_str()); if (current_format.fill_applied()) xf_node.append_attribute("applyFill").set_value(write_bool(true).c_str()); if (current_format.font_applied()) xf_node.append_attribute("applyFont").set_value(write_bool(true).c_str()); if (current_format.border_applied()) xf_node.append_attribute("applyBorder").set_value(write_bool(true).c_str()); if (current_format.alignment_applied()) { xf_node.append_attribute("applyAlignment").set_value(write_bool(true).c_str()); auto alignment_node = xf_node.append_child("alignment"); auto current_alignment = current_format.alignment(); if (current_alignment.vertical()) { auto vertical = to_string(*current_alignment.vertical()); alignment_node.append_attribute("vertical").set_value(vertical.c_str()); } if (current_alignment.horizontal()) { auto horizontal = to_string(*current_alignment.horizontal()); alignment_node.append_attribute("horizontal").set_value(horizontal.c_str()); } if (current_alignment.rotation()) { alignment_node.append_attribute("textRotation").set_value(std::to_string(*current_alignment.rotation()).c_str()); } if (current_alignment.wrap()) { alignment_node.append_attribute("wrapText").set_value(*current_alignment.wrap() ? "true" : "false"); } if (current_alignment.indent()) { alignment_node.append_attribute("indent").set_value(std::to_string(*current_alignment.indent()).c_str()); } if (current_alignment.shrink()) { alignment_node.append_attribute("shrinkToFit").set_value(*current_alignment.shrink() ? "true" : "false"); } } if (current_format.protection_applied()) { xf_node.append_attribute("applyProtection").set_value(write_bool(true).c_str()); auto protection_node = xf_node.append_child("protection"); auto current_protection = current_format.protection(); protection_node.append_attribute("locked").set_value(current_protection.locked() ? "true" : "false"); protection_node.append_attribute("hidden").set_value(current_protection.hidden() ? "true" : "false"); } if (current_format.has_style()) { auto style_iter = std::find_if(stylesheet.styles.begin(), stylesheet.styles.end(), [&](const xlnt::style &s) { return s.name() == current_format.style().name(); }); auto style_index = std::distance(stylesheet.styles.begin(), style_iter); xf_node.append_attribute("xfId").set_value(std::to_string(style_index).c_str()); } } // Styles auto cell_styles_node = stylesheet_node.append_child("cellStyles"); cell_style_xfs_node.append_attribute("count").set_value(std::to_string(stylesheet.styles.size()).c_str()); cell_styles_node.append_attribute("count").set_value(std::to_string(stylesheet.styles.size()).c_str()); std::size_t style_index = 0; for (auto ¤t_style : stylesheet.styles) { auto cell_style_node = cell_styles_node.append_child("cellStyle"); cell_style_node.append_attribute("name").set_value(current_style.name().c_str()); cell_style_node.append_attribute("xfId").set_value(std::to_string(style_index++).c_str()); if (current_style.builtin_id()) { cell_style_node.append_attribute("builtinId").set_value(std::to_string(*current_style.builtin_id()).c_str()); } if (current_style.hidden()) { cell_style_node.append_attribute("hidden").set_value(write_bool(true).c_str()); } if (current_style.custom()) { cell_style_node.append_attribute("customBuiltin").set_value(write_bool(*current_style.custom()).c_str()); } auto xf_node = cell_style_xfs_node.append_child("xf"); xf_node.append_attribute("numFmtId").set_value(std::to_string(current_style.number_format().get_id()).c_str()); auto font_id = std::distance(stylesheet.fonts.begin(), std::find(stylesheet.fonts.begin(), stylesheet.fonts.end(), current_style.font())); xf_node.append_attribute("fontId").set_value(std::to_string(font_id).c_str()); auto fill_id = std::distance(stylesheet.fills.begin(), std::find(stylesheet.fills.begin(), stylesheet.fills.end(), current_style.fill())); xf_node.append_attribute("fillId").set_value(std::to_string(fill_id).c_str()); auto border_id = std::distance(stylesheet.borders.begin(), std::find(stylesheet.borders.begin(), stylesheet.borders.end(), current_style.border())); xf_node.append_attribute("borderId").set_value(std::to_string(border_id).c_str()); if (current_style.number_format_applied()) xf_node.append_attribute("applyNumberFormat").set_value(write_bool(true).c_str()); if (current_style.fill_applied()) xf_node.append_attribute("applyFill").set_value(write_bool(true).c_str()); if (current_style.font_applied()) xf_node.append_attribute("applyFont").set_value(write_bool(true).c_str()); if (current_style.border_applied()) xf_node.append_attribute("applyBorder").set_value(write_bool(true).c_str()); if (current_style.alignment_applied()) { xf_node.append_attribute("applyAlignment").set_value(write_bool(true).c_str()); auto alignment_node = xf_node.append_child("alignment"); auto current_alignment = current_style.alignment(); if (current_alignment.vertical()) { auto vertical = to_string(*current_alignment.vertical()); alignment_node.append_attribute("vertical").set_value(vertical.c_str()); } if (current_alignment.horizontal()) { auto horizontal = to_string(*current_alignment.horizontal()); alignment_node.append_attribute("horizontal").set_value(horizontal.c_str()); } if (current_alignment.rotation()) { alignment_node.append_attribute("textRotation").set_value(std::to_string(*current_alignment.rotation()).c_str()); } if (current_alignment.wrap()) { alignment_node.append_attribute("wrapText").set_value(write_bool(*current_alignment.wrap()).c_str()); } if (current_alignment.indent()) { alignment_node.append_attribute("indent").set_value(std::to_string(*current_alignment.indent()).c_str()); } if (current_alignment.shrink()) { alignment_node.append_attribute("shrinkToFit").set_value(write_bool(*current_alignment.shrink()).c_str()); } } if (current_style.protection_applied()) { xf_node.append_attribute("applyProtection").set_value(write_bool(true).c_str()); auto protection_node = xf_node.append_child("protection"); auto current_protection = current_style.protection(); protection_node.append_attribute("locked").set_value(write_bool(current_protection.locked()).c_str()); protection_node.append_attribute("hidden").set_value(write_bool(current_protection.hidden()).c_str()); } } // Dxfs auto dxfs_node = stylesheet_node.append_child("dxfs"); write_dxfs(dxfs_node); // Table Styles auto table_styles_node = stylesheet_node.append_child("tableStyles"); write_table_styles(table_styles_node); // Colors if (!stylesheet.colors.empty()) { auto colors_node = stylesheet_node.append_child("colors"); write_colors(stylesheet.colors, colors_node); } // Ext Lst auto ext_list_node = stylesheet_node.append_child("extLst"); auto ext_node = ext_list_node.append_child("ext"); ext_node.append_attribute("uri").set_value("{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}"); ext_node.append_attribute("xmlns:x14").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"); auto slicer_styles_node = ext_node.append_child("x14:slicerStyles"); slicer_styles_node.append_attribute("defaultSlicerStyle").set_value("SlicerStyleLight1"); } void xlsx_producer::write_theme(const relationship &rel, pugi::xml_node root) { auto theme_node = root.append_child("a:theme"); theme_node.append_attribute("xmlns:a").set_value(constants::get_namespace("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_elements = { { "a:dk1", "a:sysClr", "windowText" },{ "a:lt1", "a:sysClr", "window" }, { "a:dk2", "a:srgbClr", "44546A" },{ "a:lt2", "a:srgbClr", "E7E6E6" }, { "a:accent1", "a:srgbClr", "5B9BD5" },{ "a:accent2", "a:srgbClr", "ED7D31" }, { "a:accent3", "a:srgbClr", "A5A5A5" },{ "a:accent4", "a:srgbClr", "FFC000" }, { "a:accent5", "a:srgbClr", "4472C4" },{ "a:accent6", "a:srgbClr", "70AD47" }, { "a:hlink", "a:srgbClr", "0563C1" },{ "a:folHlink", "a:srgbClr", "954F72" }, }; 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_schemes = { { true, "a:latin", "Calibri Light", "Calibri" }, { true, "a:ea", "", "" }, { true, "a:cs", "", "" }, { false, "Jpan", "Yu Gothic Light", "Yu Gothic" }, { 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", "DengXian Light", "DengXian" }, { 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" }, { false, "Geor", "Sylfaen", "Sylfaen" } }; 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) { if (scheme.typeface) { auto major_font_node = major_fonts_node.append_child(scheme.script.c_str()); major_font_node.append_attribute("typeface").set_value(scheme.major.c_str()); if (scheme.major == "Calibri Light") { major_font_node.append_attribute("panose").set_value("020F0302020204030204"); } auto minor_font_node = minor_fonts_node.append_child(scheme.script.c_str()); minor_font_node.append_attribute("typeface").set_value(scheme.minor.c_str()); if (scheme.minor == "Calibri") { minor_font_node.append_attribute("panose").set_value("020F0302020204030204"); } } else { auto major_font_node = major_fonts_node.append_child("a:font"); major_font_node.append_attribute("script").set_value(scheme.script.c_str()); major_font_node.append_attribute("typeface").set_value(scheme.major.c_str()); auto minor_font_node = minor_fonts_node.append_child("a:font"); minor_font_node.append_attribute("script").set_value(scheme.script.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:lumMod").append_attribute("val").set_value("110000"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("105000"); scheme_color_node.append_child("a:tint").append_attribute("val").set_value("67000"); gs_node = grad_fill_list.append_child("a:gs"); gs_node.append_attribute("pos").set_value("50000"); scheme_color_node = gs_node.append_child("a:schemeClr"); scheme_color_node.append_attribute("val").set_value("phClr"); scheme_color_node.append_child("a:lumMod").append_attribute("val").set_value("105000"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("103000"); scheme_color_node.append_child("a:tint").append_attribute("val").set_value("73000"); 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:lumMod").append_attribute("val").set_value("105000"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("109000"); scheme_color_node.append_child("a:tint").append_attribute("val").set_value("81000"); auto lin_node = grad_fill_node.append_child("a:lin"); lin_node.append_attribute("ang").set_value("5400000"); lin_node.append_attribute("scaled").set_value("0"); 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:satMod").append_attribute("val").set_value("103000"); scheme_color_node.append_child("a:lumMod").append_attribute("val").set_value("102000"); scheme_color_node.append_child("a:tint").append_attribute("val").set_value("94000"); gs_node = grad_fill_list.append_child("a:gs"); gs_node.append_attribute("pos").set_value("50000"); scheme_color_node = gs_node.append_child("a:schemeClr"); scheme_color_node.append_attribute("val").set_value("phClr"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("110000"); scheme_color_node.append_child("a:lumMod").append_attribute("val").set_value("100000"); scheme_color_node.append_child("a:shade").append_attribute("val").set_value("100000"); 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:lumMod").append_attribute("val").set_value("99000"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("120000"); scheme_color_node.append_child("a:shade").append_attribute("val").set_value("78000"); lin_node = grad_fill_node.append_child("a:lin"); lin_node.append_attribute("ang").set_value("5400000"); 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("6350"); 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"); ln_node.append_child("a:prstDash").append_attribute("val").set_value("solid"); ln_node.append_child("a:miter").append_attribute("lim").set_value("800000"); ln_node = line_style_list_node.append_child("a:ln"); ln_node.append_attribute("w").set_value("12700"); 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.append_child("a:miter").append_attribute("lim").set_value("800000"); ln_node = line_style_list_node.append_child("a:ln"); ln_node.append_attribute("w").set_value("19050"); 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.append_child("a:miter").append_attribute("lim").set_value("800000"); 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"); effect_style_node = effect_style_list_node.append_child("a:effectStyle"); effect_list_node = effect_style_node.append_child("a:effectLst"); effect_style_node = effect_style_list_node.append_child("a:effectStyle"); 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("57150"); outer_shadow_node.append_attribute("dist").set_value("19050"); outer_shadow_node.append_attribute("dir").set_value("5400000"); outer_shadow_node.append_attribute("algn").set_value("ctr"); 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("63000"); 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"); scheme_color_node = bg_fill_style_list_node.append_child("a:solidFill").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("95000"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("170000"); 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("93000"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("150000"); scheme_color_node.append_child("a:shade").append_attribute("val").set_value("98000"); scheme_color_node.append_child("a:lumMod").append_attribute("val").set_value("102000"); gs_node = grad_fill_list.append_child("a:gs"); gs_node.append_attribute("pos").set_value("50000"); 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("98000"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("130000"); scheme_color_node.append_child("a:shade").append_attribute("val").set_value("90000"); scheme_color_node.append_child("a:lumMod").append_attribute("val").set_value("103000"); 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("63000"); scheme_color_node.append_child("a:satMod").append_attribute("val").set_value("120000"); lin_node = grad_fill_node.append_child("a:lin"); lin_node.append_attribute("ang").set_value("5400000"); lin_node.append_attribute("scaled").set_value("0"); theme_node.append_child("a:objectDefaults"); theme_node.append_child("a:extraClrSchemeLst"); auto ext_lst_node = theme_node.append_child("a:extLst"); auto ext_node = ext_lst_node.append_child("a:ext"); ext_node.append_attribute("uri").set_value("{05A4C25C-085E-4340-85A3-A5531E510DB2}"); auto theme_family_node = ext_node.append_child("thm15:themeFamily"); theme_family_node.append_attribute("xmlns:thm15").set_value("http://schemas.microsoft.com/office/thememl/2012/main"); theme_family_node.append_attribute("name").set_value("Office Theme"); theme_family_node.append_attribute("id").set_value("{62F939B6-93AF-4DB8-9C6B-D6C7DFDC589F}"); theme_family_node.append_attribute("vid").set_value("{4A3C46E8-61CC-4603-A589-7422A47A8E4A}"); } void xlsx_producer::write_volatile_dependencies(const relationship &rel, pugi::xml_node root) { /*auto vol_types_node = */root.append_child("volTypes"); } void xlsx_producer::write_worksheet(const relationship &rel, pugi::xml_node root) { auto title = std::find_if(source_.d_->sheet_title_rel_id_map_.begin(), source_.d_->sheet_title_rel_id_map_.end(), [&](const std::pair &p) { return p.second == rel.get_id(); })->first; auto ws = source_.get_sheet_by_title(title); auto worksheet_node = root.append_child("worksheet"); worksheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); worksheet_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships"); if (ws.x14ac_enabled()) { worksheet_node.append_attribute("xmlns:mc").set_value("http://schemas.openxmlformats.org/markup-compatibility/2006"); worksheet_node.append_attribute("mc:Ignorable").set_value("x14ac"); worksheet_node.append_attribute("xmlns:x14ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"); } if (ws.has_page_setup()) { auto sheet_pr_node = worksheet_node.append_child("sheetPr"); auto outline_pr_node = sheet_pr_node.append_child("outlinePr"); outline_pr_node.append_attribute("summaryBelow").set_value("1"); outline_pr_node.append_attribute("summaryRight").set_value("1"); auto page_set_up_pr_node = sheet_pr_node.append_child("pageSetUpPr"); page_set_up_pr_node.append_attribute("fitToPage").set_value(ws.get_page_setup().fit_to_page() ? "1" : "0"); } if (ws.has_dimension()) { auto dimension_node = worksheet_node.append_child("dimension"); auto dimension = ws.calculate_dimension(); auto dimension_string = dimension.is_single_cell() ? dimension.get_top_left().to_string() : dimension.to_string(); dimension_node.append_attribute("ref").set_value(dimension_string.c_str()); } if (ws.has_view()) { auto sheet_views_node = worksheet_node.append_child("sheetViews"); auto sheet_view_node = sheet_views_node.append_child("sheetView"); const auto view = ws.get_view(); sheet_view_node.append_attribute("tabSelected").set_value("1"); sheet_view_node.append_attribute("workbookViewId").set_value("0"); if (!view.get_selections().empty()) { auto selection_node = sheet_view_node.child("selection") ? sheet_view_node.child("selection") : sheet_view_node.append_child("selection"); const auto &first_selection = view.get_selections().front(); if (first_selection.has_active_cell()) { auto active_cell = first_selection.get_active_cell(); selection_node.append_attribute("activeCell").set_value(active_cell.to_string().c_str()); selection_node.append_attribute("sqref").set_value(active_cell.to_string().c_str()); } } std::string active_pane = "bottomRight"; if (ws.has_frozen_panes()) { auto pane_node = sheet_view_node.append_child("pane"); if (ws.get_frozen_panes().get_column_index() > 1) { pane_node.append_attribute("xSplit").set_value(std::to_string(ws.get_frozen_panes().get_column_index().index - 1).c_str()); active_pane = "topRight"; } if (ws.get_frozen_panes().get_row() > 1) { pane_node.append_attribute("ySplit").set_value(std::to_string(ws.get_frozen_panes().get_row() - 1).c_str()); active_pane = "bottomLeft"; } if (ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1) { auto top_right_node = sheet_view_node.append_child("selection"); top_right_node.append_attribute("pane").set_value("topRight"); auto bottom_left_node = sheet_view_node.append_child("selection"); bottom_left_node.append_attribute("pane").set_value("bottomLeft"); active_pane = "bottomRight"; } pane_node.append_attribute("topLeftCell").set_value(ws.get_frozen_panes().to_string().c_str()); pane_node.append_attribute("activePane").set_value(active_pane.c_str()); pane_node.append_attribute("state").set_value("frozen"); auto selection_node = sheet_view_node.append_child("selection"); if (ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1) { selection_node.append_attribute("pane").set_value("bottomRight"); } else if (ws.get_frozen_panes().get_row() > 1) { selection_node.append_attribute("pane").set_value("bottomLeft"); } else if (ws.get_frozen_panes().get_column_index() > 1) { selection_node.append_attribute("pane").set_value("topRight"); } } } if (ws.has_format_properties()) { auto sheet_format_pr_node = worksheet_node.append_child("sheetFormatPr"); sheet_format_pr_node.append_attribute("baseColWidth").set_value("10"); sheet_format_pr_node.append_attribute("defaultRowHeight").set_value("16"); sheet_format_pr_node.append_attribute("x14ac:dyDescent").set_value("0.2"); } bool has_column_properties = false; for (auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++) { if (ws.has_column_properties(column)) { has_column_properties = true; break; } } if (has_column_properties) { auto cols_node = worksheet_node.append_child("cols"); for (auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++) { if (!ws.has_column_properties(column)) { continue; } const auto &props = ws.get_column_properties(column); auto col_node = cols_node.append_child("col"); col_node.append_attribute("min").set_value(std::to_string(column.index).c_str()); col_node.append_attribute("max").set_value(std::to_string(column.index).c_str()); col_node.append_attribute("width").set_value(std::to_string(props.width).c_str()); col_node.append_attribute("style").set_value(std::to_string(props.style).c_str()); col_node.append_attribute("customWidth").set_value(props.custom ? "1" : "0"); } } std::unordered_map hyperlink_references; auto sheet_data_node = worksheet_node.append_child("sheetData"); const auto &shared_strings = ws.get_workbook().get_shared_strings(); for (auto row : ws.rows()) { auto min = static_cast(row.num_cells()); xlnt::row_t max = 0; bool any_non_null = false; for (auto cell : row) { min = std::min(min, cell.get_column().index); max = std::max(max, cell.get_column().index); if (!cell.garbage_collectible()) { any_non_null = true; } } if (!any_non_null) { continue; } auto row_node = sheet_data_node.append_child("row"); row_node.append_attribute("r").set_value(std::to_string(row.front().get_row()).c_str()); row_node.append_attribute("spans").set_value((std::to_string(min) + ":" + std::to_string(max)).c_str()); if (ws.has_row_properties(row.front().get_row())) { row_node.append_attribute("customHeight").set_value("1"); auto height = ws.get_row_properties(row.front().get_row()).height; if (height == std::floor(height)) { row_node.append_attribute("ht").set_value((std::to_string(static_cast(height)) + ".0").c_str()); } else { row_node.append_attribute("ht").set_value(std::to_string(height).c_str()); } } // row_node.append_attribute("x14ac:dyDescent", 0.25); for (auto cell : row) { if (!cell.garbage_collectible()) { auto cell_node = row_node.append_child("c"); cell_node.append_attribute("r").set_value(cell.get_reference().to_string().c_str()); if (cell.get_data_type() == cell::type::string) { if (cell.has_formula()) { cell_node.append_attribute("t").set_value("str"); cell_node.append_child("f").text().set(cell.get_formula().c_str()); cell_node.append_child("v").text().set(cell.to_string().c_str()); continue; } int match_index = -1; for (std::size_t i = 0; i < shared_strings.size(); i++) { if (shared_strings[i] == cell.get_value()) { match_index = static_cast(i); break; } } if (match_index == -1) { if (cell.get_value().empty()) { cell_node.append_attribute("t").set_value("s"); } else { cell_node.append_attribute("t").set_value("inlineStr"); auto inline_string_node = cell_node.append_child("is"); inline_string_node.append_child("t").text().set(cell.get_value().c_str()); } } else { cell_node.append_attribute("t").set_value("s"); auto value_node = cell_node.append_child("v"); value_node.text().set(std::to_string(match_index).c_str()); } } else { if (cell.get_data_type() != cell::type::null) { if (cell.get_data_type() == cell::type::boolean) { cell_node.append_attribute("t").set_value("b"); auto value_node = cell_node.append_child("v"); value_node.text().set(cell.get_value() ? "1" : "0"); } else if (cell.get_data_type() == cell::type::numeric) { if (cell.has_formula()) { cell_node.append_child("f").text().set(cell.get_formula().c_str()); cell_node.append_child("v").text().set(cell.to_string().c_str()); continue; } cell_node.append_attribute("t").set_value("n"); auto value_node = cell_node.append_child("v"); if (is_integral(cell.get_value())) { value_node.text().set(std::to_string(cell.get_value()).c_str()); } else { std::stringstream ss; ss.precision(20); ss << cell.get_value(); ss.str(); value_node.text().set(ss.str().c_str()); } } } else if (cell.has_formula()) { cell_node.append_child("f").text().set(cell.get_formula().c_str()); cell_node.append_child("v"); continue; } } if (cell.has_format()) { cell_node.append_attribute("s").set_value(std::to_string(cell.get_format().id()).c_str()); } } } } if (ws.has_auto_filter()) { auto auto_filter_node = worksheet_node.append_child("autoFilter"); auto_filter_node.append_attribute("ref").set_value(ws.get_auto_filter().to_string().c_str()); } if (!ws.get_merged_ranges().empty()) { auto merge_cells_node = worksheet_node.append_child("mergeCells"); merge_cells_node.append_attribute("count").set_value(std::to_string(ws.get_merged_ranges().size()).c_str()); for (auto merged_range : ws.get_merged_ranges()) { auto merge_cell_node = merge_cells_node.append_child("mergeCell"); merge_cell_node.append_attribute("ref").set_value(merged_range.to_string().c_str()); } } const auto sheet_rels = source_.get_manifest().get_relationships(rel.get_target().get_path()); if (!sheet_rels.empty()) { std::vector hyperlink_sheet_rels; for (const auto &sheet_rel : sheet_rels) { if (sheet_rel.get_type() == relationship::type::hyperlink) { hyperlink_sheet_rels.push_back(sheet_rel); } } if (!hyperlink_sheet_rels.empty()) { auto hyperlinks_node = worksheet_node.append_child("hyperlinks"); for (const auto &hyperlink_rel : hyperlink_sheet_rels) { auto hyperlink_node = hyperlinks_node.append_child("hyperlink"); hyperlink_node.append_attribute("display").set_value(hyperlink_rel.get_target().get_path().string().c_str()); hyperlink_node.append_attribute("ref").set_value(hyperlink_references.at(hyperlink_rel.get_id()).c_str()); hyperlink_node.append_attribute("r:id").set_value(hyperlink_rel.get_id().c_str()); } } } if (ws.has_page_setup()) { auto print_options_node = worksheet_node.append_child("printOptions"); print_options_node.append_attribute("horizontalCentered").set_value( ws.get_page_setup().get_horizontal_centered() ? "1" : "0"); print_options_node.append_attribute("verticalCentered").set_value( ws.get_page_setup().get_vertical_centered() ? "1" : "0"); } if (ws.has_page_margins()) { auto page_margins_node = worksheet_node.append_child("pageMargins"); //TODO: there must be a better way to do this auto remove_trailing_zeros = [](const std::string &n) { auto decimal = n.find('.'); if (decimal == std::string::npos) return n; auto index = n.size() - 1; while (index >= decimal && n[index] == '0') { index--; } if (index == decimal) { return n.substr(0, decimal); } return n.substr(0, index + 1); }; page_margins_node.append_attribute("left").set_value(remove_trailing_zeros(std::to_string(ws.get_page_margins().get_left())).c_str()); page_margins_node.append_attribute("right").set_value(remove_trailing_zeros(std::to_string(ws.get_page_margins().get_right())).c_str()); page_margins_node.append_attribute("top").set_value(remove_trailing_zeros(std::to_string(ws.get_page_margins().get_top())).c_str()); page_margins_node.append_attribute("bottom").set_value(remove_trailing_zeros(std::to_string(ws.get_page_margins().get_bottom())).c_str()); page_margins_node.append_attribute("header").set_value(remove_trailing_zeros(std::to_string(ws.get_page_margins().get_header())).c_str()); page_margins_node.append_attribute("footer").set_value(remove_trailing_zeros(std::to_string(ws.get_page_margins().get_footer())).c_str()); } if (ws.has_page_setup()) { auto page_setup_node = worksheet_node.append_child("pageSetup"); std::string orientation_string = ws.get_page_setup().get_orientation() == xlnt::orientation::landscape ? "landscape" : "portrait"; page_setup_node.append_attribute("orientation").set_value(orientation_string.c_str()); page_setup_node.append_attribute("paperSize").set_value( std::to_string(static_cast(ws.get_page_setup().get_paper_size())).c_str()); page_setup_node.append_attribute("fitToHeight").set_value(ws.get_page_setup().fit_to_height() ? "1" : "0"); page_setup_node.append_attribute("fitToWidth").set_value(ws.get_page_setup().fit_to_width() ? "1" : "0"); } if (!ws.get_header_footer().is_default()) { auto header_footer_node = worksheet_node.append_child("headerFooter"); auto odd_header_node = header_footer_node.append_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.c_str()); auto odd_footer_node = header_footer_node.append_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.c_str()); } } // Sheet Relationship Target Parts void xlsx_producer::write_comments(const relationship &rel, pugi::xml_node root) { /*auto comments_node = */root.append_child("comments"); } void xlsx_producer::write_drawings(const relationship &rel, pugi::xml_node root) { /*auto ws_dr_node = */root.append_child("wsDr"); } // Other Parts void xlsx_producer::write_custom_property() { } void xlsx_producer::write_unknown_parts() { } void xlsx_producer::write_unknown_relationships() { } void xlsx_producer::write_thumbnail(const relationship &rel) { const auto &thumbnail = source_.get_thumbnail(); std::string thumbnail_string(thumbnail.begin(), thumbnail.end()); destination_.write_string(thumbnail_string, rel.get_target().get_path()); } std::string xlsx_producer::write_bool(bool boolean) const { if (source_.d_->short_bools_) { return boolean ? "1" : "0"; } return boolean ? "true" : "false"; } } // namespace detail } // namepsace xlnt