almost done. phew...

This commit is contained in:
Thomas Fussell 2015-10-30 18:54:04 -04:00
parent 84e9dd099e
commit 9dce7b8f0c
42 changed files with 1211 additions and 641 deletions

View File

@ -30,21 +30,20 @@
namespace xlnt {
class xml_node;
class xml_document;
class comment_serializer
{
comment_serializer(worksheet sheet);
void read_comments(const xml_node &xml);
void read_comments_vml(const xml_node &xml);
void read_comments(const xml_document &xml);
void read_comments_vml(const xml_document &xml);
xml_node write_comments();
xml_node write_comments_vml();
xml_document write_comments() const;
xml_document write_comments_vml() const;
private:
worksheet sheet_;
std::vector<comment> comments_;
};
} // namespace xlnt

View File

@ -34,41 +34,148 @@ namespace xlnt {
class workbook;
/// <summary>
/// Handles reading and writing workbooks from an actual XLSX archive
/// using other serializers.
/// </summary>
class excel_serializer
{
public:
/// <summary>
///
/// </summary>
static const std::string central_directory_signature();
/// <summary>
///
/// </summary>
static std::string repair_central_directory(const std::string &original);
/// <summary>
/// Construct an excel_serializer which operates on wb.
/// </summary>
excel_serializer(workbook &wb);
/// <summary>
/// Create a ZIP file in memory, load archive from filename, then populate workbook
/// with data from archive.
/// </summary>
bool load_workbook(const std::string &filename, bool guess_types = false, bool data_only = false);
bool load_stream_workbook(std::istream &stream, bool guess_types = false, bool data_only = false);
bool load_virtual_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types = false, bool data_only = false);
/// <summary>
/// Create a ZIP file in memory, load archive from stream, then populate workbook
/// with data from archive.
/// </summary>
bool load_stream_workbook(std::istream &stream, bool guess_types = false, bool data_only = false);
/// <summary>
/// Create a ZIP file in memory, load archive from bytes, then populate workbook
/// with data from archive.
/// </summary>
bool load_virtual_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types = false, bool data_only = false);
/// <summary>
/// Create a ZIP file in memory, save workbook to this archive, then save archive
/// to filename.
/// </summary>
bool save_workbook(const std::string &filename, bool as_template = false);
/// <summary>
/// Create a ZIP file in memory, save workbook to this archive, then assign ZIP file
/// binary data to bytes.
/// </summary>
bool save_virtual_workbook(std::vector<std::uint8_t> &bytes, bool as_template = false);
/// <summary>
/// Create a ZIP file in memory, save workbook to this archive, then copy ZIP file
/// binary data to stream.
/// </summary>
bool save_stream_workbook(std::ostream &stream, bool as_template = false);
private:
/// <summary>
/// Reads all files in archive and populates workbook with associated data
/// using other appropriate serializers such as workbook_serializer.
/// </summary>
void read_data(bool guess_types, bool data_only);
/// <summary>
/// Read xl/sharedStrings.xml from internal archive and add shared strings to workbook.
/// </summary>
void read_shared_strings();
/// <summary>
///
/// </summary>
void read_images();
/// <summary>
///
/// </summary>
void read_charts();
/// <summary>
///
/// </summary>
void read_chartsheets();
/// <summary>
///
/// </summary>
void read_worksheets();
/// <summary>
///
/// </summary>
void read_external_links();
/// <summary>
/// Write all files needed to create a valid XLSX file which represents all
/// data contained in workbook.
/// </summary>
void write_data(bool as_template);
/// <summary>
/// Write xl/sharedStrings.xml to internal archive based on shared strings in workbook.
/// </summary>
void write_shared_strings();
/// <summary>
///
/// </summary>
void write_images();
/// <summary>
///
/// </summary>
void write_charts();
/// <summary>
///
/// </summary>
void write_chartsheets();
/// <summary>
///
/// </summary>
void write_worksheets();
/// <summary>
///
/// </summary>
void write_external_links();
workbook &wb_;
std::vector<std::string> shared_strings_;
/// <summary>
/// A reference to the workbook which is the object of read/write operations.
/// </summary>
workbook &workbook_;
/// <summary>
/// The internal archive which holds files representing workbook_ during
/// read/write operations.
/// </summary>
zip_file archive_;
};

View File

@ -5,17 +5,17 @@
namespace xlnt {
class manifest;
class workbook;
class xml_document;
class zip_file;
class manifest_serializer
{
public:
manifest_serializer(manifest &m);
bool read_manifest(const xml_document &xml);
bool write_manifest(xml_document &xml);
void read_manifest(const xml_document &xml);
xml_document write_manifest() const;
std::string determine_document_type() const;
private:
manifest &manifest_;

View File

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

View File

@ -33,8 +33,8 @@ class xml_document;
class shared_strings_serializer
{
public:
bool read_strings(const xml_document &xml, std::vector<std::string> &strings);
bool write_strings(const std::vector<std::string> &strings, xml_document &xml);
static bool read_shared_strings(const xml_document &xml, std::vector<std::string> &strings);
static xml_document write_shared_strings(const std::vector<std::string> &strings);
};
} // namespace xlnt

View File

@ -56,6 +56,10 @@ public:
/// with styles from an existing styles.xml.
style_serializer(workbook &wb);
//
// Primary methods
//
/// <summary>
/// Load all styles from xml_document into workbook given in constructor.
/// </summary>
@ -65,28 +69,118 @@ public:
/// Populate parameter xml with an XML tree representing the styles contained in the workbook
/// given in the constructor.
/// </summary>
bool write_stylesheet(xml_document &xml) const;
xml_document write_stylesheet() const;
private:
/// <summary>
/// Read a single style from the given node. In styles.xml, this is an "xf" element.
/// A style has an optional border id, fill id, font id, and number format id where
/// each id is an index in the corresponding list of borders, etc. A style also has
/// optional alignment and protection children. A style also defines whether each of
/// these is "applied". For example, a style with a defined font id, font=# but with
/// "applyFont=0" will not use the font in formatting.
/// </summary>
style read_style(const xml_node &style_node) const;
//TODO: These need to be public for unit tests. Could also make test class a friend?
//private:
//
// Static element readers (i.e. readers that don't use internal state)
//
/// <summary>
/// Read and return an alignment from alignment_node.
/// </summary>
alignment read_alignment(const xml_node &alignment_node) const;
static alignment read_alignment(const xml_node &alignment_node);
/// <summary>
/// Read and return a border side from side_node.
/// </summary>
side read_side(const xml_node &side_node) const;
static side read_side(const xml_node &side_node);
/// <summary>
/// Read and return a border from border_node.
/// </summary>
static border read_border(const xml_node &border_node);
/// <summary>
/// Read and return a fill from fill_node.
/// </summary>
static fill read_fill(const xml_node &fill_node);
/// <summary>
/// Read and return a font from font_node.
/// </summary>
static font read_font(const xml_node &font_node);
/// <summary>
/// Read and return a number format from number_format_node.
/// </summary>
static number_format read_number_format(const xml_node &number_format_node);
/// <summary>
/// Read and return a protection from protection_node.
/// </summary>
static protection read_protection(const xml_node &protection_node);
/// <summary>
/// Read and return all indexed colors from indexed_colors_node.
/// </summary>
static std::vector<color> read_indexed_colors(const xml_node &indexed_colors_node);
/// <summary>
/// Read and return a color from color_node.
/// </summary>
static color read_color(const xml_node &color_node);
/// <summary>
/// Read and return a conditional format, dxf, from conditional_format_node.
/// </summary>
static conditional_format read_conditional_format(const xml_node &conditional_formats_node);
/// <summary>
/// Read and return a pair containing a name and corresponding style from named_style_node.
/// </summary>
static std::pair<std::string, style> read_named_style(const xml_node &named_style_node);
//
// Static element writers (i.e. writers that don't use internal state)
//
/// <summary>
/// Build and return an xml tree representing alignment_.
/// </summary>
static xml_node write_alignment(const alignment &alignment_);
/// <summary>
/// Build and return an xml tree representing border_.
/// </summary>
static xml_node write_border(const border &border_);
/// <summary>
/// Build and return an xml tree representing conditional_format_.
/// </summary>
static xml_node write_conditional_format(const conditional_format &conditional_format_);
/// <summary>
/// Build and return an xml tree representing fill_.
/// </summary>
static xml_node write_fill(const fill &fill_);
/// <summary>
/// Build and return an xml tree representing font_.
/// </summary>
static xml_node write_font(const font &font_);
/// <summary>
/// Build and return two xml trees, first=cell style and second=named style, representing named_style_.
/// </summary>
static std::pair<xml_node, xml_node> write_named_style(const named_style &named_style_);
/// <summary>
/// Build an xml tree representing all named styles in workbook into named_styles_node and cell_styles_node.
/// Returns true on success.
/// </summary>
static std::pair<xml_node, xml_node> write_named_styles();
/// <summary>
/// Build and return an xml tree representing number_format_.
/// </summary>
static xml_node write_number_format(const number_format &number_format_);
//
// Non-static element readers (i.e. readers that modify internal state)
//
/// <summary>
/// Read all borders from borders_node and add them to workbook.
@ -94,70 +188,24 @@ private:
/// </summary>
bool read_borders(const xml_node &borders_node);
/// <summary>
/// Read and return a border from border_node.
/// </summary>
border read_border(const xml_node &border_node) const;
/// <summary>
/// Read all fills from fills_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_fills(const xml_node &fills_node);
/// <summary>
/// Read and return a fill from fill_node.
/// </summary>
fill read_fill(const xml_node &fill_node) const;
/// <summary>
/// Read all fonts from fonts_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_fonts(const xml_node &fonts_node);
/// <summary>
/// Read and return a font from font_node.
/// </summary>
font read_font(const xml_node &font_node) const;
/// <summary>
/// Read all borders from number_formats_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_number_formats(const xml_node &number_formats_node);
/// <summary>
/// Read and return a number format from number_format_node.
/// </summary>
number_format read_number_format(const xml_node &number_format_node) const;
/// <summary>
/// Read and return a protection from protection_node.
/// </summary>
protection read_protection(const xml_node &protection_node) const;
/// <summary>
/// Read all colors from colors_node and add them to workbook.
/// Return true on success.
/// </summary>
bool read_colors(const xml_node &colors_node);
/// <summary>
/// Read and return all indexed colors from indexed_colors_node.
/// </summary>
std::vector<color> read_indexed_colors(const xml_node &indexed_colors_node) const;
/// <summary>
/// Read and return a color from color_node.
/// </summary>
color read_color(const xml_node &color_node) const;
/// <summary>
/// Read and return a conditional format, dxf, from conditional_format_node.
/// </summary>
conditional_format read_conditional_format(const xml_node &conditional_formats_node) const;
/// <summary>
/// Read all named styles from named_style_node and cell_styles_node and add them to workbook.
/// Return true on success.
@ -165,19 +213,24 @@ private:
bool read_named_styles(const xml_node &named_styles_node);
/// <summary>
/// Read and return a pair containing a name and corresponding style from named_style_node.
/// Read all borders from number_formats_node and add them to workbook.
/// Return true on success.
/// </summary>
std::pair<std::string, style> read_named_style(const xml_node &named_style_node) const;
bool read_number_formats(const xml_node &number_formats_node);
/// <summary>
/// Build and return an xml tree representing alignment_.
/// Read a single style from the given node. In styles.xml, this is an "xf" element.
/// A style has an optional border id, fill id, font id, and number format id where
/// each id is an index in the corresponding list of borders, etc. A style also has
/// optional alignment and protection children. A style also defines whether each of
/// these is "applied". For example, a style with a defined font id, font=# but with
/// "applyFont=0" will not use the font in formatting.
/// </summary>
xml_node write_alignment(const alignment &alignment_) const;
style read_style(const xml_node &style_node);
/// <summary>
/// Build and return an xml tree representing border_.
/// </summary>
xml_node write_border(const border &border_) const;
//
// Non-static element writers (i.e. writers that modify internal workbook)
//
/// <summary>
/// Build an xml tree representing all borders in workbook into borders_node.
@ -186,9 +239,10 @@ private:
bool write_borders(xml_node &borders_node) const;
/// <summary>
/// Build and return an xml tree representing fill_.
/// Build an xml tree representing all conditional formats in workbook into conditional_formats_node.
/// Returns true on success.
/// </summary>
xml_node write_fill(const fill &fill_) const;
bool write_conditional_formats(xml_node &conditional_formats_node) const;
/// <summary>
/// Build an xml tree representing all fills in workbook into fills_node.
@ -196,38 +250,17 @@ private:
/// </summary>
bool write_fills(xml_node &fills_node) const;
/// <summary>
/// Build and return an xml tree representing font_.
/// </summary>
xml_node write_font(const font &font_) const;
/// <summary>
/// Build an xml tree representing all fonts in workbook into fonts_node.
/// Returns true on success.
/// </summary>
bool write_fonts(xml_node &fonts_node) const;
/// <summary>
/// Build and return an xml tree representing number_format_.
/// </summary>
xml_node write_number_format(const number_format &number_format_) const;
/// <summary>
/// Build an xml tree representing all number formats in workbook into number_formats_node.
/// Returns true on success.
/// </summary>
bool write_number_formats(xml_node &fonts_node) const;
/// <summary>
/// Build and return two xml trees, first=cell style and second=named style, representing named_style_.
/// </summary>
std::pair<xml_node, xml_node> write_named_style(const named_style &named_style_) const;
/// <summary>
/// Build an xml tree representing all named styles in workbook into named_styles_node and cell_styles_node.
/// Returns true on success.
/// </summary>
void write_named_styles(xml_node &named_styles_node, xml_node &cell_styles_node) const;
bool write_number_formats(xml_node fonts_node) const;
/// <summary>
/// Build an xml tree representing the given style into style_node.
@ -235,21 +268,11 @@ private:
/// </summary>
bool write_style(const style &style_, xml_node &style_node) const;
/// <summary>
/// Build and return an xml tree representing conditional_format_.
/// </summary>
xml_node write_conditional_format(const conditional_format &conditional_format_) const;
/// <summary>
/// Build an xml tree representing all conditional formats in workbook into conditional_formats_node.
/// Returns true on success.
/// </summary>
bool write_conditional_formats(xml_node &conditional_formats_node) const;
private:
/// <summary>
/// Set in the constructor, this workbook is used as the source or target for all writing or reading, respectively.
/// </summary>
workbook &wb_;
workbook &workbook_;
};
} // namespace xlnt

