diff --git a/.gitmodules b/.gitmodules index 7dcbe7b5..d04a3132 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,8 @@ path = third-party/utfcpp url = https://github.com/nemtrif/utfcpp branch = master + +[submodule "third-party/pugixml"] + path = third-party/pugixml + url = https://github.com/zeux/pugixml + branch = master diff --git a/cmake/xlnt.cmake b/cmake/xlnt.cmake index f99d1717..4d28b528 100644 --- a/cmake/xlnt.cmake +++ b/cmake/xlnt.cmake @@ -28,7 +28,7 @@ include_directories(include) include_directories(include/xlnt) include_directories(source) include_directories(third-party/miniz) -include_directories(third-party/pugixml/src) +include_directories(third-party/libstudxml) include_directories(third-party/utfcpp/source) FILE(GLOB ROOT_HEADERS include/xlnt/*.hpp) @@ -64,14 +64,13 @@ SET(SOURCES ${CELL_SOURCES} ${CHARTS_SOURCES} ${CHARTSHEET_SOURCES} ${DRAWING_SO SET(MINIZ ../third-party/miniz/miniz.c ../third-party/miniz/miniz.h) -SET(PUGIXML ../third-party/pugixml/src/pugixml.hpp ../third-party/pugixml/src/pugixml.cpp ../third-party/pugixml/src/pugiconfig.hpp) +SET(LIBSTUDXML ../third-party/libstudxml/xml/parser.cxx) if(SHARED) - add_library(xlnt.shared SHARED ${HEADERS} ${SOURCES} ${MINIZ} ${PUGIXML}) + add_library(xlnt.shared SHARED ${HEADERS} ${SOURCES} ${MINIZ} ${LIBSTUDXML}) target_compile_definitions(xlnt.shared PRIVATE XLNT_SHARED=1) if(MSVC) target_compile_definitions(xlnt.shared PRIVATE XLNT_EXPORT=1) - target_compile_definitions(xlnt.shared PRIVATE PUGIXML_API=__declspec\(dllexport\)) set_target_properties(xlnt.shared PROPERTIES COMPILE_FLAGS "/wd\"4251\" /wd\"4275\"") endif() install(TARGETS xlnt.shared @@ -102,7 +101,7 @@ if(SHARED) endif() if(STATIC) - add_library(xlnt.static STATIC ${HEADERS} ${SOURCES} ${MINIZ} ${PUGIXML}) + add_library(xlnt.static STATIC ${HEADERS} ${SOURCES} ${MINIZ} ${LIBSTUDXML}) target_compile_definitions(xlnt.static PUBLIC XLNT_STATIC=1) install(TARGETS xlnt.static LIBRARY DESTINATION ${LIB_DEST_DIR} @@ -130,7 +129,7 @@ source_group(utils FILES ${UTILS_HEADERS} ${UTILS_SOURCES}) source_group(workbook FILES ${WORKBOOK_HEADERS} ${WORKBOOK_SOURCES}) source_group(worksheet FILES ${WORKSHEET_HEADERS} ${WORKSHEET_SOURCES}) source_group(third-party\\miniz FILES ${MINIZ}) -source_group(third-party\\pugixml FILES ${PUGIXML}) +source_group(third-party\\libstudxml FILES ${LIBSTUDXML}) SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) diff --git a/source/detail/include_pugixml.hpp b/source/detail/include_libstudxml.hpp similarity index 87% rename from source/detail/include_pugixml.hpp rename to source/detail/include_libstudxml.hpp index 13fca0fb..6ffaa583 100644 --- a/source/detail/include_pugixml.hpp +++ b/source/detail/include_libstudxml.hpp @@ -22,9 +22,7 @@ // @author: see AUTHORS file #pragma once -/// -/// Define this here so we don't have to modify pugiconfig.hpp in pugixml source tree. -/// -#define PUGIXML_HAS_LONG_LONG - -#include +#include +#include +#include +#include \ No newline at end of file diff --git a/source/detail/xlsx_consumer.cpp b/source/detail/xlsx_consumer.cpp index f51e22d5..ccc989a3 100644 --- a/source/detail/xlsx_consumer.cpp +++ b/source/detail/xlsx_consumer.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -222,20 +221,36 @@ std::string to_string(xlnt::border_side side) } } -xlnt::protection read_protection(const pugi::xml_node protection_node) +xlnt::protection read_protection(xml::parser &parser) { xlnt::protection prot; - prot.locked(is_true(protection_node.attribute("locked").value())); - prot.hidden(is_true(protection_node.attribute("hidden").value())); + for (auto event : parser) + { + if (event == xml::parser::event_type::start_attribute) + { + if (parser.name() == "locked") + { + prot.locked(is_true(parser.value())); + } + else if (parser.name() == "hidden") + { + prot.hidden(is_true(parser.value())); + } + } + else + { + break; + } + } return prot; } -xlnt::alignment read_alignment(const pugi::xml_node alignment_node) +xlnt::alignment read_alignment(xml::parser &parser) { xlnt::alignment align; - +/* align.wrap(is_true(alignment_node.attribute("wrapText").value())); align.shrink(is_true(alignment_node.attribute("shrinkToFit").value())); @@ -250,14 +265,14 @@ xlnt::alignment read_alignment(const pugi::xml_node alignment_node) std::string horizontal = alignment_node.attribute("horizontal").value(); align.horizontal(from_string(horizontal)); } - +*/ return align; } -void read_number_formats(const pugi::xml_node number_formats_node, std::vector &number_formats) +void read_number_formats(xml::parser &parser, std::vector &number_formats) { number_formats.clear(); - +/* for (auto num_fmt_node : number_formats_node.children("numFmt")) { std::string format_string(num_fmt_node.attribute("formatCode").value()); @@ -274,12 +289,13 @@ void read_number_formats(const pugi::xml_node number_formats_node, std::vector &fonts) +void read_fonts(xml::parser &parser, std::vector &fonts) { fonts.clear(); - +/* for (auto font_node : fonts_node.children()) { fonts.push_back(read_font(font_node)); } +*/ } -void read_indexed_colors(const pugi::xml_node &indexed_colors_node, std::vector &colors) +void read_indexed_colors(xml::parser &parser, std::vector &colors) { +/* for (auto color_node : indexed_colors_node.children()) { colors.push_back(read_color(color_node)); } +*/ } -void read_colors(const pugi::xml_node &colors_node, std::vector &colors) +void read_colors(xml::parser &parser, std::vector &colors) { colors.clear(); - +/* if (colors_node.child("indexedColors")) { read_indexed_colors(colors_node.child("indexedColors"), colors); } +*/ } -xlnt::fill read_fill(const pugi::xml_node &fill_node) +xlnt::fill read_fill(xml::parser &parser) { xlnt::fill new_fill; - +/* if (fill_node.child("patternFill")) { auto pattern_fill_node = fill_node.child("patternFill"); @@ -462,25 +482,26 @@ xlnt::fill read_fill(const pugi::xml_node &fill_node) new_fill = gradient; } - +*/ return new_fill; } -void read_fills(const pugi::xml_node &fills_node, std::vector &fills) +void read_fills(xml::parser &parser, std::vector &fills) { fills.clear(); - +/* for (auto fill_node : fills_node.children()) { fills.emplace_back(); fills.back() = read_fill(fill_node); } +*/ } -xlnt::border::border_property read_side(const pugi::xml_node &side_node) +xlnt::border::border_property read_side(xml::parser &parser) { xlnt::border::border_property new_side; - +/* if (side_node.attribute("style")) { new_side.style(from_string(side_node.attribute("style").value())); @@ -490,14 +511,14 @@ xlnt::border::border_property read_side(const pugi::xml_node &side_node) { new_side.color(read_color(side_node.child("color"))); } - +*/ return new_side; } -xlnt::border read_border(const pugi::xml_node &border_node) +xlnt::border read_border(xml::parser &parser) { xlnt::border new_border; - +/* for (const auto &side : xlnt::border::all_sides()) { auto side_name = to_string(side); @@ -507,41 +528,53 @@ xlnt::border read_border(const pugi::xml_node &border_node) new_border.side(side, read_side(border_node.child(side_name.c_str()))); } } - +*/ return new_border; } -void read_borders(const pugi::xml_node &borders_node, std::vector &borders) +void read_borders(xml::parser &parser, std::vector &borders) { borders.clear(); - +/* for (auto border_node : borders_node.children()) { borders.push_back(read_border(border_node)); } +*/ } std::vector read_relationships(const xlnt::path &part, xlnt::zip_file &archive) { std::vector relationships; - if (!archive.has_file(part)) return relationships; - pugi::xml_document document; - document.load_string(archive.read(part).c_str()); + std::istringstream rels_stream(archive.read(part)); + xml::parser parser(rels_stream, part.string()); - auto root_node = document.child("Relationships"); xlnt::uri source(part.string()); - for (auto relationship_node : root_node.children("Relationship")) - { - std::string id(relationship_node.attribute("Id").value()); - std::string type_string(relationship_node.attribute("Type").value()); - auto type = from_string(type_string); - xlnt::uri target(relationship_node.attribute("Target").value()); + const auto xmlns = xlnt::constants::get_namespace("relationships"); + parser.next_expect(xml::parser::event_type::start_element, xmlns, "Relationships"); + parser.content(xml::content::complex); - relationships.push_back(xlnt::relationship(id, type, source, target, xlnt::target_mode::internal)); + while (true) + { + if (parser.peek() == xml::parser::event_type::end_element) break; + + parser.next_expect(xml::parser::event_type::start_element, xmlns, "Relationship"); + + std::string id(parser.attribute("Id")); + std::string type_string(parser.attribute("Type")); + xlnt::uri target(parser.attribute("Target")); + + relationships.emplace_back(id, from_string(type_string), + source, target, xlnt::target_mode::internal); + + parser.next_expect(xml::parser::event_type::end_element, + xlnt::constants::get_namespace("relationships"), "Relationship"); } + + parser.next_expect(xml::parser::event_type::end_element, xmlns, "Relationships"); return relationships; } @@ -594,56 +627,56 @@ void xlsx_consumer::populate_workbook() for (const auto &rel : manifest.get_relationships(path("/"))) { - pugi::xml_document document; - document.load_string(source_.read(rel.get_target().get_path()).c_str()); + std::istringstream parser_stream(source_.read(rel.get_target().get_path())); + xml::parser parser(parser_stream, rel.get_target().get_path().string()); switch (rel.get_type()) { case relationship::type::core_properties: - read_core_properties(document.root()); + read_core_properties(parser); break; case relationship::type::extended_properties: - read_extended_properties(document.root()); + read_extended_properties(parser); break; case relationship::type::custom_properties: - read_custom_property(document.root()); + read_custom_property(parser); break; case relationship::type::office_document: check_document_type(manifest.get_content_type(rel.get_target().get_path())); - read_workbook(document.root()); + read_workbook(parser); break; case relationship::type::calculation_chain: - read_calculation_chain(document.root()); + read_calculation_chain(parser); break; case relationship::type::connections: - read_connections(document.root()); + read_connections(parser); break; case relationship::type::custom_xml_mappings: - read_custom_xml_mappings(document.root()); + read_custom_xml_mappings(parser); break; case relationship::type::external_workbook_references: - read_external_workbook_references(document.root()); + read_external_workbook_references(parser); break; case relationship::type::metadata: - read_metadata(document.root()); + read_metadata(parser); break; case relationship::type::pivot_table: - read_pivot_table(document.root()); + read_pivot_table(parser); break; case relationship::type::shared_string_table: - read_shared_string_table(document.root()); + read_shared_string_table(parser); break; case relationship::type::shared_workbook_revision_headers: - read_shared_workbook_revision_headers(document.root()); + read_shared_workbook_revision_headers(parser); break; case relationship::type::styles: - read_stylesheet(document.root()); + read_stylesheet(parser); break; case relationship::type::theme: - read_theme(document.root()); + read_theme(parser); break; case relationship::type::volatile_dependencies: - read_volatile_dependencies(document.root()); + read_volatile_dependencies(parser); break; default: break; @@ -656,20 +689,20 @@ void xlsx_consumer::populate_workbook() for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path())) { - pugi::xml_document document; path part_path(rel.get_source().get_path().parent().append(rel.get_target().get_path())); - document.load_string(source_.read(part_path).c_str()); + std::istringstream parser_stream(source_.read(part_path)); + xml::parser parser(parser_stream, rel.get_target().get_path().string()); switch (rel.get_type()) { case relationship::type::shared_string_table: - read_shared_string_table(document); + read_shared_string_table(parser); break; case relationship::type::styles: - read_stylesheet(document); + read_stylesheet(parser); break; case relationship::type::theme: - read_theme(document); + read_theme(parser); break; default: break; @@ -679,21 +712,21 @@ void xlsx_consumer::populate_workbook() // Second pass, read sheets themselves for (const auto &rel : manifest.get_relationships(workbook_rel.get_target().get_path())) - { - pugi::xml_document document; + { path part_path(rel.get_source().get_path().parent().append(rel.get_target().get_path())); - document.load_string(source_.read(part_path).c_str()); + std::istringstream parser_stream(source_.read(part_path)); + xml::parser parser(parser_stream, rel.get_target().get_path().string()); switch (rel.get_type()) { case relationship::type::chartsheet: - read_chartsheet(document.root(), rel.get_id()); + read_chartsheet(rel.get_id(), parser); break; case relationship::type::dialogsheet: - read_dialogsheet(document.root(), rel.get_id()); + read_dialogsheet(rel.get_id(), parser); break; case relationship::type::worksheet: - read_worksheet(document.root(), rel.get_id()); + read_worksheet(rel.get_id(), parser); break; default: break; @@ -714,25 +747,36 @@ void xlsx_consumer::read_manifest() if (!source_.has_file(package_rels_path)) throw invalid_file("missing package rels"); auto package_rels = read_relationships(package_rels_path, source_); - pugi::xml_document document; - document.load_string(source_.read(path("[Content_Types].xml")).c_str()); - - const auto root_node = document.child("Types"); + std::istringstream parser_stream(source_.read(path("[Content_Types].xml"))); + xml::parser parser(parser_stream, "[Content_Types].xml"); + auto &manifest = destination_.get_manifest(); + + const std::string xmlns = "http://schemas.openxmlformats.org/package/2006/content-types"; + parser.next_expect(xml::parser::event_type::start_element, xmlns, "Types"); + parser.content(xml::content::complex); - for (const auto child : root_node.children()) + while (true) { - if (child.name() == std::string("Default")) - { - manifest.register_default_type(child.attribute("Extension").value(), - child.attribute("ContentType").value()); - } - else if (child.name() == std::string("Override")) - { - path part(child.attribute("PartName").value()); - manifest.register_override_type(part, child.attribute("ContentType").value()); - } + if (parser.peek() == xml::parser::event_type::end_element) break; + + parser.next_expect(xml::parser::event_type::start_element); + + if (parser.name() == "Default") + { + manifest.register_default_type(parser.attribute("Extension"), + parser.attribute("ContentType")); + parser.next_expect(xml::parser::event_type::end_element, xmlns, "Default"); + } + else if (parser.name() == "Override") + { + manifest.register_override_type(path(parser.attribute("PartName")), + parser.attribute("ContentType")); + parser.next_expect(xml::parser::event_type::end_element, xmlns, "Override"); + } } + + parser.next_expect(xml::parser::event_type::end_element, xmlns, "Types"); for (const auto &package_rel : package_rels) { @@ -765,8 +809,9 @@ void xlsx_consumer::read_manifest() } } -void xlsx_consumer::read_extended_properties(const pugi::xml_node root) +void xlsx_consumer::read_extended_properties(xml::parser &parser) { +/* for (auto property_node : root.child("Properties")) { std::string name(property_node.name()); @@ -781,10 +826,12 @@ void xlsx_consumer::read_extended_properties(const pugi::xml_node root) else if (name == "AppVersion") destination_.set_app_version(value); else if (name == "Application") destination_.set_application(value); } + */ } -void xlsx_consumer::read_core_properties(const pugi::xml_node root) +void xlsx_consumer::read_core_properties(xml::parser &parser) { +/* for (auto property_node : root.child("cp:coreProperties")) { std::string name(property_node.name()); @@ -795,19 +842,23 @@ void xlsx_consumer::read_core_properties(const pugi::xml_node root) else if (name == "dcterms:created") destination_.set_created(w3cdtf_to_datetime(value)); else if (name == "dcterms:modified") destination_.set_modified(w3cdtf_to_datetime(value)); } + */ } -void xlsx_consumer::read_custom_file_properties(const pugi::xml_node root) +void xlsx_consumer::read_custom_file_properties(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */document.append_child("customFileProperties"); + document.append_child("customFileProperties"); + */ } // Write SpreadsheetML-Specific Package Parts -void xlsx_consumer::read_workbook(const pugi::xml_node root) +void xlsx_consumer::read_workbook(xml::parser &parser) { +/* auto workbook_node = root.child("workbook"); if (workbook_node.attribute("xmlns:x15")) @@ -887,72 +938,90 @@ void xlsx_consumer::read_workbook(const pugi::xml_node root) { destination_.d_->has_arch_id_ = true; } + */ } // Write Workbook Relationship Target Parts -void xlsx_consumer::read_calculation_chain(const pugi::xml_node root) +void xlsx_consumer::read_calculation_chain(xml::parser &parser) { } -void xlsx_consumer::read_chartsheet(const pugi::xml_node root, const std::string &title) +void xlsx_consumer::read_chartsheet(const std::string &title, xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("chartsheet"); + document.append_child("chartsheet"); + */ } -void xlsx_consumer::read_connections(const pugi::xml_node root) +void xlsx_consumer::read_connections(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("connections"); + document.append_child("connections"); + */ } -void xlsx_consumer::read_custom_property(const pugi::xml_node root) +void xlsx_consumer::read_custom_property(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("customProperty"); + document.append_child("customProperty"); + */ } -void xlsx_consumer::read_custom_xml_mappings(const pugi::xml_node root) +void xlsx_consumer::read_custom_xml_mappings(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("connections"); + document.append_child("connections"); + */ } -void xlsx_consumer::read_dialogsheet(const pugi::xml_node root, const std::string &title) +void xlsx_consumer::read_dialogsheet(const std::string &title, xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("dialogsheet"); + document.append_child("dialogsheet"); + */ } -void xlsx_consumer::read_external_workbook_references(const pugi::xml_node root) +void xlsx_consumer::read_external_workbook_references(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("externalLink"); + document.append_child("externalLink"); + */ } -void xlsx_consumer::read_metadata(const pugi::xml_node root) +void xlsx_consumer::read_metadata(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("metadata"); + document.append_child("metadata"); + */ } -void xlsx_consumer::read_pivot_table(const pugi::xml_node root) +void xlsx_consumer::read_pivot_table(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("pivotTableDefinition"); + document.append_child("pivotTableDefinition"); + */ } -void xlsx_consumer::read_shared_string_table(const pugi::xml_node root) +void xlsx_consumer::read_shared_string_table(xml::parser &parser) { +/* auto sst_node = root.child("sst"); std::size_t unique_count = 0; @@ -1025,31 +1094,39 @@ void xlsx_consumer::read_shared_string_table(const pugi::xml_node root) { throw invalid_file("sizes don't match"); } + */ } -void xlsx_consumer::read_shared_workbook_revision_headers(const pugi::xml_node root) +void xlsx_consumer::read_shared_workbook_revision_headers(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("headers"); + document.append_child("headers"); + */ } -void xlsx_consumer::read_shared_workbook(const pugi::xml_node root) +void xlsx_consumer::read_shared_workbook(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("revisions"); + document.append_child("revisions"); + */ } -void xlsx_consumer::read_shared_workbook_user_data(const pugi::xml_node root) +void xlsx_consumer::read_shared_workbook_user_data(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("users"); + document.append_child("users"); + */ } -void xlsx_consumer::read_stylesheet(const pugi::xml_node root) +void xlsx_consumer::read_stylesheet(xml::parser &parser) { +/* auto stylesheet_node = root.child("styleSheet"); auto &stylesheet = destination_.impl().stylesheet_; @@ -1192,23 +1269,29 @@ void xlsx_consumer::read_stylesheet(const pugi::xml_node root) format.style(stylesheet.get_style(style_name)); } } + */ } -void xlsx_consumer::read_theme(const pugi::xml_node root) +void xlsx_consumer::read_theme(xml::parser &parser) { +/* root.child("theme"); destination_.set_theme(theme()); + */ } -void xlsx_consumer::read_volatile_dependencies(const pugi::xml_node root) +void xlsx_consumer::read_volatile_dependencies(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("volTypes"); + document.append_child("volTypes"); + */ } -void xlsx_consumer::read_worksheet(const pugi::xml_node root, const std::string &rel_id) +void xlsx_consumer::read_worksheet(const std::string &title, xml::parser &parser) { +/* auto title = std::find_if(destination_.d_->sheet_title_rel_id_map_.begin(), destination_.d_->sheet_title_rel_id_map_.end(), [&](const std::pair &p) @@ -1425,38 +1508,47 @@ void xlsx_consumer::read_worksheet(const pugi::xml_node root, const std::string ws.set_page_margins(margins); } + */ } // Sheet Relationship Target Parts -void xlsx_consumer::read_comments(const pugi::xml_node root) +void xlsx_consumer::read_comments(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("comments"); + document.append_child("comments"); + */ } -void xlsx_consumer::read_drawings(const pugi::xml_node root) +void xlsx_consumer::read_drawings(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("wsDr"); + document.append_child("wsDr"); + */ } // Unknown Parts -void xlsx_consumer::read_unknown_parts(const pugi::xml_node root) +void xlsx_consumer::read_unknown_parts(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("Hmm"); + document.append_child("Hmm"); + */ } -void xlsx_consumer::read_unknown_relationships(const pugi::xml_node root) +void xlsx_consumer::read_unknown_relationships(xml::parser &parser) { +/* pugi::xml_document document; document.load_string(source_.read(path("[Content Types].xml")).c_str()); - /*auto root_node = */ document.append_child("Relationships"); + document.append_child("Relationships"); + */ } } // namespace detail diff --git a/source/detail/xlsx_consumer.hpp b/source/detail/xlsx_consumer.hpp index bd8c4adf..695487da 100644 --- a/source/detail/xlsx_consumer.hpp +++ b/source/detail/xlsx_consumer.hpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include @@ -65,44 +65,44 @@ private: void read_manifest(); - void read_core_properties(const pugi::xml_node root); - void read_extended_properties(const pugi::xml_node root); - void read_custom_file_properties(const pugi::xml_node root); + void read_core_properties(xml::parser &parser); + void read_extended_properties(xml::parser &parser); + void read_custom_file_properties(xml::parser &parser); // SpreadsheetML-Specific Package Parts - void read_workbook(const pugi::xml_node root); + void read_workbook(xml::parser &parser); // Workbook Relationship Target Parts - void read_calculation_chain(const pugi::xml_node root); - void read_connections(const pugi::xml_node root); - void read_custom_property(const pugi::xml_node root); - void read_custom_xml_mappings(const pugi::xml_node root); - void read_external_workbook_references(const pugi::xml_node root); - void read_metadata(const pugi::xml_node root); - void read_pivot_table(const pugi::xml_node root); - void read_shared_string_table(const pugi::xml_node root); - void read_shared_workbook_revision_headers(const pugi::xml_node root); - void read_shared_workbook(const pugi::xml_node root); - void read_shared_workbook_user_data(const pugi::xml_node root); - void read_stylesheet(const pugi::xml_node root); - void read_theme(const pugi::xml_node root); - void read_volatile_dependencies(const pugi::xml_node root); + void read_calculation_chain(xml::parser &parser); + void read_connections(xml::parser &parser); + void read_custom_property(xml::parser &parser); + void read_custom_xml_mappings(xml::parser &parser); + void read_external_workbook_references(xml::parser &parser); + void read_metadata(xml::parser &parser); + void read_pivot_table(xml::parser &parser); + void read_shared_string_table(xml::parser &parser); + void read_shared_workbook_revision_headers(xml::parser &parser); + void read_shared_workbook(xml::parser &parser); + void read_shared_workbook_user_data(xml::parser &parser); + void read_stylesheet(xml::parser &parser); + void read_theme(xml::parser &parser); + void read_volatile_dependencies(xml::parser &parser); - void read_chartsheet(const pugi::xml_node root, const std::string &title); - void read_dialogsheet(const pugi::xml_node root, const std::string &title); - void read_worksheet(const pugi::xml_node root, const std::string &title); + void read_chartsheet(const std::string &title, xml::parser &parser); + void read_dialogsheet(const std::string &title, xml::parser &parser); + void read_worksheet(const std::string &title, xml::parser &parser); // Sheet Relationship Target Parts - void read_comments(const pugi::xml_node root); - void read_drawings(const pugi::xml_node root); + void read_comments(xml::parser &parser); + void read_drawings(xml::parser &parser); // Unknown Parts - void read_unknown_parts(const pugi::xml_node root); - void read_unknown_relationships(const pugi::xml_node root); + void read_unknown_parts(xml::parser &parser); + void read_unknown_relationships(xml::parser &parser); /// /// A reference to the archive from which files representing the workbook diff --git a/source/detail/xlsx_producer.cpp b/source/detail/xlsx_producer.cpp index e3de2122..e9eba970 100644 --- a/source/detail/xlsx_producer.cpp +++ b/source/detail/xlsx_producer.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -23,17 +22,6 @@ 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) @@ -195,78 +183,78 @@ std::string to_string(xlnt::border_side side) } } -void write_relationships(const std::vector &relationships, pugi::xml_node root) +void write_relationships(const std::vector &relationships, xml::serializer &serializer) { - auto relationships_node = root.append_child("Relationships"); - relationships_node.append_attribute("xmlns").set_value(xlnt::constants::get_namespace("relationships").c_str()); + const auto xmlns = xlnt::constants::get_namespace("relationships"); + + serializer.start_element(xmlns, "Relationships"); + serializer.namespace_decl(xmlns, ""); for (const auto &relationship : relationships) { - auto relationship_node = relationships_node.append_child("Relationship"); + serializer.start_element(xmlns, "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()); + serializer.attribute("Id", relationship.get_id()); + serializer.attribute("Type", to_string(relationship.get_type())); + serializer.attribute("Target", relationship.get_target().get_path().string()); if (relationship.get_target_mode() == xlnt::target_mode::external) { - relationship_node.append_attribute("TargetMode").set_value("External"); + serializer.attribute("TargetMode", "External"); } + + serializer.end_element(xmlns, "Relationship"); } + + serializer.end_element(xmlns, "Relationships"); } -bool write_color(const xlnt::color &color, pugi::xml_node color_node) +bool write_color(const xlnt::color &color, xml::serializer &serializer) { 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()); + serializer.attribute("theme", std::to_string(color.get_theme().get_index())); break; case xlnt::color::type::indexed: - color_node.append_attribute("indexed") - .set_value(std::to_string(color.get_indexed().get_index()).c_str()); + serializer.attribute("indexed", std::to_string(color.get_indexed().get_index())); break; case xlnt::color::type::rgb: default: - color_node.append_attribute("rgb") - .set_value(color.get_rgb().get_hex_string().c_str()); + serializer.attribute("rgb", color.get_rgb().get_hex_string()); break; } return true; } -bool write_dxfs(pugi::xml_node &dxfs_node) +void write_dxfs(xml::serializer &serializer) { - dxfs_node.append_attribute("count").set_value("0"); - return true; + serializer.attribute("count", "0"); } -bool write_table_styles(pugi::xml_node &table_styles_node) +void write_table_styles(xml::serializer &serializer) { - 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; + serializer.attribute("count", "0"); + serializer.attribute("defaultTableStyle", "TableStyleMedium9"); + serializer.attribute("defaultPivotStyle", "PivotStyleMedium7"); } -bool write_colors(const std::vector &colors, pugi::xml_node &colors_node) +void write_colors(const std::vector &colors, xml::serializer &serializer) { - auto indexed_colors_node = colors_node.append_child("indexedColors"); + serializer.start_element("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()); + serializer.start_element("rgbColor"); + serializer.attribute("rgb", c.get_rgb().get_hex_string()); + serializer.end_element(); } - return true; + serializer.end_element(); } } // namespace @@ -304,25 +292,27 @@ void xlsx_producer::populate_archive() for (auto &rel : source_.impl().manifest_.get_relationships(path("/"))) { - pugi::xml_document document; + std::ostringstream serializer_stream; + xml::serializer serializer(serializer_stream, rel.get_target().get_path().string()); + bool write_document = true; switch (rel.get_type()) { case relationship::type::core_properties: - write_core_properties(rel, document.root()); + write_core_properties(rel, serializer); break; case relationship::type::extended_properties: - write_extended_properties(rel, document.root()); + write_extended_properties(rel, serializer); break; case relationship::type::custom_properties: - write_custom_properties(rel, document.root()); + write_custom_properties(rel, serializer); break; case relationship::type::office_document: - write_workbook(rel, document.root()); + write_workbook(rel, serializer); break; case relationship::type::thumbnail: @@ -336,7 +326,7 @@ void xlsx_producer::populate_archive() if (write_document) { - write_document_to_archive(document, rel.get_target().get_path(), destination_); + destination_.write_string(serializer_stream.str(), rel.get_target().get_path()); } } @@ -350,26 +340,33 @@ void xlsx_producer::populate_archive() void xlsx_producer::write_manifest() { - pugi::xml_document content_types_document; + std::ostringstream content_types_stream; + xml::serializer content_types_serializer(content_types_stream, "[Content_Types].xml"); - auto types_node = content_types_document.append_child("Types"); - types_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/package/2006/content-types"); + const auto xmlns = std::string("http://schemas.openxmlformats.org/package/2006/content-types"); + + content_types_serializer.start_element(xmlns, "Types"); + content_types_serializer.namespace_decl(xmlns, ""); 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()); + content_types_serializer.start_element(xmlns, "Default"); + content_types_serializer.attribute("Extension", extension); + content_types_serializer.attribute("ContentType", + source_.get_manifest().get_default_type(extension)); + content_types_serializer.end_element(xmlns, "Default"); } 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()); + content_types_serializer.start_element(xmlns, "Override"); + content_types_serializer.attribute("PartName", part.resolve(path("/")).string()); + content_types_serializer.attribute("ContentType", + source_.get_manifest().get_override_type(part)); + content_types_serializer.end_element(xmlns, "Override"); } + + content_types_serializer.end_element(xmlns, "Types"); for (const auto &part : source_.get_manifest().get_parts()) { @@ -377,8 +374,6 @@ void xlsx_producer::write_manifest() 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()) @@ -386,24 +381,29 @@ void xlsx_producer::write_manifest() parent = path(parent.string().substr(1)); } + std::ostringstream rels_stream; path rels_path(parent.append("_rels").append(part.filename() + ".rels").string()); - write_document_to_archive(part_rels_document, rels_path, destination_); + xml::serializer rels_serializer(rels_stream, rels_path.string()); + + write_relationships(part_rels, rels_serializer); + + destination_.write_string(rels_stream.str(), rels_path); } - write_document_to_archive(content_types_document, path("[Content_Types].xml"), destination_); + destination_.write_string(content_types_stream.str(), path("[Content_Types].xml")); } -void xlsx_producer::write_extended_properties(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_extended_properties(const relationship &rel, xml::serializer &serializer) { - auto properties_node = root.append_child("Properties"); + serializer.start_element("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"); + serializer.namespace_decl("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", "xmlns"); + serializer.namespace_decl("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes", "vt"); + serializer.element("Application", source_.get_application()); + serializer.element("DocSecurity", std::to_string(source_.get_doc_security())); + serializer.element("ScaleCrop", 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"); @@ -434,10 +434,12 @@ void xlsx_producer::write_extended_properties(const relationship &rel, pugi::xml 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) +void xlsx_producer::write_core_properties(const relationship &rel, xml::serializer &serializer) { +/* 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"); @@ -457,7 +459,7 @@ void xlsx_producer::write_core_properties(const relationship &rel, pugi::xml_nod { 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"); @@ -466,14 +468,14 @@ void xlsx_producer::write_core_properties(const relationship &rel, pugi::xml_nod */ } -void xlsx_producer::write_custom_properties(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_custom_properties(const relationship &rel, xml::serializer &serializer) { - /*auto properties_node = */root.append_child("Properties"); + serializer.element("Properties"); } // Write SpreadsheetML-Specific Package Parts -void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_workbook(const relationship &rel, xml::serializer &serializer) { std::size_t num_visible = 0; bool any_defined_names = false; @@ -496,18 +498,19 @@ void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root) throw no_visible_worksheets(); } - auto workbook_node = root.append_child("workbook"); + const auto xmlns = std::string("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); - 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"); + serializer.start_element(xmlns, "workbook"); + serializer.namespace_decl(xmlns, ""); + serializer.namespace_decl("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); 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"); + serializer.namespace_decl("http://schemas.openxmlformats.org/markup-compatibility/2006", "mc"); + serializer.attribute("mc:Ignorable", "x15"); + serializer.namespace_decl("http://schemas.microsoft.com/office/spreadsheetml/2010/11/main", "x15"); } - +/* if (source_.has_file_version()) { auto file_version_node = workbook_node.append_child("fileVersion"); @@ -527,10 +530,8 @@ void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root) 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"); - */ +// 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()) @@ -570,31 +571,32 @@ void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root) 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; - + serializer.start_element(xmlns, "sheets"); +/* 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()); + serializer.start_element(xmlns, "sheet"); + serializer.attribute("name", ws.get_title()); + serializer.attribute("sheetId", std::to_string(ws.get_id())); if (ws.has_page_setup() && ws.get_sheet_state() == xlnt::sheet_state::hidden) { - sheet_node.append_attribute("state").set_value("hidden"); + serializer.attribute("state", "hidden"); } - sheet_node.append_attribute("r:id").set_value(sheet_rel_id.c_str()); - + serializer.attribute("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "id", sheet_rel_id); +/* if (ws.has_auto_filter()) { auto defined_name_node = defined_names_node.append_child("definedName"); @@ -605,8 +607,11 @@ void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root) "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string(); defined_name_node.text().set(name.c_str()); } + */ + + serializer.end_element(xmlns, "sheet"); } - +/* if (source_.has_calculation_properties()) { auto calc_pr_node = workbook_node.append_child("calcPr"); @@ -643,67 +648,72 @@ void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root) auto arch_id_node = ext_node.append_child("mx:ArchID"); arch_id_node.append_attribute("Flags").set_value("2"); } + */ + + serializer.end_element(xmlns, "sheets"); + serializer.end_element(xmlns, "workbook"); for (const auto &child_rel : source_.get_manifest().get_relationships(rel.get_target().get_path())) { - pugi::xml_document document; + std::ostringstream child_stream; + xml::serializer child_serializer(child_stream, child_rel.get_target().get_path().string()); switch (child_rel.get_type()) { case relationship::type::calculation_chain: - write_calculation_chain(child_rel, document.root()); + write_calculation_chain(child_rel, child_serializer); break; case relationship::type::chartsheet: - write_chartsheet(child_rel, document.root()); + write_chartsheet(child_rel, child_serializer); break; case relationship::type::connections: - write_connections(child_rel, document.root()); + write_connections(child_rel, child_serializer); break; case relationship::type::custom_xml_mappings: - write_custom_xml_mappings(child_rel, document.root()); + write_custom_xml_mappings(child_rel, child_serializer); break; case relationship::type::dialogsheet: - write_dialogsheet(child_rel, document.root()); + write_dialogsheet(child_rel, child_serializer); break; case relationship::type::external_workbook_references: - write_external_workbook_references(child_rel, document.root()); + write_external_workbook_references(child_rel, child_serializer); break; case relationship::type::metadata: - write_metadata(child_rel, document.root()); + write_metadata(child_rel, child_serializer); break; case relationship::type::pivot_table: - write_pivot_table(child_rel, document.root()); + write_pivot_table(child_rel, child_serializer); break; case relationship::type::shared_string_table: - write_shared_string_table(child_rel, document.root()); + write_shared_string_table(child_rel, child_serializer); break; case relationship::type::shared_workbook_revision_headers: - write_shared_workbook_revision_headers(child_rel, document.root()); + write_shared_workbook_revision_headers(child_rel, child_serializer); break; case relationship::type::styles: - write_styles(child_rel, document.root()); + write_styles(child_rel, child_serializer); break; case relationship::type::theme: - write_theme(child_rel, document.root()); + write_theme(child_rel, child_serializer); break; case relationship::type::volatile_dependencies: - write_volatile_dependencies(child_rel, document.root()); + write_volatile_dependencies(child_rel, child_serializer); break; case relationship::type::worksheet: - write_worksheet(child_rel, document.root()); + write_worksheet(child_rel, child_serializer); break; default: @@ -711,56 +721,56 @@ void xlsx_producer::write_workbook(const relationship &rel, pugi::xml_node root) } 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_); + destination_.write_string(child_stream.str(), archive_path); } } // Write Workbook Relationship Target Parts -void xlsx_producer::write_calculation_chain(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_calculation_chain(const relationship &rel, xml::serializer &serializer) { - /*auto calc_chain_node = */root.append_child("calcChain"); + serializer.start_element("calcChain"); } -void xlsx_producer::write_chartsheet(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_chartsheet(const relationship &rel, xml::serializer &serializer) { - /*auto chartsheet_node = */root.append_child("chartsheet"); + serializer.start_element("chartsheet"); } -void xlsx_producer::write_connections(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_connections(const relationship &rel, xml::serializer &serializer) { - /*auto connections_node = */root.append_child("connections"); + serializer.start_element("connections"); } -void xlsx_producer::write_custom_xml_mappings(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_custom_xml_mappings(const relationship &rel, xml::serializer &serializer) { - /*auto map_info_node = */root.append_child("MapInfo"); + serializer.start_element("MapInfo"); } -void xlsx_producer::write_dialogsheet(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_dialogsheet(const relationship &rel, xml::serializer &serializer) { - /*auto dialogsheet_node = */root.append_child("dialogsheet"); + serializer.start_element("dialogsheet"); } -void xlsx_producer::write_external_workbook_references(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_external_workbook_references(const relationship &rel, xml::serializer &serializer) { - /*auto external_link_node = */root.append_child("externalLink"); + serializer.start_element("externalLink"); } -void xlsx_producer::write_metadata(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_metadata(const relationship &rel, xml::serializer &serializer) { - /*auto metadata_node = */root.append_child("metadata"); + serializer.start_element("metadata"); } -void xlsx_producer::write_pivot_table(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_pivot_table(const relationship &rel, xml::serializer &serializer) { - /*auto pivot_table_definition_node = */root.append_child("pivotTableDefinition"); + serializer.start_element("pivotTableDefinition"); } -void xlsx_producer::write_shared_string_table(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_shared_string_table(const relationship &rel, xml::serializer &serializer) { - auto sst_node = root.append_child("sst"); - + serializer.start_element("sst"); +/* sst_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); std::size_t string_count = 0; @@ -830,27 +840,28 @@ void xlsx_producer::write_shared_string_table(const relationship &rel, pugi::xml } } } + */ } -void xlsx_producer::write_shared_workbook_revision_headers(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_shared_workbook_revision_headers(const relationship &rel, xml::serializer &serializer) { - /*auto headers_node = */root.append_child("headers"); + serializer.start_element("headers"); } -void xlsx_producer::write_shared_workbook(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_shared_workbook(const relationship &rel, xml::serializer &serializer) { - /*auto revisions_node = */root.append_child("revisions"); + serializer.start_element("revisions"); } -void xlsx_producer::write_shared_workbook_user_data(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_shared_workbook_user_data(const relationship &rel, xml::serializer &serializer) { - /*auto users_node = */root.append_child("users"); + serializer.start_element("users"); } -void xlsx_producer::write_styles(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_styles(const relationship &rel, xml::serializer &serializer) { - auto stylesheet_node = root.append_child("styleSheet"); - + serializer.start_element("styleSheet"); +/* // Namespaces stylesheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); @@ -1295,11 +1306,13 @@ void xlsx_producer::write_styles(const relationship &rel, pugi::xml_node root) 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) +void xlsx_producer::write_theme(const relationship &rel, xml::serializer &serializer) { - auto theme_node = root.append_child("a:theme"); + serializer.start_element("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"); @@ -1602,14 +1615,15 @@ void xlsx_producer::write_theme(const relationship &rel, pugi::xml_node root) 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) +void xlsx_producer::write_volatile_dependencies(const relationship &rel, xml::serializer &serializer) { - /*auto vol_types_node = */root.append_child("volTypes"); + serializer.start_element("volTypes"); } -void xlsx_producer::write_worksheet(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_worksheet(const relationship &rel, xml::serializer &serializer) { auto title = std::find_if(source_.d_->sheet_title_rel_id_map_.begin(), source_.d_->sheet_title_rel_id_map_.end(), @@ -1620,17 +1634,19 @@ void xlsx_producer::write_worksheet(const relationship &rel, pugi::xml_node root 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"); + const auto xmlns = std::string("http://schemas.openxmlformats.org/spreadsheetml/2006/main"); + + serializer.start_element(xmlns, "worksheet"); + serializer.namespace_decl(xmlns, ""); + serializer.namespace_decl("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "r"); 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"); + serializer.namespace_decl("http://schemas.openxmlformats.org/markup-compatibility/2006", "mc"); + serializer.attribute("mc:Ignorable", "x14ac"); + serializer.namespace_decl("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac", "x14ac"); } - +/* if (ws.has_page_setup()) { auto sheet_pr_node = worksheet_node.append_child("sheetPr"); @@ -1766,12 +1782,13 @@ void xlsx_producer::write_worksheet(const relationship &rel, pugi::xml_node root 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"); + serializer.start_element(xmlns, "sheetData"); const auto &shared_strings = ws.get_workbook().get_shared_strings(); - +/* for (auto row : ws.rows()) { auto min = static_cast(row.num_cells()); @@ -1916,7 +1933,9 @@ void xlsx_producer::write_worksheet(const relationship &rel, pugi::xml_node root } } } - + */ + serializer.end_element(); +/* if (ws.has_auto_filter()) { auto auto_filter_node = worksheet_node.append_child("autoFilter"); @@ -2034,31 +2053,34 @@ void xlsx_producer::write_worksheet(const relationship &rel, pugi::xml_node root "Text &P of &N"; odd_footer_node.text().set(footer_text.c_str()); } + */ + + serializer.end_element(); } // Sheet Relationship Target Parts -void xlsx_producer::write_comments(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_comments(const relationship &rel, xml::serializer &serializer) { - /*auto comments_node = */root.append_child("comments"); + serializer.start_element("comments"); } -void xlsx_producer::write_drawings(const relationship &rel, pugi::xml_node root) +void xlsx_producer::write_drawings(const relationship &rel, xml::serializer &serializer) { - /*auto ws_dr_node = */root.append_child("wsDr"); + serializer.start_element("wsDr"); } // Other Parts -void xlsx_producer::write_custom_property() +void xlsx_producer::write_custom_property(xml::serializer &serializer) { } -void xlsx_producer::write_unknown_parts() +void xlsx_producer::write_unknown_parts(xml::serializer &serializer) { } -void xlsx_producer::write_unknown_relationships() +void xlsx_producer::write_unknown_relationships(xml::serializer &serializer) { } diff --git a/source/detail/xlsx_producer.hpp b/source/detail/xlsx_producer.hpp index 709daab3..3f2d82af 100644 --- a/source/detail/xlsx_producer.hpp +++ b/source/detail/xlsx_producer.hpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -63,45 +63,45 @@ private: // Package Parts void write_manifest(); - void write_core_properties(const relationship &rel, pugi::xml_node root); - void write_extended_properties(const relationship &rel, pugi::xml_node root); - void write_custom_properties(const relationship &rel, pugi::xml_node root); + void write_core_properties(const relationship &rel, xml::serializer &serializer); + void write_extended_properties(const relationship &rel, xml::serializer &serializer); + void write_custom_properties(const relationship &rel, xml::serializer &serializer); void write_thumbnail(const relationship &rel); // SpreadsheetML-Specific Package Parts - void write_workbook(const relationship &rel, pugi::xml_node root); + void write_workbook(const relationship &rel, xml::serializer &serializer); // Workbook Relationship Target Parts - void write_calculation_chain(const relationship &rel, pugi::xml_node root); - void write_connections(const relationship &rel, pugi::xml_node root); - void write_custom_xml_mappings(const relationship &rel, pugi::xml_node root); - void write_external_workbook_references(const relationship &rel, pugi::xml_node root); - void write_metadata(const relationship &rel, pugi::xml_node root); - void write_pivot_table(const relationship &rel, pugi::xml_node root); - void write_shared_string_table(const relationship &rel, pugi::xml_node root); - void write_shared_workbook_revision_headers(const relationship &rel, pugi::xml_node root); - void write_shared_workbook(const relationship &rel, pugi::xml_node root); - void write_shared_workbook_user_data(const relationship &rel, pugi::xml_node root); - void write_styles(const relationship &rel, pugi::xml_node root); - void write_theme(const relationship &rel, pugi::xml_node root); - void write_volatile_dependencies(const relationship &rel, pugi::xml_node root); + void write_calculation_chain(const relationship &rel, xml::serializer &serializer); + void write_connections(const relationship &rel, xml::serializer &serializer); + void write_custom_xml_mappings(const relationship &rel, xml::serializer &serializer); + void write_external_workbook_references(const relationship &rel, xml::serializer &serializer); + void write_metadata(const relationship &rel, xml::serializer &serializer); + void write_pivot_table(const relationship &rel, xml::serializer &serializer); + void write_shared_string_table(const relationship &rel, xml::serializer &serializer); + void write_shared_workbook_revision_headers(const relationship &rel, xml::serializer &serializer); + void write_shared_workbook(const relationship &rel, xml::serializer &serializer); + void write_shared_workbook_user_data(const relationship &rel, xml::serializer &serializer); + void write_styles(const relationship &rel, xml::serializer &serializer); + void write_theme(const relationship &rel, xml::serializer &serializer); + void write_volatile_dependencies(const relationship &rel, xml::serializer &serializer); - void write_chartsheet(const relationship &rel, pugi::xml_node root); - void write_dialogsheet(const relationship &rel, pugi::xml_node root); - void write_worksheet(const relationship &rel, pugi::xml_node root); + void write_chartsheet(const relationship &rel, xml::serializer &serializer); + void write_dialogsheet(const relationship &rel, xml::serializer &serializer); + void write_worksheet(const relationship &rel, xml::serializer &serializer); // Sheet Relationship Target Parts - void write_comments(const relationship &rel, pugi::xml_node root); - void write_drawings(const relationship &rel, pugi::xml_node root); + void write_comments(const relationship &rel, xml::serializer &serializer); + void write_drawings(const relationship &rel, xml::serializer &serializer); // Other Parts - void write_custom_property(); - void write_unknown_parts(); - void write_unknown_relationships(); + void write_custom_property(xml::serializer &serializer); + void write_unknown_parts(xml::serializer &serializer); + void write_unknown_relationships(xml::serializer &serializer); // Helpers diff --git a/source/detail/xml/details/config.h b/source/detail/xml/details/config.h new file mode 100644 index 00000000..90beb67e --- /dev/null +++ b/source/detail/xml/details/config.h @@ -0,0 +1,15 @@ +/* file : xml/details/config.h.in + * copyright : Copyright (c) 2013-2014 Code Synthesis Tools CC + * license : MIT; see accompanying LICENSE file + */ + +/* This file is automatically processed by configure. */ + +#ifndef XML_DETAILS_CONFIG_H +#define XML_DETAILS_CONFIG_H + +#undef LIBSTUDXML_STATIC_LIB +#undef LIBSTUDXML_EXTERNAL_EXPAT +#undef LIBSTUDXML_BYTEORDER + +#endif /* XML_DETAILS_CONFIG_H */ diff --git a/source/styles/tests/test_number_format.hpp b/source/styles/tests/test_number_format.hpp index 0532afc4..c5263edb 100644 --- a/source/styles/tests/test_number_format.hpp +++ b/source/styles/tests/test_number_format.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include diff --git a/source/workbook/tests/test_produce_xlsx.hpp b/source/workbook/tests/test_produce_xlsx.hpp index ecf85bd9..e7ed9be3 100644 --- a/source/workbook/tests/test_produce_xlsx.hpp +++ b/source/workbook/tests/test_produce_xlsx.hpp @@ -16,6 +16,8 @@ public: { std::vector buffer; wb.save(buffer); + + wb.save("a.xlsx"); xlnt::zip_file wb_archive(buffer); xlnt::zip_file file_archive(file); diff --git a/third-party/pugixml b/third-party/pugixml new file mode 160000 index 00000000..dfe9360c --- /dev/null +++ b/third-party/pugixml @@ -0,0 +1 @@ +Subproject commit dfe9360cdf038c0ecf53d45bfc75cf8fd34604b8