View File

@ -33,8 +33,10 @@ class xml_document;
class theme_serializer
{
public:
//theme read_theme(const xml_document &xml);
xml_document write_theme(const theme &theme_);
bool read_theme(const xml_document &xml, theme &t);
xml_document write_theme(const theme &t) const;
private:
};
} // namespace xlnt

View File

@ -40,8 +40,7 @@ class xml_node;
class workbook_serializer
{
public:
//TODO: does this go here?
static std::string determine_document_type(const manifest &manifest_);
using string_pair = std::pair<std::string, std::string>;
workbook_serializer(workbook &wb);
@ -53,15 +52,13 @@ public:
xml_document write_properties_app() const;
xml_document write_properties_core() const;
using string_pair = std::pair<std::string, std::string>;
std::vector<string_pair> read_sheets();
std::vector<string_pair> detect_worksheets();
bool write_named_ranges(xml_node &named_ranges_node);
xml_node write_named_ranges() const;
private:
workbook &wb_;
workbook &workbook_;
};
} // namespace xlnt

View File

@ -34,15 +34,14 @@ class relationship;
class workbook;
class worksheet;
class xml_document;
class xml_node;
class worksheet_serializer
{
public:
worksheet_serializer(worksheet sheet);
bool read_worksheet(const xml_document &xml, const std::vector<std::string> &shared_strings, const relationship &rel);
bool write_worksheet(const std::vector<std::string> &string_table, xml_document &xml);
bool read_worksheet(const xml_document &xml);
xml_document write_worksheet() const;
private:
worksheet sheet_;

View File

@ -1,25 +1,48 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <xlnt/s11n/xml_node.hpp>
namespace xlnt {
namespace detail {
struct xml_document_impl;
} // namespace detail
class xml_node;
class xml_serializer;
class xml_document
{
public:
using string_pair = std::pair<std::string, std::string>;
xml_document();
xml_document(const xml_document &other);
xml_document(xml_document &&other);
~xml_document();
xml_document &operator=(const xml_document &other);
xml_document &operator=(xml_document &&other);
void set_encoding(const std::string &encoding);
void add_namespace(const std::string &id, const std::string &uri);
xml_node &root();
const xml_node &root() const;
xml_node add_child(const xml_node &child);
xml_node add_child(const std::string &child_name);
xml_node get_root();
const xml_node get_root() const;
xml_node get_child(const std::string &child_name);
const xml_node get_child(const std::string &child_name) const;
std::string to_string() const;
xml_document &from_string(const std::string &xml_string);
private:
xml_node root_;
std::string encoding_;
std::vector<string_pair> namespaces_;
friend class xml_serializer;
std::unique_ptr<detail::xml_document_impl> d_;
};
} // namespace xlnt

View File

@ -1,17 +1,26 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace xlnt {
using string_pair = std::pair<std::string, std::string>;
namespace detail {
struct xml_node_impl;
} // namespace detail
class xml_document;
class xml_node
{
public:
using string_pair = std::pair<std::string, std::string>;
xml_node();
explicit xml_node(const std::string &name);
xml_node(const xml_node &other);
~xml_node();
xml_node &operator=(const xml_node &other);
std::string get_name() const;
void set_name(const std::string &name);
@ -20,24 +29,25 @@ public:
std::string get_text() const;
void set_text(const std::string &text);
const std::vector<xml_node> &get_children() const;
const std::vector<xml_node> get_children() const;
bool has_child(const std::string &child_name) const;
xml_node &get_child(const std::string &child_name);
const xml_node &get_child(const std::string &child_name) const;
xml_node &add_child(const xml_node &child);
xml_node &add_child(const std::string &child_name);
xml_node get_child(const std::string &child_name);
const xml_node get_child(const std::string &child_name) const;
xml_node add_child(const xml_node &child);
xml_node add_child(const std::string &child_name);
const std::vector<string_pair> &get_attributes() const;
const std::vector<string_pair> get_attributes() const;
bool has_attribute(const std::string &attribute_name) const;
std::string get_attribute(const std::string &attribute_name) const;
void add_attribute(const std::string &name, const std::string &value);
std::string to_string() const;
private:
std::string name_;
bool has_text_ = false;
std::string text_;
std::vector<string_pair> attributes_;
std::vector<xml_node> children_;
friend class xml_document;
friend class xml_serializer;
xml_node(const detail::xml_node_impl &d);
std::unique_ptr<detail::xml_node_impl> d_;
};
} // namespace xlnt

View File

@ -3,14 +3,17 @@
#include <string>
namespace xlnt {
class xml_document;
class xml_node;
class xml_serializer
{
public:
static std::string serialize(const xml_document &xml);
static xml_document deserialize(const std::string &xml_string);
static std::string serialize_node(const xml_node &xml);
};
} // namespace xlnt

View File

@ -118,7 +118,7 @@ public:
{
if(type_ != type::rgb)
{
throw std::runtime_error("not theme color");
throw std::runtime_error("not rgb color");
}
return rgb_string_;

View File

@ -248,7 +248,11 @@ public:
const manifest &get_manifest() const;
const std::vector<relationship> &get_root_relationships() const;
void add_shared_string(const std::string &shared);
std::vector<std::string> &get_shared_strings();
const std::vector<std::string> &get_shared_strings() const;
private:
friend class worksheet;
std::shared_ptr<detail::workbook_impl> d_;

View File

@ -361,7 +361,7 @@ section parse_section(const std::string &section_string)
static const std::vector<std::string> bracket_times = { "h", "hh", "m", "mm", "s", "ss" };
for(int i = 0; i < section_string.size(); i++)
for(std::size_t i = 0; i < section_string.size(); i++)
{
if(!in_quotes && section_string[i] == '"')
{

View File

@ -15,7 +15,8 @@ struct workbook_impl
worksheets_(other.worksheets_),
relationships_(other.relationships_),
root_relationships_(other.root_relationships_),
drawings_(other.drawings_),
drawings_(other.drawings_),
shared_strings_(other.shared_strings_),
properties_(other.properties_),
guess_types_(other.guess_types_),
data_only_(other.data_only_),
@ -40,6 +41,8 @@ struct workbook_impl
std::copy(other.root_relationships_.begin(), other.root_relationships_.end(), std::back_inserter(root_relationships_));
drawings_.clear();
std::copy(other.drawings_.begin(), other.drawings_.end(), back_inserter(drawings_));
shared_strings_.clear();
std::copy(other.shared_strings_.begin(), other.shared_strings_.end(), std::back_inserter(shared_strings_));
properties_ = other.properties_;
guess_types_ = other.guess_types_;
data_only_ = other.data_only_;
@ -59,6 +62,7 @@ struct workbook_impl
std::vector<relationship> relationships_;
std::vector<relationship> root_relationships_;
std::vector<drawing> drawings_;
std::vector<std::string> shared_strings_;
document_properties properties_;

View File

@ -0,0 +1,17 @@
#pragma once
#include <string>
#include <detail/include_pugixml.hpp>
namespace xlnt {
namespace detail {
struct xml_document_impl
{
std::string encoding;
pugi::xml_document doc;
};
} // namespace detail
} // namespace xlnt

View File

@ -0,0 +1,16 @@
#pragma once
#include <detail/include_pugixml.hpp>
namespace xlnt {
namespace detail {
struct xml_node_impl
{
xml_node_impl() {}
explicit xml_node_impl(pugi::xml_node n) : node(n) {}
pugi::xml_node node;
};
} // namespace detail
} // namespace xlnt

View File

@ -8,6 +8,7 @@
#include <xlnt/s11n/workbook_serializer.hpp>
#include <xlnt/s11n/worksheet_serializer.hpp>
#include <xlnt/s11n/xml_document.hpp>
#include <xlnt/s11n/xml_node.hpp>
#include <xlnt/s11n/xml_serializer.hpp>
#include <xlnt/workbook/document_properties.hpp>
#include <xlnt/workbook/manifest.hpp>
@ -43,44 +44,49 @@ bool load_workbook(xlnt::zip_file &archive, bool guess_types, bool data_only, xl
xlnt::manifest_serializer ms(wb.get_manifest());
ms.read_manifest(xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcContentTypes)));
if(xlnt::workbook_serializer::determine_document_type(wb.get_manifest()) != "excel")
if(ms.determine_document_type() != "excel")
{
throw xlnt::invalid_file_exception("");
}
wb.clear();
std::vector<xlnt::relationship> workbook_relationships;
xlnt::relationship_serializer::read_relationships(xlnt::xml_serializer::deserialize(archive.read("xl/_rels/workbook.xml.rels")), "", workbook_relationships);
auto workbook_relationships = xlnt::relationship_serializer::read_relationships(archive, xlnt::constants::ArcWorkbook);
for(auto relationship : workbook_relationships)
for(const auto &relationship : workbook_relationships)
{
wb.create_relationship(relationship.get_id(), relationship.get_target_uri(), relationship.get_type());
}
auto xml = xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcWorkbook));
auto &root_node = xml.root();
auto root_node = xml.get_child("workbook");
auto &workbook_pr_node = root_node.get_child("workbookPr");
auto workbook_pr_node = root_node.get_child("workbookPr");
wb.get_properties().excel_base_date = (workbook_pr_node.has_attribute("date1904") && workbook_pr_node.get_attribute("date1904") != "0") ? xlnt::calendar::mac_1904 : xlnt::calendar::windows_1900;
xlnt::shared_strings_serializer shared_strings_serializer_;
std::vector<std::string> shared_strings;
shared_strings_serializer_.read_strings(xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcSharedString)), shared_strings);
shared_strings_serializer_.read_shared_strings(xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcSharedString)), shared_strings);
for(auto shared_string : shared_strings)
{
wb.add_shared_string(shared_string);
}
xlnt::style_serializer style_reader_(wb);
style_reader_.read_stylesheet(xlnt::xml_serializer::deserialize(archive.read(xlnt::constants::ArcStyles)));
auto &sheets_node = root_node.get_child("sheets");
auto sheets_node = root_node.get_child("sheets");
for(auto sheet_node : sheets_node.get_children())
{
auto rel = wb.get_relationship(sheet_node.get_attribute("r:id"));
auto ws = wb.create_sheet(sheet_node.get_attribute("name"), rel);
auto ws_filename = "xl/" + rel.get_target_uri();
xlnt::worksheet_serializer worksheet_serializer(ws);
worksheet_serializer.read_worksheet(xlnt::xml_serializer::deserialize(archive.read(rel.get_target_uri())), shared_strings, rel);
worksheet_serializer.read_worksheet(xlnt::xml_serializer::deserialize(archive.read(ws_filename)));
}
return true;
@ -126,52 +132,45 @@ bool excel_serializer::load_workbook(const std::string &filename, bool guess_typ
throw invalid_file_exception(filename);
}
return ::load_workbook(archive_, guess_types, data_only, wb_);
return ::load_workbook(archive_, guess_types, data_only, workbook_);
}
bool excel_serializer::load_virtual_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types, bool data_only)
{
archive_.load(bytes);
return ::load_workbook(archive_, guess_types, data_only, wb_);
return ::load_workbook(archive_, guess_types, data_only, workbook_);
}
excel_serializer::excel_serializer(workbook &wb) : wb_(wb)
excel_serializer::excel_serializer(workbook &wb) : workbook_(wb)
{
}
void excel_serializer::write_data(bool as_template)
void excel_serializer::write_data(bool /*as_template*/)
{
relationship_serializer relationship_serializer_;
xlnt::xml_document root_rels_xml;
relationship_serializer_.write_relationships(wb_.get_root_relationships(), "", root_rels_xml);
archive_.writestr(constants::ArcRootRels, xml_serializer::serialize(root_rels_xml));
xml_document workbook_rels_xml;
relationship_serializer_.write_relationships(wb_.get_relationships(), "", workbook_rels_xml);
archive_.writestr(constants::ArcWorkbookRels, xml_serializer::serialize(workbook_rels_xml));
relationship_serializer_.write_relationships(workbook_.get_root_relationships(), "", archive_);
relationship_serializer_.write_relationships(workbook_.get_relationships(), constants::ArcWorkbook, archive_);
xml_document properties_app_xml;
workbook_serializer workbook_serializer_(wb_);
workbook_serializer workbook_serializer_(workbook_);
archive_.writestr(constants::ArcApp, xml_serializer::serialize(workbook_serializer_.write_properties_app()));
archive_.writestr(constants::ArcCore, xml_serializer::serialize(workbook_serializer_.write_properties_core()));
theme_serializer theme_serializer_;
xml_document theme_xml = theme_serializer_.write_theme(wb_.get_loaded_theme());
archive_.writestr(constants::ArcTheme, xml_serializer::serialize(theme_xml));
archive_.writestr(constants::ArcTheme, theme_serializer_.write_theme(workbook_.get_loaded_theme()).to_string());
xlnt::shared_strings_serializer shared_strings_serializer_;
archive_.writestr(constants::ArcSharedString, xml_serializer::serialize(shared_strings_serializer_.write_shared_strings(workbook_.get_shared_strings())));
archive_.writestr(constants::ArcWorkbook, xml_serializer::serialize(workbook_serializer_.write_workbook()));
style_serializer style_serializer_(wb_);
xml_document style_xml;
style_serializer_.write_stylesheet(style_xml);
archive_.writestr(constants::ArcStyles, xml_serializer::serialize(style_xml));
style_serializer style_serializer_(workbook_);
archive_.writestr(constants::ArcStyles, style_serializer_.write_stylesheet().to_string());
manifest_serializer manifest_serializer_(wb_.get_manifest());
xml_document manifest_xml;
manifest_serializer_.write_manifest(manifest_xml);
archive_.writestr(constants::ArcContentTypes, xml_serializer::serialize(manifest_xml));
manifest_serializer manifest_serializer_(workbook_.get_manifest());
archive_.writestr(constants::ArcContentTypes, manifest_serializer_.write_manifest().to_string());
write_worksheets();
}
@ -180,17 +179,16 @@ void excel_serializer::write_worksheets()
{
std::size_t index = 0;
for(auto ws : wb_)
for(auto ws : workbook_)
{
for(auto relationship : wb_.get_relationships())
for(auto relationship : workbook_.get_relationships())
{
if(relationship.get_type() == relationship::type::worksheet &&
workbook::index_from_ws_filename(relationship.get_target_uri()) == index)
{
worksheet_serializer serializer_(ws);
xml_document xml;
serializer_.write_worksheet(shared_strings_, xml);
archive_.writestr(relationship.get_target_uri(), xml_serializer::serialize(xml));
std::string ws_filename = "xl/" + relationship.get_target_uri();
archive_.writestr(ws_filename, serializer_.write_worksheet().to_string());
break;
}
}

View File

@ -1,33 +1,81 @@
#include <xlnt/s11n/manifest_serializer.hpp>
#include <xlnt/s11n/xml_document.hpp>
#include <xlnt/s11n/xml_node.hpp>
#include <xlnt/workbook/manifest.hpp>
#include "detail/constants.hpp"
namespace xlnt {
bool manifest_serializer::write_manifest(xml_document &xml)
manifest_serializer::manifest_serializer(manifest &m) : manifest_(m)
{
}
void manifest_serializer::read_manifest(const xml_document &xml)
{
const auto root_node = xml.get_child("Types");
for(const auto child : root_node.get_children())
{
if(child.get_name() == "Default")
{
manifest_.add_default_type(child.get_attribute("Extension"), child.get_attribute("ContentType"));
}
else if(child.get_name() == "Override")
{
manifest_.add_override_type(child.get_attribute("PartName"), child.get_attribute("ContentType"));
}
}
}
xml_document manifest_serializer::write_manifest() const
{
xml_document xml;
auto root_node = xml.add_child("Types");
xml.add_namespace("", constants::Namespaces.at("content-types"));
auto root_node = xml.root();
root_node.set_name("Types");
for(const auto &default_type : manifest_.get_default_types())
for(const auto default_type : manifest_.get_default_types())
{
auto type_node = root_node.add_child("Default");
type_node.add_attribute("Extension", default_type.get_extension());
type_node.add_attribute("ContentType", default_type.get_extension());
type_node.add_attribute("ContentType", default_type.get_content_type());
}
for(const auto &override_type : manifest_.get_override_types())
for(const auto override_type : manifest_.get_override_types())
{
auto type_node = root_node.add_child("Override");
type_node.add_attribute("PartName", override_type.get_part_name());
type_node.add_attribute("ContentType", override_type.get_content_type());
}
return true;
return xml;
}
std::string manifest_serializer::determine_document_type() const
{
if(!manifest_.has_override_type(constants::ArcWorkbook))
{
return "unsupported";
}
std::string type = manifest_.get_override_type(constants::ArcWorkbook);
if(type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml")
{
return "excel";
}
else if(type == "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml")
{
return "powerpoint";
}
else if(type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")
{
return "word";
}
return "unsupported";
}
} // namespace xlnt

View File

@ -1,17 +1,42 @@
#include <xlnt/s11n/relationship_serializer.hpp>
#include <xlnt/common/relationship.hpp>
#include <xlnt/common/zip_file.hpp>
#include <xlnt/s11n/xml_document.hpp>
#include <xlnt/s11n/xml_node.hpp>
#include "detail/constants.hpp"
namespace {
std::string make_rels_name(const std::string &target)
{
const char sep = '/';
if(target.empty() || target.back() == sep)
{
return target + "_rels/.rels";
}
auto sep_pos = target.find_last_of(sep);
auto first_part = target.substr(0, sep_pos + 1);
auto last_part = target.substr(sep_pos + 1);
return first_part + "_rels/" + last_part + ".rels";
}
}
namespace xlnt {
bool relationship_serializer::read_relationships(const xml_document &xml, const std::string &dir, std::vector<relationship> &relationships)
std::vector<relationship> relationship_serializer::read_relationships(zip_file &archive, const std::string &target)
{
auto root_node = xml.root();
root_node.set_name("Relationships");
xml_document xml;
xml.from_string(archive.read(make_rels_name(target)));
auto root_node = xml.get_child("Relationships");
std::vector<relationship> relationships;
for(auto relationship_node : root_node.get_children())
{
@ -27,25 +52,21 @@ bool relationship_serializer::read_relationships(const xml_document &xml, const
relationships.push_back(xlnt::relationship(type, id, target));
}
return true;
return relationships;
}
bool relationship_serializer::write_relationships(const std::vector<relationship> &relationships, const std::string &dir, xml_document &xml)
bool relationship_serializer::write_relationships(const std::vector<relationship> &relationships, const std::string &target, zip_file &archive)
{
xml.add_namespace("", constants::Namespaces.at("relationships"));
xml_document xml;
auto root_node = xml.root();
root_node.set_name("Relationships");
auto root_node = xml.add_child("Relationships");
xml.add_namespace("", constants::Namespaces.at("relationships"));
for(const auto &relationship : relationships)
{
auto target = relationship.get_target_uri();
if (dir != "" && target.substr(0, dir.size()) == dir)
{
target = target.substr(dir.size());
}
auto relationship_node = root_node.add_child("Relationship");
relationship_node.add_attribute("Id", relationship.get_id());
@ -58,6 +79,8 @@ bool relationship_serializer::write_relationships(const std::vector<relationship
}
}
archive.writestr(make_rels_name(target), xml.to_string());
return true;
}

View File

@ -3,19 +3,48 @@
#include <xlnt/s11n/xml_node.hpp>
namespace xlnt {
xml_document shared_strings_serializer::write_shared_strings(const std::vector<std::string> &strings)
{
xml_document xml;
auto root_node = xml.add_child("sst");
xml.add_namespace("", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
root_node.add_attribute("uniqueCount", std::to_string(strings.size()));
for(const auto &string : strings)
{
root_node.add_child("si").add_child("t").set_text(string);
}
return xml;
}
bool shared_strings_serializer::read_strings(const xml_document &xml, std::vector<std::string> &strings)
bool shared_strings_serializer::read_shared_strings(const xml_document &xml, std::vector<std::string> &strings)
{
strings.clear();
auto root_node = xml.root();
root_node.set_name("sst");
auto root_node = xml.get_child("sst");
auto unique_count = std::stoull(root_node.get_attribute("uniqueCount"));
for(const auto &si_node : root_node.get_children())
{
strings.push_back(si_node.get_child("t").get_text());
if(si_node.get_name() != "si")
{
continue;
}
if(si_node.has_child("t"))
{
strings.push_back(si_node.get_child("t").get_text());
}
else if(si_node.has_child("r"))
{
strings.push_back(si_node.get_child("r").get_child("t").get_text());
}
}
if(unique_count != strings.size())

View File

@ -132,11 +132,11 @@ xlnt::border_style border_style_from_string(const std::string &border_style_stri
namespace xlnt {
style_serializer::style_serializer(workbook &wb) : wb_(wb)
style_serializer::style_serializer(workbook &wb) : workbook_(wb)
{
}
protection style_serializer::read_protection(const xml_node &protection_node) const
protection style_serializer::read_protection(const xml_node &protection_node)
{
protection prot;
@ -146,7 +146,7 @@ protection style_serializer::read_protection(const xml_node &protection_node) co
return prot;
}
alignment style_serializer::read_alignment(const xml_node &alignment_node) const
alignment style_serializer::read_alignment(const xml_node &alignment_node)
{
alignment align;
@ -219,7 +219,7 @@ alignment style_serializer::read_alignment(const xml_node &alignment_node) const
return align;
}
style style_serializer::read_style(const xml_node &style_node) const
style style_serializer::read_style(const xml_node &style_node)
{
style s;
@ -228,9 +228,9 @@ style style_serializer::read_style(const xml_node &style_node) const
bool builtin_format = true;
for(auto num_fmt : wb_.get_number_formats())
for(auto num_fmt : workbook_.get_number_formats())
{
if(num_fmt.get_id() == s.get_number_format_id())
if(static_cast<std::size_t>(num_fmt.get_id()) == s.get_number_format_id())
{
s.number_format_ = num_fmt;
builtin_format = false;
@ -245,15 +245,15 @@ style style_serializer::read_style(const xml_node &style_node) const
s.apply_font(is_true(style_node.get_attribute("applyFont")));
s.font_id_ = style_node.has_attribute("fontId") ? std::stoull(style_node.get_attribute("fontId")) : 0;
s.font_ = wb_.get_font(s.font_id_);
s.font_ = workbook_.get_font(s.font_id_);
s.apply_fill(is_true(style_node.get_attribute("applyFill")));
s.fill_id_ = style_node.has_attribute("fillId") ? std::stoull(style_node.get_attribute("fillId")) : 0;
s.fill_ = wb_.get_fill(s.fill_id_);
s.fill_ = workbook_.get_fill(s.fill_id_);
s.apply_border(is_true(style_node.get_attribute("applyBorder")));
s.border_id_ = style_node.has_attribute("borderId") ? std::stoull(style_node.get_attribute("borderId")) : 0;
s.border_ = wb_.get_border(s.border_id_);
s.border_ = workbook_.get_border(s.border_id_);
s.apply_protection(style_node.has_attribute("protection"));
@ -276,7 +276,7 @@ style style_serializer::read_style(const xml_node &style_node) const
bool style_serializer::read_stylesheet(const xml_document &xml)
{
auto stylesheet_node = xml.root();
auto stylesheet_node = xml.get_child("styleSheet");
read_borders(stylesheet_node.get_child("borders"));
read_fills(stylesheet_node.get_child("fills"));
@ -293,7 +293,7 @@ bool style_serializer::read_stylesheet(const xml_document &xml)
continue;
}
wb_.add_style(read_style(xf_node));
workbook_.add_style(read_style(xf_node));
}
return true;
@ -320,7 +320,7 @@ bool style_serializer::read_number_formats(const xml_node &number_formats_node)
nf.set_format_string(format_string);
nf.set_id(std::stoull(num_fmt_node.get_attribute("numFmtId")));
wb_.add_number_format(nf);
workbook_.add_number_format(nf);
}
return true;
@ -330,13 +330,13 @@ bool style_serializer::read_fonts(const xml_node &fonts_node)
{
for(auto font_node : fonts_node.get_children())
{
wb_.add_font(read_font(font_node));
workbook_.add_font(read_font(font_node));
}
return true;
}
font style_serializer::read_font(const xlnt::xml_node &font_node) const
font style_serializer::read_font(const xlnt::xml_node &font_node)
{
font new_font;
@ -390,7 +390,7 @@ bool style_serializer::read_colors(const xml_node &colors_node)
for(const auto &indexed_color : indexed_colors)
{
wb_.add_color(indexed_color);
workbook_.add_color(indexed_color);
}
}
@ -401,13 +401,13 @@ bool style_serializer::read_fills(const xml_node &fills_node)
{
for(auto fill_node : fills_node.get_children())
{
wb_.add_fill(read_fill(fill_node));
workbook_.add_fill(read_fill(fill_node));
}
return true;
}
fill style_serializer::read_fill(const xml_node &fill_node) const
fill style_serializer::read_fill(const xml_node &fill_node)
{
fill new_fill;
@ -432,7 +432,7 @@ fill style_serializer::read_fill(const xml_node &fill_node) const
return new_fill;
}
side style_serializer::read_side(const xml_node &side_node) const
side style_serializer::read_side(const xml_node &side_node)
{
side new_side;
@ -453,13 +453,13 @@ bool style_serializer::read_borders(const xml_node &borders_node)
{
for(auto border_node : borders_node.get_children())
{
wb_.add_border(read_border(border_node));
workbook_.add_border(read_border(border_node));
}
return true;
}
border style_serializer::read_border(const xml_node &border_node) const
border style_serializer::read_border(const xml_node &border_node)
{
border new_border;
@ -520,21 +520,56 @@ border style_serializer::read_border(const xml_node &border_node) const
return new_border;
}
bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
std::vector<color> style_serializer::read_indexed_colors(const xml_node &indexed_colors_node)
{
std::vector<color> colors;
for(auto color_node : indexed_colors_node.get_children())
{
colors.push_back(read_color(color_node));
}
return colors;
}
color style_serializer::read_color(const xml_node &color_node)
{
if(color_node.has_attribute("rgb"))
{
return color(color::type::rgb, color_node.get_attribute("rgb"));
}
else if(color_node.has_attribute("theme"))
{
return color(color::type::theme, std::stoull(color_node.get_attribute("theme")));
}
else if(color_node.has_attribute("indexed"))
{
return color(color::type::indexed, std::stoull(color_node.get_attribute("indexed")));
}
else if(color_node.has_attribute("auto"))
{
return color(color::type::auto_, std::stoull(color_node.get_attribute("auto")));
}
throw std::runtime_error("bad color");
return color();
}
xml_document style_serializer::write_stylesheet() const
{
xml_document xml;
auto style_sheet_node = xml.add_child("styleSheet");
xml.add_namespace("", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
xml.add_namespace("mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
style_sheet_node.add_attribute("mc:Ignorable", "x14ac");
xml.add_namespace("x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
auto &style_sheet_node = xml.root();
style_sheet_node.set_name("styleSheet");
style_sheet_node.add_attribute("mc:Ignorable", "x14ac");
auto num_fmts_node = style_sheet_node.add_child("numFmts");
auto num_fmts = wb_.get_number_formats();
auto num_fmts = workbook_.get_number_formats();
num_fmts_node.add_attribute("count", std::to_string(num_fmts.size()));
for(auto &num_fmt : num_fmts)
for(const auto &num_fmt : num_fmts)
{
auto num_fmt_node = num_fmts_node.add_child("numFmt");
num_fmt_node.add_attribute("numFmtId", std::to_string(num_fmt.get_id()));
@ -542,7 +577,7 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
}
auto fonts_node = style_sheet_node.add_child("fonts");
auto fonts = wb_.get_fonts();
auto fonts = workbook_.get_fonts();
if(fonts.empty())
{
@ -620,7 +655,7 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
}
auto fills_node = style_sheet_node.add_child("fills");
const auto &fills = wb_.get_fills();
const auto &fills = workbook_.get_fills();
fills_node.add_attribute("count", std::to_string(fills.size()));
for(auto &fill_ : fills)
@ -635,7 +670,7 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
if(fill_.has_foreground_color())
{
auto &fg_color_node = pattern_fill_node.add_child("fgColor");
auto fg_color_node = pattern_fill_node.add_child("fgColor");
switch(fill_.get_foreground_color().get_type())
{
@ -689,7 +724,7 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
}
auto borders_node = style_sheet_node.add_child("borders");
const auto &borders = wb_.get_borders();
const auto &borders = workbook_.get_borders();
borders_node.add_attribute("count", std::to_string(borders.size()));
for(const auto &border_ : borders)
@ -764,17 +799,17 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
}
}
auto &cell_style_xfs_node = style_sheet_node.add_child("cellStyleXfs");
auto cell_style_xfs_node = style_sheet_node.add_child("cellStyleXfs");
cell_style_xfs_node.add_attribute("count", "1");
auto &style_xf_node = cell_style_xfs_node.add_child("xf");
auto style_xf_node = cell_style_xfs_node.add_child("xf");
style_xf_node.add_attribute("numFmtId", "0");
style_xf_node.add_attribute("fontId", "0");
style_xf_node.add_attribute("fillId", "0");
style_xf_node.add_attribute("borderId", "0");
auto cell_xfs_node = style_sheet_node.add_child("cellXfs");
const auto &styles = wb_.get_styles();
const auto &styles = workbook_.get_styles();
cell_xfs_node.add_attribute("count", std::to_string(styles.size()));
for(auto &style : styles)
@ -876,7 +911,7 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
auto colors_node = style_sheet_node.add_child("colors");
auto indexed_colors_node = colors_node.add_child("indexedColors");
for(auto &c : wb_.get_colors())
for(auto &c : workbook_.get_colors())
{
indexed_colors_node.add_child("rgbColor").add_attribute("rgb", c.get_rgb_string());
}
@ -887,16 +922,16 @@ bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
ext_node.add_attribute("xmlns:x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main");
ext_node.add_child("x14:slicerStyles").add_attribute("defaultSlicerStyle", "SlicerStyleLight1");
return true;
return xml;
}
bool style_serializer::write_number_formats(xml_node &number_formats_node) const
bool style_serializer::write_number_formats(xml_node number_formats_node) const
{
number_formats_node.add_attribute("count", std::to_string(wb_.get_number_formats().size()));
number_formats_node.add_attribute("count", std::to_string(workbook_.get_number_formats().size()));
for(const auto &num_fmt : wb_.get_number_formats())
for(const auto &num_fmt : workbook_.get_number_formats())
{
auto &num_fmt_node = number_formats_node.add_child("numFmt");
auto num_fmt_node = number_formats_node.add_child("numFmt");
num_fmt_node.add_attribute("numFmtId", std::to_string(num_fmt.get_id()));
num_fmt_node.add_attribute("formatCode", num_fmt.get_format_string());
}

View File

@ -7,17 +7,16 @@
namespace xlnt {
//I have no idea what this stuff is. I hope it was worth it.
xml_document theme_serializer::write_theme(const theme &theme_)
xml_document theme_serializer::write_theme(const theme &) const
{
xml_document xml;
auto theme_node = xml.add_child("a:theme");
xml.add_namespace("a", constants::Namespaces.at("drawingml"));
auto &theme_node = xml.root();
theme_node.set_name("a:theme");
theme_node.add_attribute("name", "Office Theme");
auto &theme_elements_node = theme_node.add_child("a:themeElements");
auto &clr_scheme_node = theme_elements_node.add_child("a:clrScheme");
auto theme_elements_node = theme_node.add_child("a:themeElements");
auto clr_scheme_node = theme_elements_node.add_child("a:clrScheme");
clr_scheme_node.add_attribute("name", "Office");
struct scheme_element
@ -112,19 +111,19 @@ xml_document theme_serializer::write_theme(const theme &theme_)
{
if(scheme.typeface)
{
auto &major_font_node = major_fonts_node.add_child(scheme.script);
auto major_font_node = major_fonts_node.add_child(scheme.script);
major_font_node.add_attribute("typeface", scheme.major);
auto &minor_font_node = minor_fonts_node.add_child(scheme.script);
auto minor_font_node = minor_fonts_node.add_child(scheme.script);
minor_font_node.add_attribute("typeface", scheme.minor);
}
else
{
auto &major_font_node = major_fonts_node.add_child("a:font");
auto major_font_node = major_fonts_node.add_child("a:font");
major_font_node.add_attribute("script", scheme.script);
major_font_node.add_attribute("typeface", scheme.major);
auto &minor_font_node = minor_fonts_node.add_child("a:font");
auto minor_font_node = minor_fonts_node.add_child("a:font");
minor_font_node.add_attribute("script", scheme.script);
minor_font_node.add_attribute("typeface", scheme.minor);
}
@ -141,7 +140,7 @@ xml_document theme_serializer::write_theme(const theme &theme_)
auto grad_fill_list = grad_fill_node.add_child("a:gsLst");
auto gs_node = grad_fill_list.add_child("a:gs");
gs_node.add_attribute("pos", 0);
gs_node.add_attribute("pos", "0");
auto scheme_color_node = gs_node.add_child("a:schemeClr");
scheme_color_node.add_attribute("val", "phClr");
scheme_color_node.add_child("a:tint").add_attribute("val", "50000");

View File

@ -50,10 +50,14 @@ std::string datetime_to_w3cdtf(const xlnt::datetime &dt)
} // namespace
namespace xlnt {
/*
std::vector<std::pair<std::string, std::string>> workbook_serializer::read_sheets(zip_file &archive)
workbook_serializer::workbook_serializer(workbook &wb) : workbook_(wb)
{
}
std::vector<workbook_serializer::string_pair> workbook_serializer::read_sheets()
{
/*
std::string ns;
for(auto child : doc.children())
@ -72,9 +76,9 @@ std::vector<std::pair<std::string, std::string>> workbook_serializer::read_sheet
auto root_node = doc.get_child(with_ns("workbook"));
auto sheets_node = root_node.get_child(with_ns("sheets"));
std::vector<std::pair<std::string, std::string>> sheets;
*/
std::vector<string_pair> sheets;
/*
// store temp because pugixml iteration uses the internal char array multiple times
auto sheet_element_name = with_ns("sheet");
@ -84,15 +88,14 @@ std::vector<std::pair<std::string, std::string>> workbook_serializer::read_sheet
std::string name = sheet_node.attribute("name").as_string();
sheets.push_back(std::make_pair(id, name));
}
*/
return sheets;
}
*/
void workbook_serializer::read_properties_core(const xml_document &xml)
{
auto &props = wb_.get_properties();
auto root_node = xml.root();
auto &props = workbook_.get_properties();
auto root_node = xml.get_child("dc:coreProperties");
props.excel_base_date = calendar::windows_1900;
@ -116,44 +119,19 @@ void workbook_serializer::read_properties_core(const xml_document &xml)
}
}
std::string workbook_serializer::determine_document_type(const manifest &manifest)
{
if(!manifest.has_override_type(constants::ArcWorkbook))
{
return "unsupported";
}
std::string type = manifest.get_override_type(constants::ArcWorkbook);
if(type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml")
{
return "excel";
}
else if(type == "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml")
{
return "powerpoint";
}
else if(type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")
{
return "word";
}
return "unsupported";
}
/// <summary>
/// Return a list of worksheets.
/// content types has a list of paths but no titles
/// workbook has a list of titles and relIds but no paths
/// workbook_rels has a list of relIds and paths but no titles
/// </summary>
std::vector<string_pair> workbook_serializer::detect_worksheets()
std::vector<workbook_serializer::string_pair> workbook_serializer::detect_worksheets()
{
static const std::string ValidWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
std::vector<std::string> valid_sheets;
for(const auto &content_type : wb_.get_manifest().get_override_types())
for(const auto &content_type : workbook_.get_manifest().get_override_types())
{
if(content_type.get_content_type() == ValidWorksheet)
{
@ -161,7 +139,7 @@ std::vector<string_pair> workbook_serializer::detect_worksheets()
}
}
auto &workbook_relationships = wb_.get_relationships();
auto &workbook_relationships = workbook_.get_relationships();
std::vector<std::pair<std::string, std::string>> result;
for(const auto &ws : read_sheets())
@ -180,19 +158,18 @@ std::vector<string_pair> workbook_serializer::detect_worksheets()
xml_document workbook_serializer::write_properties_core() const
{
auto &props = wb_.get_properties();
auto &props = workbook_.get_properties();
xml_document xml;
auto root_node = xml.add_child("cp:coreProperties");
xml.add_namespace("cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
xml.add_namespace("dc", "http://purl.org/dc/elements/1.1/");
xml.add_namespace("dcmitype", "http://purl.org/dc/dcmitype/");
xml.add_namespace("dcterms", "http://purl.org/dc/terms/");
xml.add_namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
auto &root_node = xml.root();
root_node.set_name("cp:coreProperties");
root_node.add_child("dc:creator").set_text(props.creator);
root_node.add_child("cp:lastModifiedBy").set_text(props.last_modified_by);
root_node.add_child("dcterms:created").set_text(datetime_to_w3cdtf(props.created));
@ -212,11 +189,10 @@ xml_document workbook_serializer::write_properties_app() const
{
xml_document xml;
xml.add_namespace("xmlns", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
xml.add_namespace("xmlns:vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
auto root_node = xml.add_child("Properties");
auto &root_node = xml.root();
root_node.set_name("Properties");
xml.add_namespace("", "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
xml.add_namespace("vt", "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
root_node.add_child("Application").set_text("Microsoft Excel");
root_node.add_child("DocSecurity").set_text("0");
@ -232,14 +208,14 @@ xml_document workbook_serializer::write_properties_app() const
heading_pairs_vector_node.add_attribute("baseType", "variant");
heading_pairs_vector_node.add_attribute("size", "2");
heading_pairs_vector_node.add_child("vt:variant").add_child("vt:lpstr").set_text("Worksheets");
heading_pairs_vector_node.add_child("vt:variant").add_child("vt:i4").set_text(std::to_string(wb_.get_sheet_names().size()));
heading_pairs_vector_node.add_child("vt:variant").add_child("vt:i4").set_text(std::to_string(workbook_.get_sheet_names().size()));
auto titles_of_parts_node = root_node.add_child("TitlesOfParts");
auto titles_of_parts_vector_node = titles_of_parts_node.add_child("vt:vector");
titles_of_parts_vector_node.add_attribute("baseType", "lpstr");
titles_of_parts_vector_node.add_attribute("size", std::to_string(wb_.get_sheet_names().size()));
titles_of_parts_vector_node.add_attribute("size", std::to_string(workbook_.get_sheet_names().size()));
for(auto ws : wb_)
for(auto ws : workbook_)
{
titles_of_parts_vector_node.add_child("vt:lpstr").set_text(ws.get_title());
}
@ -251,7 +227,7 @@ xml_document workbook_serializer::write_workbook() const
{
std::size_t num_visible = 0;
for(auto ws : wb_)
for(auto ws : workbook_)
{
if(ws.get_page_setup().get_sheet_state() == xlnt::page_setup::sheet_state::visible)
{
@ -266,22 +242,21 @@ xml_document workbook_serializer::write_workbook() const
xml_document xml;
xml.add_namespace("xmlns", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
xml.add_namespace("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
auto root_node = xml.add_child("workbook");
auto &root_node = xml.root();
root_node.set_name("workbook");
xml.add_namespace("", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
xml.add_namespace("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
auto &file_version_node = root_node.add_child("fileVersion");
auto file_version_node = root_node.add_child("fileVersion");
file_version_node.add_attribute("appName", "xl");
file_version_node.add_attribute("lastEdited", "4");
file_version_node.add_attribute("lowestEdited", "4");
file_version_node.add_attribute("rupBuild", "4505");
auto &workbook_pr_node = root_node.add_child("workbookPr");
auto workbook_pr_node = root_node.add_child("workbookPr");
workbook_pr_node.add_attribute("codeName", "ThisWorkbook");
workbook_pr_node.add_attribute("defaultThemeVersion", "124226");
workbook_pr_node.add_attribute("date1904", wb_.get_properties().excel_base_date == calendar::mac_1904 ? "1" : "0");
workbook_pr_node.add_attribute("date1904", workbook_.get_properties().excel_base_date == calendar::mac_1904 ? "1" : "0");
auto book_views_node = root_node.add_child("bookViews");
auto workbook_view_node = book_views_node.add_child("workbookView");
@ -298,10 +273,11 @@ xml_document workbook_serializer::write_workbook() const
auto sheets_node = root_node.add_child("sheets");
auto defined_names_node = root_node.add_child("definedNames");
for(auto relationship : wb_.get_relationships())
for(const auto &relationship : workbook_.get_relationships())
{
if(relationship.get_type() == relationship::type::worksheet)
{
//TODO: this is ugly
std::string sheet_index_string = relationship.get_target_uri();
sheet_index_string = sheet_index_string.substr(0, sheet_index_string.find('.'));
sheet_index_string = sheet_index_string.substr(sheet_index_string.find_last_of('/'));
@ -312,16 +288,16 @@ xml_document workbook_serializer::write_workbook() const
sheet_index_string = sheet_index_string.substr(static_cast<std::string::size_type>(first_digit + 1));
std::size_t sheet_index = static_cast<std::size_t>(std::stoll(sheet_index_string) - 1);
auto ws = wb_.get_sheet_by_index(sheet_index);
auto ws = workbook_.get_sheet_by_index(sheet_index);
auto sheet_node = sheets_node.add_child("sheet");
sheet_node.add_attribute("name", ws.get_title());
sheet_node.add_attribute("r:id", relationship.get_id());
sheet_node.add_attribute("sheetId", std::to_string(sheet_index + 1));
sheet_node.add_attribute("r:id", relationship.get_id());
if(ws.has_auto_filter())
{
auto &defined_name_node = defined_names_node.add_child("definedName");
auto defined_name_node = defined_names_node.add_child("definedName");
defined_name_node.add_attribute("name", "_xlnm._FilterDatabase");
defined_name_node.add_attribute("hidden", "1");
defined_name_node.add_attribute("localSheetId", "0");
@ -339,14 +315,16 @@ xml_document workbook_serializer::write_workbook() const
return xml;
}
bool workbook_serializer::write_named_ranges(xlnt::xml_node &named_ranges_node)
xml_node workbook_serializer::write_named_ranges() const
{
for(auto &named_range : wb_.get_named_ranges())
xlnt::xml_node named_ranges_node;
for(auto &named_range : workbook_.get_named_ranges())
{
named_ranges_node.add_child(named_range.get_name());
}
return true;
return named_ranges_node;
}
} // namespace xlnt

View File

@ -21,10 +21,14 @@ bool is_integral(long double d)
} // namepsace
namespace xlnt {
bool worksheet_serializer::read_worksheet(const xml_document &xml, const std::vector<std::string> &string_table, const relationship &rel)
worksheet_serializer::worksheet_serializer(worksheet sheet) : sheet_(sheet)
{
auto &root_node = xml.root();
}
bool worksheet_serializer::read_worksheet(const xml_document &xml)
{
auto &root_node = xml.get_child("worksheet");
auto &dimension_node = root_node.get_child("dimension");
std::string dimension = dimension_node.get_attribute("ref");
@ -53,6 +57,8 @@ bool worksheet_serializer::read_worksheet(const xml_document &xml, const std::ve
}
}
auto &shared_strings = sheet_.get_parent().get_shared_strings();
for(auto row_node : sheet_data_node.get_children())
{
if(row_node.get_name() != "row")
@ -62,7 +68,7 @@ bool worksheet_serializer::read_worksheet(const xml_document &xml, const std::ve
auto row_index = static_cast<row_t>(std::stoull(row_node.get_attribute("r")));
if(row_node.get_attribute("ht") != nullptr)
if(row_node.has_attribute("ht"))
{
sheet_.get_row_properties(row_index).height = std::stold(row_node.get_attribute("ht"));
}
@ -111,10 +117,10 @@ bool worksheet_serializer::read_worksheet(const xml_document &xml, const std::ve
bool has_value = cell_node.has_child("v");
std::string value_string = has_value ? cell_node.get_child("v").get_text() : "";
bool has_type = cell_node.get_attribute("t") != nullptr;
bool has_type = cell_node.has_attribute("t");
std::string type = has_type ? cell_node.get_attribute("t") : "";
bool has_style = cell_node.get_attribute("s") != nullptr;
bool has_style = cell_node.has_attribute("s");
int style_id = has_style ? std::stoull(cell_node.get_attribute("s")) : 0;
bool has_formula = cell_node.has_child("f");
@ -136,7 +142,7 @@ bool worksheet_serializer::read_worksheet(const xml_document &xml, const std::ve
else if(has_type && type == "s" && !has_formula) // shared string
{
auto shared_string_index = std::stoull(value_string);
auto shared_string = string_table.at(shared_string_index);
auto shared_string = shared_strings.at(shared_string_index);
cell.set_value(shared_string);
}
else if(has_type && type == "b") // boolean
@ -205,34 +211,35 @@ bool worksheet_serializer::read_worksheet(const xml_document &xml, const std::ve
return true;
}
bool worksheet_serializer::write_worksheet(const std::vector<std::string> &string_table, xml_document &xml)
xml_document worksheet_serializer::write_worksheet() const
{
sheet_.get_cell("A1");
xml_document xml;
auto root_node = xml.add_child("worksheet");
xml.add_namespace("", constants::Namespaces.at("spreadsheetml"));
xml.add_namespace("r", constants::Namespaces.at("r"));
auto &root_node = xml.root();
root_node.set_name("worksheet");
auto &sheet_pr_node = root_node.add_child("sheetPr");
auto sheet_pr_node = root_node.add_child("sheetPr");
if(!sheet_.get_page_setup().is_default())
{
auto &page_set_up_pr_node = sheet_pr_node.add_child("pageSetUpPr");
auto page_set_up_pr_node = sheet_pr_node.add_child("pageSetUpPr");
page_set_up_pr_node.add_attribute("fitToPage", sheet_.get_page_setup().fit_to_page() ? "1" : "0");
}
auto &outline_pr_node = sheet_pr_node.add_child("outlinePr");
auto outline_pr_node = sheet_pr_node.add_child("outlinePr");
outline_pr_node.add_attribute("summaryBelow", "1");
outline_pr_node.add_attribute("summaryRight", "1");
auto &dimension_node = root_node.add_child("dimension");
auto dimension_node = root_node.add_child("dimension");
dimension_node.add_attribute("ref", sheet_.calculate_dimension().to_string());
auto &sheet_views_node = root_node.add_child("sheetViews");
auto &sheet_view_node = sheet_views_node.add_child("sheetView");
auto sheet_views_node = root_node.add_child("sheetViews");
auto sheet_view_node = sheet_views_node.add_child("sheetView");
sheet_view_node.add_attribute("workbookViewId", "0");
std::string active_pane = "bottomRight";
@ -325,6 +332,7 @@ bool worksheet_serializer::write_worksheet(const std::vector<std::string> &strin
std::unordered_map<std::string, std::string> hyperlink_references;
auto sheet_data_node = root_node.add_child("sheetData");
const auto &shared_strings = sheet_.get_parent().get_shared_strings();
for(auto row : sheet_.rows())
{
@ -395,9 +403,9 @@ bool worksheet_serializer::write_worksheet(const std::vector<std::string> &strin
int match_index = -1;
for(std::size_t i = 0; i < string_table.size(); i++)
for(std::size_t i = 0; i < shared_strings.size(); i++)
{
if(string_table[i] == cell.get_value<std::string>())
if(shared_strings[i] == cell.get_value<std::string>())
{
match_index = static_cast<int>(i);
break;
@ -545,7 +553,7 @@ bool worksheet_serializer::write_worksheet(const std::vector<std::string> &strin
odd_footer_node.set_text(footer_text);
}
return true;
return xml;
}
} // namespace xlnt

View File

@ -1,25 +1,78 @@
#include <xlnt/s11n/xml_document.hpp>
#include <xlnt/s11n/xml_node.hpp>
#include <xlnt/s11n/xml_serializer.hpp>
#include <detail/xml_document_impl.hpp>
#include <detail/xml_node_impl.hpp>
namespace xlnt {
xml_document::xml_document() : d_(new detail::xml_document_impl())
{
}
xml_document::xml_document(const xml_document &other) : xml_document()
{
d_->doc.append_copy(other.d_->doc.root());
}
xml_document::~xml_document()
{
}
void xml_document::set_encoding(const std::string &encoding)
{
d_->encoding = encoding;
}
void xml_document::add_namespace(const std::string &id, const std::string &uri)
{
d_->doc.first_child().append_attribute((id.empty() ? "xmlns" : "xmlns:" + id).c_str()).set_value(uri.c_str());
}
xml_node xml_document::add_child(const xml_node &child)
{
auto child_node = d_->doc.root().append_copy(child.d_->node);
return xml_node(detail::xml_node_impl(child_node));
}
xml_node xml_document::add_child(const std::string &child_name)
{
auto child = d_->doc.root().append_child(child_name.c_str());
return xml_node(detail::xml_node_impl(child));
}
xml_node xml_document::get_root()
{
return xml_node(detail::xml_node_impl(d_->doc.root()));
}
const xml_node xml_document::get_root() const
{
return xml_node(detail::xml_node_impl(d_->doc.root()));
}
std::string xml_document::to_string() const
{
return xml_serializer::serialize(*this);
}
xml_document &xml_document::from_string(const std::string &xml_string)
{
auto doc = xml_serializer::deserialize(xml_string);
std::swap(doc.d_, d_);
return *this;
}
xml_node &xml_document::root()
xml_node xml_document::get_child(const std::string &child_name)
{
return root_;
return xml_node(detail::xml_node_impl(d_->doc.child(child_name.c_str())));
}
const xml_node &xml_document::root() const
const xml_node xml_document::get_child(const std::string &child_name) const
{
return root_;
return xml_node(detail::xml_node_impl(d_->doc.child(child_name.c_str())));
}
} // namespace xlnt

View File

@ -1,120 +1,139 @@
#include <xlnt/s11n/xml_node.hpp>
#include <xlnt/s11n/xml_serializer.hpp>
#include <detail/xml_node_impl.hpp>
namespace xlnt {
xml_node::xml_node()
xml_node::xml_node() : d_(new detail::xml_node_impl)
{
}
xml_node::xml_node(const std::string &name)
xml_node::xml_node(const detail::xml_node_impl &d) : xml_node()
{
set_name(name);
d_->node = d.node;
}
xml_node::~xml_node()
{
}
xml_node::xml_node(const xml_node &other) : xml_node()
{
d_->node = other.d_->node;
}
xml_node &xml_node::operator=(const xlnt::xml_node &other)
{
d_->node = other.d_->node;
return *this;
}
std::string xml_node::get_name() const
{
return name_;
return d_->node.name();
}
void xml_node::set_name(const std::string &name)
{
name_ = name;
d_->node.set_name(name.c_str());
}
bool xml_node::has_text() const
{
return has_text_;
return d_->node.text() != nullptr;
}
std::string xml_node::get_text() const
{
return text_;
return d_->node.text().as_string();
}
void xml_node::set_text(const std::string &text)
{
text_ = text;
has_text_ = true;
d_->node.text().set(text.c_str());
}
const std::vector<xml_node> &xml_node::get_children() const
const std::vector<xml_node> xml_node::get_children() const
{
return children_;
}
xml_node &xml_node::add_child(const xml_node &child)
{
has_text_ = false;
text_.clear();
std::vector<xml_node> children;
children_.push_back(child);
return children_.back();
for(auto child : d_->node.children())
{
children.push_back(xml_node(detail::xml_node_impl(child)));
}
return children;
}
xml_node &xml_node::add_child(const std::string &child_name)
xml_node xml_node::add_child(const xml_node &child)
{
return add_child(xml_node(child_name));
auto child_node = xml_node(detail::xml_node_impl(d_->node.append_child(child.get_name().c_str())));
for(auto attr : child.get_attributes())
{
child_node.add_attribute(attr.first, attr.second);
}
for(auto child_child : child.get_children())
{
child_node.add_child(child_child);
}
return child_node;
}
const std::vector<string_pair> &xml_node::get_attributes() const
xml_node xml_node::add_child(const std::string &child_name)
{
return attributes_;
return xml_node(detail::xml_node_impl(d_->node.append_child(child_name.c_str())));
}
const std::vector<xml_node::string_pair> xml_node::get_attributes() const
{
std::vector<string_pair> attributes;
for(auto attr : d_->node.attributes())
{
attributes.push_back(std::make_pair<std::string, std::string>(attr.name(), attr.value()));
}
return attributes;
}
void xml_node::add_attribute(const std::string &name, const std::string &value)
{
attributes_.push_back(std::make_pair(name, value));
d_->node.append_attribute(name.c_str()).set_value(value.c_str());
}
bool xml_node::has_attribute(const std::string &attribute_name) const
{
return std::find_if(attributes_.begin(), attributes_.end(),
[&](const string_pair &p) { return p.first == attribute_name; }) != attributes_.end();
return d_->node.attribute(attribute_name.c_str()) != nullptr;
}
std::string xml_node::get_attribute(const std::string &attribute_name) const
{
auto match = std::find_if(attributes_.begin(), attributes_.end(),
[&](const string_pair &p) { return p.first == attribute_name; });
if(match == attributes_.end())
{
throw std::runtime_error("attribute doesn't exist: " + attribute_name);
}
return match->second;
return d_->node.attribute(attribute_name.c_str()).value();
}
bool xml_node::has_child(const std::string &child_name) const
{
return std::find_if(children_.begin(), children_.end(),
[&](const xml_node &n) { return n.get_name() == child_name; }) != children_.end();
return d_->node.child(child_name.c_str()) != nullptr;
}
xml_node &xml_node::get_child(const std::string &child_name)
xml_node xml_node::get_child(const std::string &child_name)
{
auto match = std::find_if(children_.begin(), children_.end(),
[&](const xml_node &n) { return n.get_name() == child_name; });
if(match == children_.end())
{
throw std::runtime_error("child doesn't exist: " + child_name);
}
return *match;
return xml_node(detail::xml_node_impl(d_->node.child(child_name.c_str())));
}
const xml_node &xml_node::get_child(const std::string &child_name) const
const xml_node xml_node::get_child(const std::string &child_name) const
{
auto match = std::find_if(children_.begin(), children_.end(),
[&](const xml_node &n) { return n.get_name() == child_name; });
return xml_node(detail::xml_node_impl(d_->node.child(child_name.c_str())));
}
if(match == children_.end())
{
throw std::runtime_error("child doesn't exist: " + child_name);
}
return *match;
std::string xml_node::to_string() const
{
return xml_serializer::serialize_node(*this);
}
} // namespace xlnt

View File

@ -5,65 +5,31 @@
#include <xlnt/s11n/xml_node.hpp>
#include "detail/include_pugixml.hpp"
namespace {
void serialize_node(const xlnt::xml_node &source, pugi::xml_node node)
{
for(const auto &attribute : source.get_attributes())
{
node.append_attribute(attribute.first.c_str()).set_value(attribute.second.c_str());
}
if(source.has_text())
{
node.text().set(source.get_text().c_str());
}
else
{
for(const auto &child : source.get_children())
{
pugi::xml_node child_node = node.append_child(child.get_name().c_str());
serialize_node(child, child_node);
}
}
}
xlnt::xml_node deserialize_node(const pugi::xml_node source)
{
xlnt::xml_node node(source.name());
for(const auto attribute : source.attributes())
{
node.add_attribute(attribute.name(), attribute.as_string());
}
if(source.text() != nullptr)
{
node.set_text(source.text().as_string());
}
else
{
for(const auto child : source.children())
{
node.add_child(deserialize_node(child));
}
}
return node;
}
} // namespace
#include "detail/xml_document_impl.hpp"
#include "detail/xml_node_impl.hpp"
namespace xlnt {
std::string xml_serializer::serialize(const xml_document &xml)
{
pugi::xml_document doc;
std::ostringstream ss;
xml.d_->doc.save(ss, " ", pugi::format_default, pugi::encoding_utf8);
auto root = doc.root();
root.set_name(xml.root().get_name().c_str());
serialize_node(xml.root(), root);
return ss.str();
}
xml_document xml_serializer::deserialize(const std::string &xml_string)
{
xml_document doc;
doc.d_->doc.load(xml_string.c_str());
return doc;
}
std::string xml_serializer::serialize_node(const xml_node &xml)
{
pugi::xml_document doc;
doc.append_copy(xml.d_->node);
std::ostringstream ss;
doc.save(ss);
@ -71,15 +37,4 @@ std::string xml_serializer::serialize(const xml_document &xml)
return ss.str();
}
xml_document xml_serializer::deserialize(const std::string &xml_string)
{
pugi::xml_document doc;
doc.load(xml_string.c_str());
xml_document result;
result.root() = deserialize_node(doc.root());
return result;
}
} // namespace xlnt

View File

@ -1,7 +1,78 @@
#include <xlnt/workbook/manifest.hpp>
namespace {
bool match_path(const std::string &path, const std::string &comparand)
{
if(path == comparand)
{
return true;
}
if(path[0] != '/' && path[0] != '.' && comparand[0] == '/')
{
return match_path("/" + path, comparand);
}
else if(comparand[0] != '/' && comparand[0] != '.' && path[0] == '/')
{
return match_path(path, "/" + comparand);
}
return false;
}
} // namespace
namespace xlnt {
default_type::default_type()
{
}
default_type::default_type(const std::string &extension, const std::string &content_type) :
extension_(extension),
content_type_(content_type)
{
}
default_type::default_type(const default_type &other) :
extension_(other.extension_),
content_type_(other.content_type_)
{
}
default_type &default_type::operator=(const default_type &other)
{
extension_ = other.extension_;
content_type_ = other.content_type_;
return *this;
}
override_type::override_type()
{
}
override_type::override_type(const std::string &part_name, const std::string &content_type) :
part_name_(part_name),
content_type_(content_type)
{
}
override_type::override_type(const override_type &other) :
part_name_(other.part_name_),
content_type_(other.content_type_)
{
}
override_type &override_type::operator=(const override_type &other)
{
part_name_ = other.part_name_;
content_type_ = other.content_type_;
return *this;
}
bool manifest::has_default_type(const std::string &extension) const
{
return std::find_if(default_types_.begin(), default_types_.end(),
@ -11,7 +82,17 @@ bool manifest::has_default_type(const std::string &extension) const
bool manifest::has_override_type(const std::string &part_name) const
{
return std::find_if(override_types_.begin(), override_types_.end(),
[&](const override_type &d) { return d.get_part_name() == part_name; }) != override_types_.end();
[&](const override_type &d) { return match_path(d.get_part_name(), part_name); }) != override_types_.end();
}
void manifest::add_default_type(const std::string &extension, const std::string &content_type)
{
default_types_.push_back(default_type(extension, content_type));
}
void manifest::add_override_type(const std::string &part_name, const std::string &content_type)
{
override_types_.push_back(override_type(part_name, content_type));
}
std::string manifest::get_default_type(const std::string &extension) const
@ -30,7 +111,7 @@ std::string manifest::get_default_type(const std::string &extension) const
std::string manifest::get_override_type(const std::string &part_name) const
{
auto match = std::find_if(override_types_.begin(), override_types_.end(),
[&](const override_type &d) { return d.get_part_name() == part_name; });
[&](const override_type &d) { return match_path(d.get_part_name(), part_name); });
if(match == override_types_.end())
{

View File

@ -619,7 +619,7 @@ const number_format &workbook::get_number_format(std::size_t style_id) const
for(const auto &number_format_ : d_->number_formats_)
{
if(number_format_.get_id() == number_format_id)
if(static_cast<std::size_t>(number_format_.get_id()) == number_format_id)
{
return number_format_;
}
@ -631,15 +631,15 @@ const number_format &workbook::get_number_format(std::size_t style_id) const
return d_->number_formats_.back();
}
const font &workbook::get_font(std::size_t style_id) const
const font &workbook::get_font(std::size_t font_id) const
{
return d_->fonts_[d_->styles_[style_id].font_id_];
return d_->fonts_[font_id];
}
std::size_t workbook::set_font(const font &font_, std::size_t style_id)
{
auto match = std::find(d_->fonts_.begin(), d_->fonts_.end(), font_);
auto font_index = 0;
std::size_t font_index = 0;
if(match == d_->fonts_.end())
{
@ -674,22 +674,22 @@ std::size_t workbook::set_font(const font &font_, std::size_t style_id)
return d_->styles_.size() - 1;
}
const fill &workbook::get_fill(std::size_t style_id) const
const fill &workbook::get_fill(std::size_t fill_id) const
{
return d_->fills_[d_->styles_[style_id].fill_id_];
return d_->fills_[fill_id];
}
std::size_t workbook::set_fill(const fill &fill_, std::size_t style_id)
std::size_t workbook::set_fill(const fill &/*fill_*/, std::size_t style_id)
{
return style_id;
}
const border &workbook::get_border(std::size_t style_id) const
const border &workbook::get_border(std::size_t border_id) const
{
return d_->borders_[d_->styles_[style_id].border_id_];
return d_->borders_[border_id];
}
std::size_t workbook::set_border(const border &border_, std::size_t style_id)
std::size_t workbook::set_border(const border &/*border_*/, std::size_t style_id)
{
return style_id;
}
@ -699,7 +699,7 @@ const alignment &workbook::get_alignment(std::size_t style_id) const
return d_->styles_[style_id].alignment_;
}
std::size_t workbook::set_alignment(const alignment &alignment_, std::size_t style_id)
std::size_t workbook::set_alignment(const alignment &/*alignment_*/, std::size_t style_id)
{
return style_id;
}
@ -709,7 +709,7 @@ const protection &workbook::get_protection(std::size_t style_id) const
return d_->styles_[style_id].protection_;
}
std::size_t workbook::set_protection(const protection &protection_, std::size_t style_id)
std::size_t workbook::set_protection(const protection &/*protection_*/, std::size_t style_id)
{
return style_id;
}
@ -861,12 +861,27 @@ const std::vector<relationship> &workbook::get_root_relationships() const
{
if(d_->root_relationships_.empty())
{
d_->root_relationships_.push_back(relationship(relationship::type::extended_properties, "rId3", "docProps/app.xml"));
d_->root_relationships_.push_back(relationship(relationship::type::core_properties, "rId2", "docProps/core.xml"));
d_->root_relationships_.push_back(relationship(relationship::type::office_document, "rId1", "xl/workbook.xml"));
d_->root_relationships_.push_back(relationship(relationship::type::core_properties, "rId1", "docProps/core.xml"));
d_->root_relationships_.push_back(relationship(relationship::type::extended_properties, "rId2", "docProps/app.xml"));
d_->root_relationships_.push_back(relationship(relationship::type::office_document, "rId3", "xl/workbook.xml"));
}
return d_->root_relationships_;
}
std::vector<std::string> &workbook::get_shared_strings()
{
return d_->shared_strings_;
}
const std::vector<std::string> &workbook::get_shared_strings() const
{
return d_->shared_strings_;
}
void workbook::add_shared_string(const std::string &shared)
{
d_->shared_strings_.push_back(shared);
}
} // namespace xlnt

View File

@ -83,4 +83,10 @@ bool range_reference::operator==(const range_reference &comparand) const
&& comparand.bottom_right_ == bottom_right_;
}
bool range_reference::operator!=(const range_reference &comparand) const
{
return comparand.top_left_ != top_left_
|| comparand.bottom_right_ != bottom_right_;
}
}

View File

@ -73,6 +73,11 @@ std::vector<range_reference> worksheet::get_merged_ranges() const
return d_->merged_cells_;
}
margins &worksheet::get_page_margins()
{
return d_->page_margins_;
}
const margins &worksheet::get_page_margins() const
{
return d_->page_margins_;
@ -103,6 +108,11 @@ void worksheet::unset_auto_filter()
d_->auto_filter_ = range_reference(1, 1, 1, 1);
}
page_setup &worksheet::get_page_setup()
{
return d_->page_setup_;
}
const page_setup &worksheet::get_page_setup() const
{
return d_->page_setup_;

View File

@ -1,16 +0,0 @@
#include <xlnt/cell/cell.hpp>
#include <xlnt/cell/cell_reference.hpp>
#include <xlnt/common/zip_file.hpp>
#include <xlnt/styles/number_format.hpp>
#include <xlnt/workbook/workbook.hpp>
#include <xlnt/worksheet/range_reference.hpp>
#include <xlnt/worksheet/worksheet.hpp>
#include "detail/include_pugixml.hpp"
namespace {
} // namespace
namespace xlnt {
} // namespace xlnt

View File

@ -31,15 +31,27 @@ public:
operator bool() const { return difference == difference_type::equivalent; }
};
static comparison_result compare_xml(const xlnt::xml_document &expected, const xlnt::xml_document &observed)
{
return compare_xml(expected.get_root(), observed.get_root());
}
static comparison_result compare_xml(const std::string &expected, const xlnt::xml_document &observed)
{
std::ifstream f(expected);
std::ostringstream s;
f >> s.rdbuf();
std::string expected_contents = expected;
auto expected_xml = xlnt::xml_serializer::deserialize(s.str());
if(PathHelper::FileExists(expected))
{
std::ifstream f(expected);
std::ostringstream s;
f >> s.rdbuf();
expected_contents = s.str();
}
return compare_xml(expected_xml.root(), observed.root());
auto expected_xml = xlnt::xml_serializer::deserialize(expected_contents);
return compare_xml(expected_xml.get_root(), observed.get_root());
}
static comparison_result compare_xml(const std::string &left_contents, const std::string &right_contents)
@ -47,7 +59,7 @@ public:
auto left_doc = xlnt::xml_serializer::deserialize(left_contents);
auto right_doc = xlnt::xml_serializer::deserialize(right_contents);
return compare_xml(left_doc.root(), right_doc.root());
return compare_xml(left_doc.get_root(), right_doc.get_root());
}
static comparison_result compare_xml(const xlnt::xml_node &left, const xlnt::xml_node &right)
@ -100,13 +112,14 @@ public:
return {difference_type::text_values_differ, "((empty))", right_temp};
}
auto right_child_iter = right.get_children().begin();
auto right_children = right.get_children();
auto right_child_iter = right_children.begin();
for(auto left_child : left.get_children())
{
left_temp = left_child.get_name();
if(right_child_iter == right.get_children().end())
if(right_child_iter == right_children.end())
{
return {difference_type::child_order_differs, left_temp, "((end))"};
}
@ -122,7 +135,7 @@ public:
}
}
if(right_child_iter != right.get_children().end())
if(right_child_iter != right_children.end())
{
right_temp = right_child_iter->get_name();
return {difference_type::child_order_differs, "((end))", right_temp};

View File

@ -83,6 +83,8 @@ public:
prop.last_modified_by = "SOMEBODY";
prop.created = xlnt::datetime(2010, 4, 1, 20, 30, 00);
prop.modified = xlnt::datetime(2010, 4, 5, 14, 5, 30);
TS_FAIL("");
return;
xlnt::workbook_serializer serializer(wb);
xlnt::xml_document xml = serializer.write_properties_core();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/core.xml", xml));
@ -95,6 +97,8 @@ public:
wb.create_sheet();
xlnt::workbook_serializer serializer(wb);
xlnt::xml_document xml = serializer.write_properties_app();
TS_FAIL("");
return;
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/app.xml", xml));
}
};

View File

@ -7,6 +7,7 @@
#include <xlnt/s11n/excel_serializer.hpp>
#include <xlnt/s11n/manifest_serializer.hpp>
#include <xlnt/s11n/relationship_serializer.hpp>
#include <xlnt/s11n/workbook_serializer.hpp>
#include <xlnt/s11n/xml_serializer.hpp>
#include <xlnt/workbook/manifest.hpp>
@ -331,11 +332,15 @@ public:
{
auto path = PathHelper::GetDataDirectory("/reader/bug137.xlsx");
xlnt::zip_file archive(path);
std::vector<std::pair<std::string, std::string>> expected =
{
{"xl/worksheets/sheet1.xml", "Sheet1"}
};
TS_ASSERT_EQUALS(xlnt::detect_worksheets(archive), expected);
xlnt::workbook wb;
xlnt::workbook_serializer serializer(wb);
TS_ASSERT_EQUALS(serializer.detect_worksheets(), expected);
}
{
@ -348,7 +353,9 @@ public:
{"xl/worksheets/sheet2.xml", "moredata"}
};
TS_ASSERT_EQUALS(xlnt::detect_worksheets(archive), expected);
xlnt::workbook wb;
xlnt::workbook_serializer serializer(wb);
TS_ASSERT_EQUALS(serializer.detect_worksheets(), expected);
}
{
@ -362,7 +369,9 @@ public:
{"xl/worksheets/sheet.xml", "Sheet3"}
};
TS_ASSERT_EQUALS(xlnt::detect_worksheets(archive), expected);
xlnt::workbook wb;
xlnt::workbook_serializer serializer(wb);
TS_ASSERT_EQUALS(serializer.detect_worksheets(), expected);
}
}
@ -381,7 +390,7 @@ public:
auto path = PathHelper::GetDataDirectory("/reader/bug137.xlsx");
xlnt::zip_file archive(path);
TS_ASSERT_EQUALS(xlnt::read_relationships(archive, "xl/workbook.xml"), expected);
TS_ASSERT_EQUALS(xlnt::relationship_serializer::read_relationships(archive, "xl/workbook.xml"), expected);
}
{
@ -400,7 +409,7 @@ public:
auto path = PathHelper::GetDataDirectory("/reader/bug304.xlsx");
xlnt::zip_file archive(path);
TS_ASSERT_EQUALS(xlnt::read_relationships(archive, "xl/workbook.xml"), expected);
TS_ASSERT_EQUALS(xlnt::relationship_serializer::read_relationships(archive, "xl/workbook.xml"), expected);
}
}

View File

@ -13,14 +13,15 @@ public:
xlnt::workbook wb;
wb.add_number_format(xlnt::number_format("YYYY"));
xlnt::style_serializer writer(wb);
auto xml = writer.write_number_formats();
xlnt::xml_document observed;
writer.write_number_formats(observed.add_child("numFmts"));
std::string expected =
"<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"
" <numFmts count=\"1\">"
" <numFmt formatCode=\"YYYY\" numFmtId=\"164\"></numFmt>"
" </numFmts>"
"</styleSheet>";
auto diff = Helper::compare_xml(xml, expected);
auto diff = Helper::compare_xml(expected, observed);
TS_ASSERT(diff);
}
/*

View File

@ -14,9 +14,9 @@ class test_theme : public CxxTest::TestSuite
public:
void test_write_theme()
{
xlnt::theme_serializer serializer;
xlnt::workbook wb;
auto content = serializer.write_theme(wb.get_loaded_theme());
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/theme1.xml", content));
xlnt::theme_serializer serializer;
auto xml = serializer.write_theme(wb.get_loaded_theme());
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/theme1.xml", xml));
}
};

View File

@ -3,6 +3,7 @@
#include <iostream>
#include <cxxtest/TestSuite.h>
#include <xlnt/s11n/worksheet_serializer.hpp>
#include <xlnt/worksheet/worksheet.hpp>
class test_worksheet : public CxxTest::TestSuite
@ -639,10 +640,8 @@ public:
{
xlnt::worksheet ws(wb_);
auto xml_string = xlnt::write_worksheet(ws, {});
pugi::xml_document doc;
doc.load(xml_string.c_str());
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
auto expected_string =
"<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
@ -660,10 +659,10 @@ public:
" <pageMargins left=\"0.75\" right=\"0.75\" top=\"1\" bottom=\"1\" header=\"0.5\" footer=\"0.5\"/>"
"</worksheet>";
pugi::xml_document expected_doc;
expected_doc.load(expected_string);
xlnt::xml_document expected;
expected.from_string(expected_string);
TS_ASSERT(Helper::compare_xml(expected_doc, doc));
TS_ASSERT(Helper::compare_xml(expected, observed));
}
void test_page_margins()
@ -677,10 +676,8 @@ public:
ws.get_page_margins().set_header(1.5);
ws.get_page_margins().set_footer(1.5);
auto xml_string = xlnt::write_worksheet(ws, {});
pugi::xml_document doc;
doc.load(xml_string.c_str());
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
auto expected_string =
"<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
@ -698,10 +695,10 @@ public:
" <pageMargins left=\"2\" right=\"2\" top=\"2\" bottom=\"2\" header=\"1.5\" footer=\"1.5\"/>"
"</worksheet>";
pugi::xml_document expected_doc;
expected_doc.load(expected_string);
TS_ASSERT(Helper::compare_xml(expected_doc, doc));
xlnt::xml_document expected;
expected.from_string(expected_string);
TS_ASSERT(Helper::compare_xml(expected, observed));
}
void test_merge()
@ -737,18 +734,17 @@ public:
ws.get_cell("A1").set_value("Cell A1");
ws.get_cell("B1").set_value("Cell B1");
auto xml_string = xlnt::write_worksheet(ws, string_table);
{
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
pugi::xml_document doc;
doc.load(xml_string.c_str());
pugi::xml_document expected_doc;
expected_doc.load(expected_string1);
TS_ASSERT(Helper::compare_xml(expected_doc, doc));
xlnt::xml_document expected;
expected.from_string(expected_string1);
TS_ASSERT(Helper::compare_xml(expected, observed));
}
ws.merge_cells("A1:B1");
xml_string = xlnt::write_worksheet(ws, string_table);
auto expected_string2 =
"<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
@ -776,13 +772,17 @@ public:
" <pageMargins left=\"0.75\" right=\"0.75\" top=\"1\" bottom=\"1\" header=\"0.5\" footer=\"0.5\"/>"
"</worksheet>";
doc.load(xml_string.c_str());
expected_doc.load(expected_string2);
TS_ASSERT(Helper::compare_xml(expected_doc, doc));
{
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
xlnt::xml_document expected;
expected.from_string(expected_string2);
TS_ASSERT(Helper::compare_xml(expected, observed));
}
ws.unmerge_cells("A1:B1");
xml_string = xlnt::write_worksheet(ws, string_table);
auto expected_string3 =
"<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
@ -807,10 +807,15 @@ public:
" <pageMargins left=\"0.75\" right=\"0.75\" top=\"1\" bottom=\"1\" header=\"0.5\" footer=\"0.5\"/>"
"</worksheet>";
doc.load(xml_string.c_str());
expected_doc.load(expected_string3);
TS_ASSERT(Helper::compare_xml(expected_doc, doc));
{
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
xlnt::xml_document expected;
expected.from_string(expected_string3);
TS_ASSERT(Helper::compare_xml(expected, observed));
}
}
void test_printer_settings()
@ -825,11 +830,9 @@ public:
ws.get_page_setup().set_horizontal_centered(true);
ws.get_page_setup().set_vertical_centered(true);
auto xml_string = xlnt::write_worksheet(ws, {});
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
pugi::xml_document doc;
doc.load(xml_string.c_str());
auto expected_string =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
@ -850,10 +853,10 @@ public:
" <pageSetup orientation=\"landscape\" paperSize=\"3\" fitToHeight=\"0\" fitToWidth=\"1\" />"
"</worksheet>";
pugi::xml_document expected_doc;
expected_doc.load(expected_string);
xlnt::xml_document expected;
expected.from_string(expected_string);
TS_ASSERT(Helper::compare_xml(expected_doc, doc));
TS_ASSERT(Helper::compare_xml(expected, observed));
}
void test_header_footer()
@ -901,13 +904,15 @@ public:
" </headerFooter>"
"</worksheet>";
pugi::xml_document expected_doc;
pugi::xml_document observed_doc;
xlnt::xml_document expected;
expected.from_string(expected_xml_string);
expected_doc.load(expected_xml_string.c_str());
observed_doc.load(xlnt::write_worksheet(ws, {}).c_str());
TS_ASSERT(Helper::compare_xml(expected_doc, observed_doc));
{
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(expected, observed));
}
ws = wb_.create_sheet();
@ -927,10 +932,12 @@ public:
" <pageMargins left=\"0.75\" right=\"0.75\" top=\"1\" bottom=\"1\" header=\"0.5\" footer=\"0.5\"/>"
"</worksheet>";
expected_doc.load(expected_xml_string.c_str());
observed_doc.load(xlnt::write_worksheet(ws, {}).c_str());
TS_ASSERT(Helper::compare_xml(expected_doc, observed_doc));
{
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(expected, observed));
}
}
void test_page_setup()

View File

@ -3,7 +3,12 @@
#include <iostream>
#include <cxxtest/TestSuite.h>
#include <xlnt/xlnt.hpp>
#include <xlnt/s11n/relationship_serializer.hpp>
#include <xlnt/s11n/shared_strings_serializer.hpp>
#include <xlnt/s11n/workbook_serializer.hpp>
#include <xlnt/s11n/worksheet_serializer.hpp>
#include <xlnt/workbook/workbook.hpp>
#include "helpers/temporary_file.hpp"
#include "helpers/path_helper.hpp"
#include "helpers/helper.hpp"
@ -41,32 +46,45 @@ public:
void test_write_workbook_rels()
{
xlnt::workbook wb;
auto content = xlnt::write_workbook_rels(wb);
xlnt::zip_file archive;
xlnt::relationship_serializer::write_relationships(wb.get_relationships(), "xl/workbook.xml", archive);
auto content = xlnt::xml_serializer::deserialize(archive.read("xl/_rels/workbook.xml.rels"));
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook.xml.rels", content));
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/workbook.xml.rels", content));
}
void test_write_workbook()
{
xlnt::workbook wb;
auto content = xlnt::write_workbook(wb);
xlnt::workbook_serializer serializer(wb);
auto content = serializer.write_workbook();
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook.xml", content));
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/workbook.xml", content));
}
void test_write_string_table()
{
std::vector<std::string> table = {"hello", "world", "nice"};
auto content = xlnt::write_shared_strings(table);
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sharedStrings.xml", content));
xlnt::workbook wb;
auto ws = wb.get_active_sheet();
ws.get_cell("A1").set_value("hello");
ws.get_cell("A2").set_value("world");
ws.get_cell("A3").set_value("nice");
auto content = xlnt::shared_strings_serializer::write_shared_strings(wb.get_shared_strings());
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sharedStrings.xml", content));
}
void test_write_worksheet()
{
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value("hello");
auto content = xlnt::write_worksheet(ws, {"hello"});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1.xml", observed));
}
void test_write_hidden_worksheet()
@ -74,8 +92,11 @@ public:
auto ws = wb_.create_sheet();
ws.get_page_setup().set_sheet_state(xlnt::page_setup::sheet_state::hidden);
ws.get_cell("F42").set_value("hello");
auto content = xlnt::write_worksheet(ws, {"hello"});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1.xml", observed));
}
void test_write_bool()
@ -83,8 +104,11 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value(false);
ws.get_cell("F43").set_value(true);
auto content = xlnt::write_worksheet(ws, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_bool.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_bool.xml", observed));
}
void test_write_formula()
@ -93,8 +117,11 @@ public:
ws.get_cell("F1").set_value(10);
ws.get_cell("F2").set_value(32);
ws.get_cell("F3").set_formula("F1+F2");
auto content = xlnt::write_worksheet(ws, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_formula.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_formula.xml", observed));
}
void test_write_height()
@ -102,8 +129,11 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F1").set_value(10);
ws.get_row_properties(ws.get_cell("F1").get_row()).height = 30;
auto content = xlnt::write_worksheet(ws, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_height.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_height.xml", observed));
}
void test_write_hyperlink()
@ -111,8 +141,11 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("A1").set_value("test");
ws.get_cell("A1").set_hyperlink("http://test.com");
auto content = xlnt::write_worksheet(ws, {"test"});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_hyperlink.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_hyperlink.xml", observed));
}
void test_write_hyperlink_rels()
@ -125,8 +158,12 @@ public:
ws.get_cell("A2").set_value("test");
ws.get_cell("A2").set_hyperlink("http://test2.com/");
TS_ASSERT_EQUALS(2, ws.get_relationships().size());
auto content = xlnt::write_worksheet_rels(ws);
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_hyperlink.xml.rels", content));
xlnt::zip_file archive;
xlnt::relationship_serializer::write_relationships(ws.get_relationships(), "xl/worksheets/sheet1.xml", archive);
auto content = xlnt::xml_serializer::deserialize(archive.read("xl/worksheets/_rels/sheet1.xml.rels"));
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_hyperlink.xml.rels", content));
}
void _test_write_hyperlink_image_rels()
@ -149,11 +186,16 @@ public:
auto ws = wb.get_sheet_by_index(0);
ws.get_cell("F42").set_value("hello");
ws.auto_filter("A1:F1");
auto content = xlnt::write_worksheet(ws, {"hello"});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_auto_filter.xml", content));
content = xlnt::write_workbook(wb);
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook_auto_filter.xml", content));
xlnt::worksheet_serializer ws_serializer(ws);
auto observed = ws_serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_auto_filter.xml", observed));
xlnt::workbook_serializer wb_serializer(wb);
auto observed2 = wb_serializer.write_workbook();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/workbook_auto_filter.xml", observed2));
}
void test_write_auto_filter_filter_column()
@ -171,8 +213,11 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value("hello");
ws.freeze_panes("A4");
auto content = xlnt::write_worksheet(ws, {"hello"});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_horiz.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_horiz.xml", observed));
}
void test_freeze_panes_vert()
@ -180,8 +225,11 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value("hello");
ws.freeze_panes("D1");
auto content = xlnt::write_worksheet(ws, {"hello"});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_vert.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_vert.xml", observed));
}
void test_freeze_panes_both()
@ -189,24 +237,33 @@ public:
auto ws = wb_.create_sheet();
ws.get_cell("F42").set_value("hello");
ws.freeze_panes("D4");
auto content = xlnt::write_worksheet(ws, {"hello"});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_both.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_freeze_panes_both.xml", observed));
}
void test_long_number()
{
auto ws = wb_.create_sheet();
ws.get_cell("A1").set_value(9781231231230LL);
auto content = xlnt::write_worksheet(ws, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/long_number.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/long_number.xml", observed));
}
void test_short_number()
{
auto ws = wb_.create_sheet();
ws.get_cell("A1").set_value(1234567890);
auto content = xlnt::write_worksheet(ws, {});
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/short_number.xml", content));
xlnt::worksheet_serializer serializer(ws);
auto observed = serializer.write_worksheet();
TS_ASSERT(Helper::compare_xml(PathHelper::GetDataDirectory() + "/writer/expected/short_number.xml", observed));
}
void _test_write_images()

View File

@ -4,8 +4,7 @@
#include <cxxtest/TestSuite.h>
#include <xlnt/common/exceptions.hpp>
#include <xlnt/reader/workbook_reader.hpp>
#include <xlnt/writer/workbook_writer.hpp>
#include <xlnt/s11n/workbook_serializer.hpp>
#include "helpers/path_helper.hpp"
@ -19,8 +18,10 @@ public:
ws.get_cell("F42").set_value("hello");
ws.get_auto_filter() = "A1:F1";
auto content = xlnt::write_workbook(wb);
auto diff = Helper::compare_xml(PathHelper::read_file("workbook_auto_filter.xml"), content);
xlnt::workbook_serializer serializer(wb);
auto observed = serializer.write_workbook();
auto diff = Helper::compare_xml(PathHelper::read_file("workbook_auto_filter.xml"), observed);
TS_ASSERT(!diff);
}
@ -30,8 +31,11 @@ public:
auto ws = wb.create_sheet();
ws.set_sheet_state(xlnt::page_setup::sheet_state::hidden);
wb.create_sheet();
auto xml = xlnt::write_workbook(wb);
std::string expected =
xlnt::workbook_serializer serializer(wb);
auto observed = serializer.write_workbook();
std::string expected_string =
"<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
" <workbookPr/>"
" <bookViews>"
@ -44,7 +48,11 @@ public:
" <definedNames/>"
" <calcPr calcId=\"124519\" fullCalcOnLoad=\"1\"/>"
"</workbook>";
auto diff = Helper::compare_xml(xml, expected);
xlnt::xml_document expected;
expected.from_string(expected_string);
auto diff = Helper::compare_xml(expected, observed);
TS_ASSERT(!diff);
}
@ -53,40 +61,56 @@ public:
xlnt::workbook wb;
auto ws = wb.get_active_sheet();
ws.set_sheet_state(xlnt::page_setup::sheet_state::hidden);
TS_ASSERT_THROWS(xlnt::write_workbook(wb), xlnt::value_error);
xlnt::workbook_serializer serializer(wb);
TS_ASSERT_THROWS(serializer.write_workbook(), xlnt::value_error);
}
void test_write_empty_workbook()
{
xlnt::workbook wb;
TemporaryFile file;
xlnt::save_workbook(wb, file.GetFilename());
xlnt::excel_serializer serializer(wb);
serializer.save_workbook(file.GetFilename());
TS_ASSERT(PathHelper::FileExists(file.GetFilename()));
}
void test_write_virtual_workbook()
{
xlnt::workbook old_wb;
auto saved_wb = xlnt::save_virtual_workbook(old_wb);
auto new_wb = xlnt::excel_reader::load_workbook(saved_wb);
xlnt::workbook old_wb, new_wb;
xlnt::excel_serializer serializer(old_wb);
std::vector<std::uint8_t> wb_bytes;
serializer.save_virtual_workbook(wb_bytes);
xlnt::excel_serializer deserializer(new_wb);
deserializer.load_virtual_workbook(wb_bytes);
TS_ASSERT(new_wb != nullptr);
}
void test_write_workbook_rels()
{
xlnt::workbook wb;
auto content = xlnt::write_workbook_rels(wb);
xlnt::zip_file archive;
xlnt::relationship_serializer::write_relationships(wb.get_relationships(), "xl/workbook.xml", archive);
xlnt::xml_document observed;
observed.from_string(archive.read("xl/workbook/_rels/workbook.xml.rels"));
auto filename = "workbook.xml.rels";
auto diff = Helper::compare_xml(PathHelper::read_file(filename), content);
auto diff = Helper::compare_xml(PathHelper::read_file(filename), observed);
TS_ASSERT(!diff);
}
void test_write_workbook_()
{
xlnt::workbook wb;
auto content = xlnt::write_workbook(wb);
xlnt::workbook_serializer serializer(wb);
auto observed = serializer.write_workbook();
auto filename = PathHelper::GetDataDirectory("/workbook.xml");
auto diff = Helper::compare_xml(PathHelper::read_file(filename), content);
auto diff = Helper::compare_xml(PathHelper::read_file(filename), observed);
TS_ASSERT(!diff);
}
@ -95,12 +119,15 @@ public:
xlnt::workbook wb;
auto ws = wb.create_sheet();
wb.create_named_range("test_range", ws, "A1:B5");
auto xml = xlnt::write_defined_names(wb);
xlnt::workbook_serializer serializer(wb);
auto observed_node = serializer.write_named_ranges();
xlnt::xml_document observed;
observed.add_child(observed_node);
std::string expected =
"<root>"
"<s:definedName xmlns:s=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" name=\"test_range\">'Sheet'!$A$1:$B$5</s:definedName>"
"</root>";
auto diff = Helper::compare_xml(xml, expected);
auto diff = Helper::compare_xml(expected, observed);
TS_ASSERT(!diff);
}
@ -115,7 +142,9 @@ public:
xlnt::workbook wb;
wb.set_code_name("MyWB");
auto content = xlnt::write_workbook(wb);
xlnt::workbook_serializer serializer(wb);
auto observed = serializer.write_workbook();
std::string expected =
"<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
" <workbookPr codeName=\"MyWB\"/>"
@ -128,21 +157,26 @@ public:
" <definedNames/>"
" <calcPr calcId=\"124519\" fullCalcOnLoad=\"1\"/>"
"</workbook>";
auto diff = Helper::compare_xml(content, expected);
auto diff = Helper::compare_xml(expected, observed);
TS_ASSERT(!diff);
}
void test_write_root_rels()
{
xlnt::workbook wb;
auto xml = xlnt::write_root_rels(wb);
xlnt::zip_file archive;
xlnt::relationship_serializer::write_relationships(wb.get_root_relationships(), "", archive);
xlnt::xml_document observed;
observed.from_string(archive.read("_rels/.rels"));
std::string expected =
"<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">"
" <Relationship Id=\"rId1\" Target=\"xl/workbook.xml\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\"/>"
" <Relationship Id=\"rId2\" Target=\"docProps/core.xml\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\"/>"
" <Relationship Id=\"rId3\" Target=\"docProps/app.xml\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\"/>"
"</Relationships>";
auto diff = Helper::compare_xml(xml, expected);
auto diff = Helper::compare_xml(expected, observed);
TS_ASSERT(!diff);
}