mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
begin refactoring writing code
This commit is contained in:
parent
7316e2184c
commit
6b3781d03b
|
@ -119,4 +119,12 @@ public:
|
|||
attribute_error();
|
||||
};
|
||||
|
||||
class value_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
value_error() : std::runtime_error("")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
18
include/xlnt/workbook/named_range.hpp
Normal file
18
include/xlnt/workbook/named_range.hpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class worksheet;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> split_named_range(const std::string &named_range_string);
|
||||
|
||||
class named_range
|
||||
{
|
||||
public:
|
||||
named_range(const std::string &name, const std::vector<std::pair<worksheet, std::string>> &targets);
|
||||
};
|
||||
|
||||
}
|
|
@ -46,6 +46,7 @@ class pattern_fill;
|
|||
class font;
|
||||
class protection;
|
||||
class color;
|
||||
class named_range;
|
||||
|
||||
enum class encoding;
|
||||
|
||||
|
@ -174,8 +175,19 @@ public:
|
|||
bool load(const std::istream &stream);
|
||||
|
||||
bool operator==(const workbook &rhs) const;
|
||||
|
||||
bool operator!=(const workbook &rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
bool operator==(std::nullptr_t) const;
|
||||
|
||||
bool operator!=(std::nullptr_t) const
|
||||
{
|
||||
return !(*this == std::nullptr_t{});
|
||||
}
|
||||
|
||||
std::vector<content_type> get_content_types() const;
|
||||
|
||||
void create_relationship(const std::string &id, const std::string &target, relationship::type type);
|
||||
|
@ -190,6 +202,13 @@ public:
|
|||
void add_color(color c);
|
||||
void add_number_format(const std::string &format);
|
||||
|
||||
void set_code_name(const std::string &code_name);
|
||||
|
||||
void add_named_range(const named_range &n);
|
||||
|
||||
bool has_loaded_theme();
|
||||
std::string get_loaded_theme();
|
||||
|
||||
private:
|
||||
static std::size_t index_from_ws_filename(const std::string &ws_filename);
|
||||
|
||||
|
|
|
@ -64,12 +64,12 @@ struct page_setup
|
|||
|
||||
public:
|
||||
page_setup() : default_(true), break_(page_break::none), sheet_state_(sheet_state::visible), paper_size_(paper_size::letter),
|
||||
orientation_(orientation::portrait), fit_to_page_(false), fit_to_height_(false), fit_to_width_(false) {}
|
||||
orientation_(orientation::portrait), fit_to_page_(false), fit_to_height_(false), fit_to_width_(false), horizontal_centered_(false), vertical_centered_(false), scale_(1) {}
|
||||
bool is_default() const { return default_; }
|
||||
page_break get_break() const { return break_; }
|
||||
void set_break(page_break b) { default_ = false; break_ = b; }
|
||||
sheet_state get_sheet_state() const { return sheet_state_; }
|
||||
void set_sheet_state(sheet_state sheet_state) { default_ = false; sheet_state_ = sheet_state; }
|
||||
void set_sheet_state(sheet_state sheet_state) { sheet_state_ = sheet_state; }
|
||||
paper_size get_paper_size() const { return paper_size_; }
|
||||
void set_paper_size(paper_size paper_size) { default_ = false; paper_size_ = paper_size; }
|
||||
orientation get_orientation() const { return orientation_; }
|
||||
|
@ -80,6 +80,12 @@ public:
|
|||
void set_fit_to_height(bool fit_to_height) { default_ = false; fit_to_height_ = fit_to_height; }
|
||||
bool fit_to_width() const { return fit_to_width_; }
|
||||
void set_fit_to_width(bool fit_to_width) { default_ = false; fit_to_width_ = fit_to_width; }
|
||||
void set_horizontal_centered(bool horizontal_centered) { default_ = false; horizontal_centered_ = horizontal_centered; }
|
||||
bool get_horizontal_centered() const { return horizontal_centered_; }
|
||||
void set_vertical_centered(bool vertical_centered) { default_ = false; vertical_centered_ = vertical_centered; }
|
||||
bool get_vertical_centered() const { return vertical_centered_; }
|
||||
void set_scale(double scale) { default_ = false; scale_ = scale; }
|
||||
double get_scale() const { return scale_; }
|
||||
|
||||
private:
|
||||
bool default_;
|
||||
|
@ -90,6 +96,9 @@ private:
|
|||
bool fit_to_page_;
|
||||
bool fit_to_height_;
|
||||
bool fit_to_width_;
|
||||
bool horizontal_centered_;
|
||||
bool vertical_centered_;
|
||||
double scale_;
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "page_setup.hpp"
|
||||
#include "../common/types.hpp"
|
||||
#include "../common/relationship.hpp"
|
||||
|
||||
|
@ -116,82 +117,6 @@ private:
|
|||
footer left_footer_, right_footer_, center_footer_;
|
||||
};
|
||||
|
||||
struct page_setup
|
||||
{
|
||||
enum class page_break
|
||||
{
|
||||
none = 0,
|
||||
row = 1,
|
||||
column = 2
|
||||
};
|
||||
|
||||
enum class sheet_state
|
||||
{
|
||||
visible,
|
||||
hidden,
|
||||
very_hidden
|
||||
};
|
||||
|
||||
enum class paper_size
|
||||
{
|
||||
letter = 1,
|
||||
letter_small = 2,
|
||||
tabloid = 3,
|
||||
ledger = 4,
|
||||
legal = 5,
|
||||
statement = 6,
|
||||
executive = 7,
|
||||
a3 = 8,
|
||||
a4 = 9,
|
||||
a4_small = 10,
|
||||
a5 = 11
|
||||
};
|
||||
|
||||
enum class orientation
|
||||
{
|
||||
portrait,
|
||||
landscape
|
||||
};
|
||||
|
||||
public:
|
||||
page_setup() : default_(true), break_(page_break::none), sheet_state_(sheet_state::visible), paper_size_(paper_size::letter),
|
||||
orientation_(orientation::portrait), fit_to_page_(false), fit_to_height_(false), fit_to_width_(false), horizontal_centered_(false), vertical_centered_(false), scale_(1) {}
|
||||
bool is_default() const { return default_; }
|
||||
page_break get_break() const { return break_; }
|
||||
void set_break(page_break b) { default_ = false; break_ = b; }
|
||||
sheet_state get_sheet_state() const { return sheet_state_; }
|
||||
void set_sheet_state(sheet_state sheet_state) { sheet_state_ = sheet_state; }
|
||||
paper_size get_paper_size() const { return paper_size_; }
|
||||
void set_paper_size(paper_size paper_size) { default_ = false; paper_size_ = paper_size; }
|
||||
orientation get_orientation() const { return orientation_; }
|
||||
void set_orientation(orientation orientation) { default_ = false; orientation_ = orientation; }
|
||||
bool fit_to_page() const { return fit_to_page_; }
|
||||
void set_fit_to_page(bool fit_to_page) { default_ = false; fit_to_page_ = fit_to_page; }
|
||||
bool fit_to_height() const { return fit_to_height_; }
|
||||
void set_fit_to_height(bool fit_to_height) { default_ = false; fit_to_height_ = fit_to_height; }
|
||||
bool fit_to_width() const { return fit_to_width_; }
|
||||
void set_fit_to_width(bool fit_to_width) { default_ = false; fit_to_width_ = fit_to_width; }
|
||||
void set_horizontal_centered(bool horizontal_centered) { default_ = false; horizontal_centered_ = horizontal_centered; }
|
||||
bool get_horizontal_centered() const { return horizontal_centered_; }
|
||||
void set_vertical_centered(bool vertical_centered) { default_ = false; vertical_centered_ = vertical_centered; }
|
||||
bool get_vertical_centered() const { return vertical_centered_; }
|
||||
void set_scale(double scale) { default_ = false; scale_ = scale; }
|
||||
double get_scale() const { return scale_; }
|
||||
|
||||
private:
|
||||
bool default_;
|
||||
page_break break_;
|
||||
sheet_state sheet_state_;
|
||||
paper_size paper_size_;
|
||||
orientation orientation_;
|
||||
bool fit_to_page_;
|
||||
bool fit_to_height_;
|
||||
bool fit_to_width_;
|
||||
bool horizontal_centered_;
|
||||
bool vertical_centered_;
|
||||
double scale_;
|
||||
};
|
||||
|
||||
struct margins
|
||||
{
|
||||
public:
|
||||
|
@ -348,6 +273,8 @@ public:
|
|||
|
||||
std::vector<std::string> get_formula_attributes() const;
|
||||
|
||||
void set_sheet_state(page_setup::sheet_state state);
|
||||
|
||||
private:
|
||||
friend class workbook;
|
||||
friend class cell;
|
||||
|
|
11
include/xlnt/writer/manifest_writer.hpp
Normal file
11
include/xlnt/writer/manifest_writer.hpp
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class workbook;
|
||||
|
||||
std::string write_content_types(const workbook &wb, bool as_template);
|
||||
|
||||
};
|
12
include/xlnt/writer/relationship_writer.hpp
Normal file
12
include/xlnt/writer/relationship_writer.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class relationship;
|
||||
|
||||
std::string write_relationships(const std::vector<relationship> &relationships, const std::string &dir);
|
||||
|
||||
} // namespace xlnt
|
|
@ -23,11 +23,11 @@
|
|||
// @author: see AUTHORS file
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class theme_writer
|
||||
{
|
||||
|
||||
};
|
||||
std::string write_theme();
|
||||
//void write_theme(const theme &t);
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -23,11 +23,40 @@
|
|||
// @author: see AUTHORS file
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <xlnt/writer/style_writer.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class workbook_writer
|
||||
{
|
||||
class workbook;
|
||||
class zip_file;
|
||||
|
||||
class excel_writer
|
||||
{
|
||||
public:
|
||||
excel_writer(workbook &wb);
|
||||
|
||||
void save(const std::string &filename, bool as_template);
|
||||
void write_data(zip_file &archive, bool as_template);
|
||||
void write_string_table(zip_file &archive);
|
||||
void write_images(zip_file &archive);
|
||||
void write_charts(zip_file &archive);
|
||||
void write_chartsheets(zip_file &archive);
|
||||
void write_worksheets(zip_file &archive);
|
||||
void write_external_links(zip_file &archive);
|
||||
|
||||
private:
|
||||
workbook wb_;
|
||||
style_writer style_writer_;
|
||||
};
|
||||
|
||||
std::string write_properties_app(const workbook &wb);
|
||||
std::string write_root_rels(const workbook &wb);
|
||||
std::string write_workbook(const workbook &wb);
|
||||
std::string write_workbook_rels(const workbook &wb);
|
||||
bool save_workbook(workbook &wb, const std::string &filename, bool as_template = false);
|
||||
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template = false);
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -1,33 +1,2 @@
|
|||
// Copyright (c) 2015 Thomas Fussell
|
||||
// Copyright (c) 2010-2015 openpyxl
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE
|
||||
//
|
||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||
// @author: see AUTHORS file
|
||||
#pragma once
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
class worksheet_writer
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -42,10 +42,6 @@ public:
|
|||
|
||||
static std::string write_properties_core(const document_properties &prop);
|
||||
|
||||
static std::string write_properties_app(const workbook &wb);
|
||||
|
||||
static std::string write_workbook(const workbook &wb);
|
||||
|
||||
static std::string write_theme();
|
||||
|
||||
static std::string write_shared_strings(const std::vector<std::string> &string_table);
|
||||
|
@ -54,14 +50,7 @@ public:
|
|||
const std::vector<std::string> &string_table = {},
|
||||
const std::unordered_map<std::size_t, std::string> &style_table = {});
|
||||
|
||||
static std::string write_root_rels();
|
||||
|
||||
static std::string write_workbook_rels(const workbook &wb);
|
||||
|
||||
static std::string write_worksheet_rels(worksheet ws);
|
||||
|
||||
private:
|
||||
static std::string write_relationships(const std::vector<relationship> &relationships, const std::string &dir = "");
|
||||
};
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -50,3 +50,4 @@ const std::string download_url = "https://github.com/tfussell/xlnt/archive/maste
|
|||
#include "workbook/document_properties.hpp"
|
||||
#include "cell/comment.hpp"
|
||||
#include "common/encoding.hpp"
|
||||
#include "workbook/named_range.hpp"
|
||||
|
|
|
@ -102,13 +102,27 @@ std::pair<std::string, row_t> cell_reference::split_reference(const std::string
|
|||
throw cell_coordinates_exception(reference_string);
|
||||
}
|
||||
}
|
||||
else if(character == '$')
|
||||
{
|
||||
if(column_part)
|
||||
{
|
||||
if(column_string.empty())
|
||||
{
|
||||
column_string.append(1, upper);
|
||||
}
|
||||
else
|
||||
{
|
||||
column_part = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(column_part)
|
||||
{
|
||||
column_part = false;
|
||||
}
|
||||
else if(!(std::isdigit(character, std::locale::classic()) || character == '$'))
|
||||
else if(!std::isdigit(character, std::locale::classic()))
|
||||
{
|
||||
throw cell_coordinates_exception(reference_string);
|
||||
}
|
||||
|
|
10
source/manifest_writer.cpp
Normal file
10
source/manifest_writer.cpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include <xlnt/writer/manifest_writer.hpp>
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
std::string write_content_types(const workbook &wb, bool as_template)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
73
source/named_range.cpp
Normal file
73
source/named_range.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
|
||||
#include <xlnt/workbook/named_range.hpp>
|
||||
#include <xlnt/common/exceptions.hpp>
|
||||
#include <xlnt/worksheet/range_reference.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
/// <summary>
|
||||
/// Return a vector containing string split at each delim.
|
||||
/// </summary>
|
||||
/// <remark>
|
||||
/// This should maybe be in a utility header so it can be used elsewhere.
|
||||
/// </remarks>
|
||||
std::vector<std::string> split_string(const std::string &string, char delim)
|
||||
{
|
||||
std::vector<std::string> split;
|
||||
std::string::size_type previous_index = 0;
|
||||
auto separator_index = string.find(delim);
|
||||
|
||||
while(separator_index != std::string::npos)
|
||||
{
|
||||
auto part = string.substr(previous_index, separator_index - previous_index);
|
||||
split.push_back(part);
|
||||
|
||||
previous_index = separator_index + 1;
|
||||
separator_index = string.find(delim, previous_index);
|
||||
}
|
||||
|
||||
split.push_back(string.substr(previous_index));
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> split_named_range(const std::string &named_range_string)
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> final;
|
||||
|
||||
for(auto part : split_string(named_range_string, ','))
|
||||
{
|
||||
auto split = split_string(part, '!');
|
||||
|
||||
if(split[0].front() == '\'' && split[0].back() == '\'')
|
||||
{
|
||||
split[0] = split[0].substr(1, split[0].length() - 2);
|
||||
}
|
||||
|
||||
// Try to parse it. Use empty string if it's not a valid range.
|
||||
try
|
||||
{
|
||||
xlnt::range_reference ref(split[1]);
|
||||
}
|
||||
catch(xlnt::cell_coordinates_exception)
|
||||
{
|
||||
split[1] = "";
|
||||
}
|
||||
|
||||
final.push_back({split[0], split[1]});
|
||||
}
|
||||
|
||||
return final;
|
||||
}
|
||||
|
||||
named_range::named_range(const std::string &name, const std::vector<std::pair<worksheet, std::string>> &targets)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
45
source/relationship_writer.cpp
Normal file
45
source/relationship_writer.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include <sstream>
|
||||
|
||||
#include <xlnt/common/relationship.hpp>
|
||||
#include <xlnt/writer/relationship_writer.hpp>
|
||||
|
||||
#include "constants.hpp"
|
||||
#include "detail/include_pugixml.hpp"
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
std::string write_relationships(const std::vector<relationship> &relationships, const std::string &dir)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
|
||||
auto root_node = doc.append_child("Relationships");
|
||||
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("relationships").c_str());
|
||||
|
||||
for(auto relationship : relationships)
|
||||
{
|
||||
auto target = relationship.get_target_uri();
|
||||
|
||||
if (dir != "" && target.substr(0, dir.size()) == dir)
|
||||
{
|
||||
target = target.substr(dir.size());
|
||||
}
|
||||
|
||||
auto app_props_node = root_node.append_child("Relationship");
|
||||
|
||||
app_props_node.append_attribute("Id").set_value(relationship.get_id().c_str());
|
||||
app_props_node.append_attribute("Target").set_value(target.c_str());
|
||||
app_props_node.append_attribute("Type").set_value(relationship.get_type_string().c_str());
|
||||
|
||||
if(relationship.get_target_mode() == target_mode::external)
|
||||
{
|
||||
app_props_node.append_attribute("TargetMode").set_value("External");
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}
|
|
@ -8,17 +8,18 @@
|
|||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/common/exceptions.hpp>
|
||||
#include <xlnt/drawing/drawing.hpp>
|
||||
#include <xlnt/worksheet/range.hpp>
|
||||
#include <xlnt/reader/reader.hpp>
|
||||
#include <xlnt/common/relationship.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
#include <xlnt/writer/writer.hpp>
|
||||
#include <xlnt/common/zip_file.hpp>
|
||||
#include <xlnt/drawing/drawing.hpp>
|
||||
#include <xlnt/reader/reader.hpp>
|
||||
#include <xlnt/workbook/document_properties.hpp>
|
||||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/worksheet/range.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
#include <xlnt/writer/style_writer.hpp>
|
||||
#include <xlnt/writer/workbook_writer.hpp>
|
||||
#include <xlnt/writer/writer.hpp>
|
||||
|
||||
#include "detail/cell_impl.hpp"
|
||||
#include "detail/include_pugixml.hpp"
|
||||
|
@ -564,7 +565,7 @@ bool workbook::save(const std::string &filename)
|
|||
|
||||
f.writestr("[Content_Types].xml", writer::write_content_types(*this));
|
||||
|
||||
f.writestr("docProps/app.xml", writer::write_properties_app(*this));
|
||||
f.writestr("docProps/app.xml", write_properties_app(*this));
|
||||
f.writestr("docProps/core.xml", writer::write_properties_core(get_properties()));
|
||||
|
||||
std::set<std::string> shared_strings_set;
|
||||
|
@ -589,10 +590,10 @@ bool workbook::save(const std::string &filename)
|
|||
f.writestr("xl/theme/theme1.xml", writer::write_theme());
|
||||
f.writestr("xl/styles.xml", style_writer(*this).write_table());
|
||||
|
||||
f.writestr("_rels/.rels", writer::write_root_rels());
|
||||
f.writestr("xl/_rels/workbook.xml.rels", writer::write_workbook_rels(*this));
|
||||
f.writestr("_rels/.rels", write_root_rels(*this));
|
||||
f.writestr("xl/_rels/workbook.xml.rels", write_workbook_rels(*this));
|
||||
|
||||
f.writestr("xl/workbook.xml", writer::write_workbook(*this));
|
||||
f.writestr("xl/workbook.xml", write_workbook(*this));
|
||||
|
||||
for(auto relationship : d_->relationships_)
|
||||
{
|
||||
|
@ -743,4 +744,23 @@ std::size_t workbook::index_from_ws_filename(const std::string &ws_filename)
|
|||
|
||||
}
|
||||
|
||||
void workbook::set_code_name(const std::string &code_name)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void workbook::add_named_range(const xlnt::named_range &n)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool workbook::has_loaded_theme()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string workbook::get_loaded_theme()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
285
source/workbook_writer.cpp
Normal file
285
source/workbook_writer.cpp
Normal file
|
@ -0,0 +1,285 @@
|
|||
#include <sstream>
|
||||
|
||||
#include <xlnt/common/exceptions.hpp>
|
||||
#include <xlnt/common/relationship.hpp>
|
||||
#include <xlnt/common/zip_file.hpp>
|
||||
#include <xlnt/workbook/document_properties.hpp>
|
||||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/worksheet/range_reference.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
#include <xlnt/writer/manifest_writer.hpp>
|
||||
#include <xlnt/writer/relationship_writer.hpp>
|
||||
#include <xlnt/writer/theme_writer.hpp>
|
||||
#include <xlnt/writer/workbook_writer.hpp>
|
||||
|
||||
#include "constants.hpp"
|
||||
#include "detail/include_pugixml.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
std::string to_xml(xlnt::document_properties &props)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
excel_writer::excel_writer(workbook &wb) : wb_(wb), style_writer_(wb_)
|
||||
{
|
||||
}
|
||||
|
||||
void excel_writer::save(const std::string &filename, bool as_template)
|
||||
{
|
||||
zip_file archive;
|
||||
write_data(archive, as_template);
|
||||
archive.save(filename);
|
||||
}
|
||||
|
||||
void excel_writer::write_data(zip_file &archive, bool as_template)
|
||||
{
|
||||
archive.writestr(constants::ArcRootRels, write_root_rels(wb_));
|
||||
archive.writestr(constants::ArcWorkbookRels, write_workbook_rels(wb_));
|
||||
archive.writestr(constants::ArcApp, write_properties_app(wb_));
|
||||
archive.writestr(constants::ArcCore, to_xml(wb_.get_properties()));
|
||||
|
||||
if(wb_.has_loaded_theme())
|
||||
{
|
||||
archive.writestr(constants::ArcTheme, wb_.get_loaded_theme());
|
||||
}
|
||||
else
|
||||
{
|
||||
archive.writestr(constants::ArcTheme, write_theme());
|
||||
}
|
||||
|
||||
archive.writestr(constants::ArcWorkbook, write_workbook(wb_));
|
||||
|
||||
/*
|
||||
if(wb_.has_vba_archive())
|
||||
{
|
||||
auto &vba_archive = wb_.get_vba_archive();
|
||||
|
||||
for(auto name : vba_archive.namelist())
|
||||
{
|
||||
for(auto s : constants::ArcVba)
|
||||
{
|
||||
if(match(s, name))
|
||||
{
|
||||
archive.writestr(name, vba_archive.read(name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
write_charts(archive);
|
||||
write_images(archive);
|
||||
write_worksheets(archive);
|
||||
write_chartsheets(archive);
|
||||
write_string_table(archive);
|
||||
write_external_links(archive);
|
||||
archive.writestr(constants::ArcStyles, style_writer_.write_table());
|
||||
auto manifest = write_content_types(wb_, as_template);
|
||||
archive.writestr(constants::ArcContentTypes, manifest);
|
||||
}
|
||||
|
||||
void excel_writer::write_string_table(zip_file &archive)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void excel_writer::write_images(zip_file &archive)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void excel_writer::write_charts(zip_file &archive)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void excel_writer::write_chartsheets(zip_file &archive)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void excel_writer::write_worksheets(zip_file &archive)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void excel_writer::write_external_links(zip_file &archive)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string write_properties_app(const workbook &wb)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
auto root_node = doc.append_child("Properties");
|
||||
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
|
||||
root_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
|
||||
|
||||
root_node.append_child("Application").text().set("Microsoft Excel");
|
||||
root_node.append_child("DocSecurity").text().set("0");
|
||||
root_node.append_child("ScaleCrop").text().set("false");
|
||||
root_node.append_child("Company");
|
||||
root_node.append_child("LinksUpToDate").text().set("false");
|
||||
root_node.append_child("SharedDoc").text().set("false");
|
||||
root_node.append_child("HyperlinksChanged").text().set("false");
|
||||
root_node.append_child("AppVersion").text().set("12.0000");
|
||||
|
||||
auto heading_pairs_node = root_node.append_child("HeadingPairs");
|
||||
auto heading_pairs_vector_node = heading_pairs_node.append_child("vt:vector");
|
||||
heading_pairs_vector_node.append_attribute("baseType").set_value("variant");
|
||||
heading_pairs_vector_node.append_attribute("size").set_value("2");
|
||||
heading_pairs_vector_node.append_child("vt:variant").append_child("vt:lpstr").text().set("Worksheets");
|
||||
heading_pairs_vector_node.append_child("vt:variant").append_child("vt:i4").text().set(std::to_string(wb.get_sheet_names().size()).c_str());
|
||||
|
||||
auto titles_of_parts_node = root_node.append_child("TitlesOfParts");
|
||||
auto titles_of_parts_vector_node = titles_of_parts_node.append_child("vt:vector");
|
||||
titles_of_parts_vector_node.append_attribute("baseType").set_value("lpstr");
|
||||
titles_of_parts_vector_node.append_attribute("size").set_value(std::to_string(wb.get_sheet_names().size()).c_str());
|
||||
|
||||
for(auto ws : wb)
|
||||
{
|
||||
titles_of_parts_vector_node.append_child("vt:lpstr").text().set(ws.get_title().c_str());
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string write_root_rels(const workbook &)
|
||||
{
|
||||
std::vector<relationship> relationships;
|
||||
|
||||
relationships.push_back(relationship(relationship::type::extended_properties, "rId3", "docProps/app.xml"));
|
||||
relationships.push_back(relationship(relationship::type::core_properties, "rId2", "docProps/core.xml"));
|
||||
relationships.push_back(relationship(relationship::type::office_document, "rId1", "xl/workbook.xml"));
|
||||
|
||||
return write_relationships(relationships, "");
|
||||
}
|
||||
|
||||
std::string write_workbook(const workbook &wb)
|
||||
{
|
||||
std::size_t num_visible = 0;
|
||||
|
||||
for(auto ws : wb)
|
||||
{
|
||||
if(ws.get_page_setup().get_sheet_state() == xlnt::page_setup::sheet_state::visible)
|
||||
{
|
||||
num_visible++;
|
||||
}
|
||||
}
|
||||
|
||||
if(num_visible == 0)
|
||||
{
|
||||
throw value_error();
|
||||
}
|
||||
|
||||
pugi::xml_document doc;
|
||||
auto root_node = doc.append_child("workbook");
|
||||
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
||||
root_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
||||
|
||||
auto file_version_node = root_node.append_child("fileVersion");
|
||||
file_version_node.append_attribute("appName").set_value("xl");
|
||||
file_version_node.append_attribute("lastEdited").set_value("4");
|
||||
file_version_node.append_attribute("lowestEdited").set_value("4");
|
||||
file_version_node.append_attribute("rupBuild").set_value("4505");
|
||||
|
||||
auto workbook_pr_node = root_node.append_child("workbookPr");
|
||||
workbook_pr_node.append_attribute("codeName").set_value("ThisWorkbook");
|
||||
workbook_pr_node.append_attribute("defaultThemeVersion").set_value("124226");
|
||||
|
||||
auto book_views_node = root_node.append_child("bookViews");
|
||||
auto workbook_view_node = book_views_node.append_child("workbookView");
|
||||
workbook_view_node.append_attribute("activeTab").set_value("0");
|
||||
workbook_view_node.append_attribute("autoFilterDateGrouping").set_value("1");
|
||||
workbook_view_node.append_attribute("firstSheet").set_value("0");
|
||||
workbook_view_node.append_attribute("minimized").set_value("0");
|
||||
workbook_view_node.append_attribute("showHorizontalScroll").set_value("1");
|
||||
workbook_view_node.append_attribute("showSheetTabs").set_value("1");
|
||||
workbook_view_node.append_attribute("showVerticalScroll").set_value("1");
|
||||
workbook_view_node.append_attribute("tabRatio").set_value("600");
|
||||
workbook_view_node.append_attribute("visibility").set_value("visible");
|
||||
|
||||
auto sheets_node = root_node.append_child("sheets");
|
||||
auto defined_names_node = root_node.append_child("definedNames");
|
||||
|
||||
for(auto relationship : wb.get_relationships())
|
||||
{
|
||||
if(relationship.get_type() == relationship::type::worksheet)
|
||||
{
|
||||
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('/'));
|
||||
auto iter = sheet_index_string.end();
|
||||
iter--;
|
||||
while (isdigit(*iter)) iter--;
|
||||
auto first_digit = iter - sheet_index_string.begin();
|
||||
sheet_index_string = sheet_index_string.substr(first_digit + 1);
|
||||
std::size_t sheet_index = std::stoi(sheet_index_string) - 1;
|
||||
|
||||
auto ws = wb.get_sheet_by_index(sheet_index);
|
||||
|
||||
auto sheet_node = sheets_node.append_child("sheet");
|
||||
sheet_node.append_attribute("name").set_value(ws.get_title().c_str());
|
||||
sheet_node.append_attribute("r:id").set_value(relationship.get_id().c_str());
|
||||
sheet_node.append_attribute("sheetId").set_value(std::to_string(sheet_index + 1).c_str());
|
||||
|
||||
if(ws.has_auto_filter())
|
||||
{
|
||||
auto defined_name_node = defined_names_node.append_child("definedName");
|
||||
defined_name_node.append_attribute("name").set_value("_xlnm._FilterDatabase");
|
||||
defined_name_node.append_attribute("hidden").set_value(1);
|
||||
defined_name_node.append_attribute("localSheetId").set_value(0);
|
||||
std::string name = "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string();
|
||||
defined_name_node.text().set(name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto calc_pr_node = root_node.append_child("calcPr");
|
||||
calc_pr_node.append_attribute("calcId").set_value("124519");
|
||||
calc_pr_node.append_attribute("calcMode").set_value("auto");
|
||||
calc_pr_node.append_attribute("fullCalcOnLoad").set_value("1");
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string write_workbook_rels(const workbook &wb)
|
||||
{
|
||||
return write_relationships(wb.get_relationships(), "xl/");
|
||||
}
|
||||
|
||||
std::string write_theme()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
bool save_workbook(workbook &wb, const std::string &filename, bool as_template)
|
||||
{
|
||||
excel_writer writer(wb);
|
||||
writer.save(filename, as_template);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template)
|
||||
{
|
||||
excel_writer writer(wb);
|
||||
std::vector<std::uint8_t> buffer;
|
||||
zip_file archive(buffer);
|
||||
writer.write_data(archive, as_template);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
|
@ -700,4 +700,9 @@ cell_reference worksheet::get_point_pos(const std::pair<int, int> &point) const
|
|||
return get_point_pos(point.first, point.second);
|
||||
}
|
||||
|
||||
void worksheet::set_sheet_state(page_setup::sheet_state state)
|
||||
{
|
||||
get_page_setup().set_sheet_state(state);
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <pugixml.hpp>
|
||||
|
||||
#include <xlnt/writer/writer.hpp>
|
||||
#include <xlnt/cell/cell.hpp>
|
||||
#include <xlnt/common/relationship.hpp>
|
||||
#include <xlnt/workbook/document_properties.hpp>
|
||||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/worksheet/range.hpp>
|
||||
#include <xlnt/worksheet/range_reference.hpp>
|
||||
#include <xlnt/worksheet/worksheet.hpp>
|
||||
#include <xlnt/workbook/workbook.hpp>
|
||||
#include <xlnt/common/relationship.hpp>
|
||||
#include <xlnt/workbook/document_properties.hpp>
|
||||
#include <xlnt/writer/relationship_writer.hpp>
|
||||
#include <xlnt/writer/writer.hpp>
|
||||
|
||||
#include "constants.hpp"
|
||||
#include "detail/include_pugixml.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -90,129 +90,9 @@ std::string writer::write_properties_core(const document_properties &prop)
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::string writer::write_properties_app(const workbook &wb)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
auto root_node = doc.append_child("Properties");
|
||||
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/officeDocument/2006/extended-properties");
|
||||
root_node.append_attribute("xmlns:vt").set_value("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes");
|
||||
|
||||
root_node.append_child("Application").text().set("Microsoft Excel");
|
||||
root_node.append_child("DocSecurity").text().set("0");
|
||||
root_node.append_child("ScaleCrop").text().set("false");
|
||||
root_node.append_child("Company");
|
||||
root_node.append_child("LinksUpToDate").text().set("false");
|
||||
root_node.append_child("SharedDoc").text().set("false");
|
||||
root_node.append_child("HyperlinksChanged").text().set("false");
|
||||
root_node.append_child("AppVersion").text().set("12.0000");
|
||||
|
||||
auto heading_pairs_node = root_node.append_child("HeadingPairs");
|
||||
auto heading_pairs_vector_node = heading_pairs_node.append_child("vt:vector");
|
||||
heading_pairs_vector_node.append_attribute("baseType").set_value("variant");
|
||||
heading_pairs_vector_node.append_attribute("size").set_value("2");
|
||||
heading_pairs_vector_node.append_child("vt:variant").append_child("vt:lpstr").text().set("Worksheets");
|
||||
heading_pairs_vector_node.append_child("vt:variant").append_child("vt:i4").text().set(std::to_string(wb.get_sheet_names().size()).c_str());
|
||||
|
||||
auto titles_of_parts_node = root_node.append_child("TitlesOfParts");
|
||||
auto titles_of_parts_vector_node = titles_of_parts_node.append_child("vt:vector");
|
||||
titles_of_parts_vector_node.append_attribute("baseType").set_value("lpstr");
|
||||
titles_of_parts_vector_node.append_attribute("size").set_value(std::to_string(wb.get_sheet_names().size()).c_str());
|
||||
|
||||
for(auto ws : wb)
|
||||
{
|
||||
titles_of_parts_vector_node.append_child("vt:lpstr").text().set(ws.get_title().c_str());
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string writer::write_workbook_rels(const workbook &wb)
|
||||
{
|
||||
return write_relationships(wb.get_relationships(), "xl/");
|
||||
}
|
||||
|
||||
std::string writer::write_worksheet_rels(worksheet ws)
|
||||
{
|
||||
return write_relationships(ws.get_relationships());
|
||||
}
|
||||
|
||||
std::string writer::write_workbook(const workbook &wb)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
auto root_node = doc.append_child("workbook");
|
||||
root_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
||||
root_node.append_attribute("xmlns:r").set_value("http://schemas.openxmlformats.org/officeDocument/2006/relationships");
|
||||
|
||||
auto file_version_node = root_node.append_child("fileVersion");
|
||||
file_version_node.append_attribute("appName").set_value("xl");
|
||||
file_version_node.append_attribute("lastEdited").set_value("4");
|
||||
file_version_node.append_attribute("lowestEdited").set_value("4");
|
||||
file_version_node.append_attribute("rupBuild").set_value("4505");
|
||||
|
||||
auto workbook_pr_node = root_node.append_child("workbookPr");
|
||||
workbook_pr_node.append_attribute("codeName").set_value("ThisWorkbook");
|
||||
workbook_pr_node.append_attribute("defaultThemeVersion").set_value("124226");
|
||||
|
||||
auto book_views_node = root_node.append_child("bookViews");
|
||||
auto workbook_view_node = book_views_node.append_child("workbookView");
|
||||
workbook_view_node.append_attribute("activeTab").set_value("0");
|
||||
workbook_view_node.append_attribute("autoFilterDateGrouping").set_value("1");
|
||||
workbook_view_node.append_attribute("firstSheet").set_value("0");
|
||||
workbook_view_node.append_attribute("minimized").set_value("0");
|
||||
workbook_view_node.append_attribute("showHorizontalScroll").set_value("1");
|
||||
workbook_view_node.append_attribute("showSheetTabs").set_value("1");
|
||||
workbook_view_node.append_attribute("showVerticalScroll").set_value("1");
|
||||
workbook_view_node.append_attribute("tabRatio").set_value("600");
|
||||
workbook_view_node.append_attribute("visibility").set_value("visible");
|
||||
|
||||
auto sheets_node = root_node.append_child("sheets");
|
||||
auto defined_names_node = root_node.append_child("definedNames");
|
||||
|
||||
for(auto relationship : wb.get_relationships())
|
||||
{
|
||||
if(relationship.get_type() == relationship::type::worksheet)
|
||||
{
|
||||
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('/'));
|
||||
auto iter = sheet_index_string.end();
|
||||
iter--;
|
||||
while (isdigit(*iter)) iter--;
|
||||
auto first_digit = iter - sheet_index_string.begin();
|
||||
sheet_index_string = sheet_index_string.substr(first_digit + 1);
|
||||
std::size_t sheet_index = std::stoi(sheet_index_string) - 1;
|
||||
|
||||
auto ws = wb.get_sheet_by_index(sheet_index);
|
||||
|
||||
auto sheet_node = sheets_node.append_child("sheet");
|
||||
sheet_node.append_attribute("name").set_value(ws.get_title().c_str());
|
||||
sheet_node.append_attribute("r:id").set_value(relationship.get_id().c_str());
|
||||
sheet_node.append_attribute("sheetId").set_value(std::to_string(sheet_index + 1).c_str());
|
||||
|
||||
if(ws.has_auto_filter())
|
||||
{
|
||||
auto defined_name_node = defined_names_node.append_child("definedName");
|
||||
defined_name_node.append_attribute("name").set_value("_xlnm._FilterDatabase");
|
||||
defined_name_node.append_attribute("hidden").set_value(1);
|
||||
defined_name_node.append_attribute("localSheetId").set_value(0);
|
||||
std::string name = "'" + ws.get_title() + "'!" + range_reference::make_absolute(ws.get_auto_filter()).to_string();
|
||||
defined_name_node.text().set(name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto calc_pr_node = root_node.append_child("calcPr");
|
||||
calc_pr_node.append_attribute("calcId").set_value("124519");
|
||||
calc_pr_node.append_attribute("calcMode").set_value("auto");
|
||||
calc_pr_node.append_attribute("fullCalcOnLoad").set_value("1");
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
|
||||
return ss.str();
|
||||
return write_relationships(ws.get_relationships(), "");
|
||||
}
|
||||
|
||||
std::string writer::write_worksheet(worksheet ws, const std::vector<std::string> &string_table, const std::unordered_map<std::size_t, std::string> &style_id_by_hash)
|
||||
|
@ -571,50 +451,6 @@ std::string writer::write_content_types(const workbook &wb)
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::string xlnt::writer::write_root_rels()
|
||||
{
|
||||
std::vector<relationship> relationships;
|
||||
|
||||
relationships.push_back(relationship(relationship::type::extended_properties, "rId3", "docProps/app.xml"));
|
||||
relationships.push_back(relationship(relationship::type::core_properties, "rId2", "docProps/core.xml"));
|
||||
relationships.push_back(relationship(relationship::type::office_document, "rId1", "xl/workbook.xml"));
|
||||
|
||||
return write_relationships(relationships);
|
||||
}
|
||||
|
||||
std::string writer::write_relationships(const std::vector<relationship> &relationships, const std::string &dir)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
|
||||
auto root_node = doc.append_child("Relationships");
|
||||
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("relationships").c_str());
|
||||
|
||||
for(auto relationship : relationships)
|
||||
{
|
||||
auto target = relationship.get_target_uri();
|
||||
|
||||
if (dir != "" && target.substr(0, dir.size()) == dir)
|
||||
{
|
||||
target = target.substr(dir.size());
|
||||
}
|
||||
|
||||
auto app_props_node = root_node.append_child("Relationship");
|
||||
|
||||
app_props_node.append_attribute("Id").set_value(relationship.get_id().c_str());
|
||||
app_props_node.append_attribute("Target").set_value(target.c_str());
|
||||
app_props_node.append_attribute("Type").set_value(relationship.get_type_string().c_str());
|
||||
|
||||
if(relationship.get_target_mode() == target_mode::external)
|
||||
{
|
||||
app_props_node.append_attribute("TargetMode").set_value("External");
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string writer::write_theme()
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
|
|
|
@ -28,6 +28,11 @@ public:
|
|||
operator bool() const { return difference == difference_type::equivalent; }
|
||||
};
|
||||
|
||||
static comparison_result compare_xml(const std::string &left_contents, const std::string &right_contents)
|
||||
{
|
||||
return {difference_type::names_differ,"",""};
|
||||
}
|
||||
|
||||
static comparison_result compare_xml(const pugi::xml_node &left, const pugi::xml_node &right)
|
||||
{
|
||||
std::string left_temp = left.name();
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
|
@ -20,6 +22,15 @@
|
|||
class PathHelper
|
||||
{
|
||||
public:
|
||||
static std::string read_file(const std::string &filename)
|
||||
{
|
||||
std::ifstream f(filename);
|
||||
std::ostringstream ss;
|
||||
ss << f.rdbuf();
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static std::string WindowsToUniversalPath(const std::string &windows_path)
|
||||
{
|
||||
std::string fixed;
|
||||
|
|
|
@ -3,14 +3,38 @@
|
|||
#include <iostream>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <xlnt/xlnt.hpp>
|
||||
#include <xlnt/workbook/named_range.hpp>
|
||||
|
||||
class test_named_range : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_split()
|
||||
{
|
||||
/*TS_ASSERT_EQUALS([("My Sheet", "$D$8"), ], split_named_range(""My Sheet"!$D$8"))*/
|
||||
using string_pair = std::pair<std::string, std::string>;
|
||||
using string_pair_vector = std::vector<string_pair>;
|
||||
using expected_pair = std::pair<std::string, string_pair_vector>;
|
||||
|
||||
std::vector<expected_pair> expected_pairs =
|
||||
{
|
||||
{ "'My Sheet'!$D$8", {{ "My Sheet", "$D$8" }} },
|
||||
{ "Sheet1!$A$1", {{ "Sheet1", "$A$1" }} },
|
||||
{ "[1]Sheet1!$A$1", {{ "[1]Sheet1", "$A$1" }} },
|
||||
{ "[1]!B2range", {{ "[1]", "" }} },
|
||||
{ "Sheet1!$C$5:$C$7,Sheet1!$C$9:$C$11,Sheet1!$E$5:$E$7,Sheet1!$E$9:$E$11,Sheet1!$D$8",
|
||||
{
|
||||
{ "Sheet1", "$C$5:$C$7" },
|
||||
{ "Sheet1", "$C$9:$C$11" },
|
||||
{ "Sheet1", "$E$5:$E$7" },
|
||||
{ "Sheet1", "$E$9:$E$11" },
|
||||
{ "Sheet1", "$D$8" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for(auto pair : expected_pairs)
|
||||
{
|
||||
TS_ASSERT_EQUALS(xlnt::split_named_range(pair.first), pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
void test_split_no_quotes()
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <xlnt/xlnt.hpp>
|
||||
|
||||
class test_number_format : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
test_number_format()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void setup_class(int cls)
|
||||
{
|
||||
//cls.workbook = Workbook()
|
||||
// cls.worksheet = Worksheet(cls.workbook, "Test")
|
||||
// cls.sd = SharedDate()
|
||||
}
|
||||
|
||||
void test_convert_date_to_julian()
|
||||
{
|
||||
//TS_ASSERT_EQUALS(40167, sd.to_julian(2009, 12, 20))
|
||||
}
|
||||
|
||||
void test_convert_date_from_julian()
|
||||
{
|
||||
}
|
||||
|
||||
void test_date_equal(int julian, int datetime)
|
||||
{
|
||||
//TS_ASSERT_EQUALS(sd.from_julian(julian), datetime);
|
||||
|
||||
//date_pairs = (
|
||||
// (40167, datetime(2009, 12, 20)),
|
||||
// (21980, datetime(1960, 3, 5)),
|
||||
// );
|
||||
|
||||
//for count, dt in date_pairs
|
||||
//{
|
||||
// yield test_date_equal, count, dt;
|
||||
//}
|
||||
}
|
||||
|
||||
void test_convert_datetime_to_julian()
|
||||
{
|
||||
//TS_ASSERT_EQUALS(40167, sd.datetime_to_julian(datetime(2009, 12, 20)))
|
||||
// TS_ASSERT_EQUALS(40196.5939815, sd.datetime_to_julian(datetime(2010, 1, 18, 14, 15, 20, 1600)))
|
||||
}
|
||||
|
||||
void test_insert_float()
|
||||
{
|
||||
//worksheet.cell("A1").value = 3.14
|
||||
// TS_ASSERT_EQUALS(Cell.TYPE_NUMERIC, worksheet.cell("A1")._data_type)
|
||||
}
|
||||
|
||||
void test_insert_percentage()
|
||||
{
|
||||
//worksheet.cell("A1").value = "3.14%"
|
||||
// TS_ASSERT_EQUALS(Cell.TYPE_NUMERIC, worksheet.cell("A1")._data_type)
|
||||
// assert_almost_equal(0.0314, worksheet.cell("A1").value)
|
||||
}
|
||||
|
||||
void test_insert_datetime()
|
||||
{
|
||||
//worksheet.cell("A1").value = date.today()
|
||||
// TS_ASSERT_EQUALS(Cell.TYPE_NUMERIC, worksheet.cell("A1")._data_type)
|
||||
}
|
||||
|
||||
void test_insert_date()
|
||||
{
|
||||
//worksheet.cell("A1").value = datetime.now()
|
||||
// TS_ASSERT_EQUALS(Cell.TYPE_NUMERIC, worksheet.cell("A1")._data_type)
|
||||
}
|
||||
|
||||
void test_internal_date()
|
||||
{
|
||||
//dt = datetime(2010, 7, 13, 6, 37, 41)
|
||||
// worksheet.cell("A3").value = dt
|
||||
// TS_ASSERT_EQUALS(40372.27616898148, worksheet.cell("A3")._value)
|
||||
}
|
||||
|
||||
void test_datetime_interpretation()
|
||||
{
|
||||
//dt = datetime(2010, 7, 13, 6, 37, 41)
|
||||
// worksheet.cell("A3").value = dt
|
||||
// TS_ASSERT_EQUALS(dt, worksheet.cell("A3").value)
|
||||
}
|
||||
|
||||
void test_date_interpretation()
|
||||
{
|
||||
//dt = date(2010, 7, 13)
|
||||
// worksheet.cell("A3").value = dt
|
||||
// TS_ASSERT_EQUALS(datetime(2010, 7, 13, 0, 0), worksheet.cell("A3").value)
|
||||
}
|
||||
|
||||
void test_number_format_style()
|
||||
{
|
||||
//worksheet.cell("A1").value = "12.6%"
|
||||
// TS_ASSERT_EQUALS(NumberFormat.FORMAT_PERCENTAGE, \
|
||||
// worksheet.cell("A1").style.number_format.format_code)
|
||||
}
|
||||
|
||||
void test_date_format_on_non_date()
|
||||
{
|
||||
//cell = worksheet.cell("A1");
|
||||
}
|
||||
|
||||
void check_date_pair(int count, const std::string &date_string)
|
||||
{
|
||||
//cell.value = strptime(date_string, "%Y-%m-%d");
|
||||
//TS_ASSERT_EQUALS(count, cell._value);
|
||||
|
||||
//date_pairs = (
|
||||
// (15, "1900-01-15"),
|
||||
// (59, "1900-02-28"),
|
||||
// (61, "1900-03-01"),
|
||||
// (367, "1901-01-01"),
|
||||
// (2958465, "9999-12-31"), );
|
||||
//for count, date_string in date_pairs
|
||||
//{
|
||||
// yield check_date_pair, count, date_string;
|
||||
//}
|
||||
}
|
||||
|
||||
void test_1900_leap_year()
|
||||
{
|
||||
//assert_raises(ValueError, sd.from_julian, 60)
|
||||
// assert_raises(ValueError, sd.to_julian, 1900, 2, 29)
|
||||
}
|
||||
|
||||
void test_bad_date()
|
||||
{
|
||||
//void check_bad_date(year, month, day)
|
||||
//{
|
||||
// assert_raises(ValueError, sd.to_julian, year, month, day)
|
||||
//}
|
||||
|
||||
//bad_dates = ((1776, 7, 4), (1899, 12, 31), )
|
||||
// for year, month, day in bad_dates
|
||||
// {
|
||||
// yield check_bad_date, year, month, day
|
||||
// }
|
||||
}
|
||||
|
||||
void test_bad_julian_date()
|
||||
{
|
||||
//assert_raises(ValueError, sd.from_julian, -1)
|
||||
}
|
||||
|
||||
void test_mac_date()
|
||||
{
|
||||
// sd.excel_base_date = CALENDAR_MAC_1904
|
||||
|
||||
// datetuple = (2011, 10, 31)
|
||||
|
||||
// dt = date(datetuple[0], datetuple[1], datetuple[2])
|
||||
// julian = sd.to_julian(datetuple[0], datetuple[1], datetuple[2])
|
||||
// reverse = sd.from_julian(julian).date()
|
||||
// TS_ASSERT_EQUALS(dt, reverse)
|
||||
// sd.excel_base_date = CALENDAR_WINDOWS_1900
|
||||
}
|
||||
};
|
|
@ -3,7 +3,8 @@
|
|||
#include <iostream>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <xlnt/xlnt.hpp>
|
||||
#include <xlnt/writer/workbook_writer.hpp>
|
||||
|
||||
#include "helpers/path_helper.hpp"
|
||||
#include "helpers/helper.hpp"
|
||||
|
||||
|
@ -69,7 +70,7 @@ public:
|
|||
xlnt::workbook wb;
|
||||
wb.create_sheet();
|
||||
wb.create_sheet();
|
||||
auto content = xlnt::writer::write_properties_app(wb);
|
||||
auto content = xlnt::write_properties_app(wb);
|
||||
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/app.xml", content));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
void test_write_workbook_rels()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto content = xlnt::writer::write_workbook_rels(wb);
|
||||
auto content = xlnt::write_workbook_rels(wb);
|
||||
|
||||
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook.xml.rels", content));
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ public:
|
|||
void test_write_workbook()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto content = xlnt::writer::write_workbook(wb);
|
||||
auto content = xlnt::write_workbook(wb);
|
||||
|
||||
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook.xml", content));
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ public:
|
|||
auto content = xlnt::writer::write_worksheet(ws, {"hello"}, {});
|
||||
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/sheet1_auto_filter.xml", content));
|
||||
|
||||
content = xlnt::writer::write_workbook(wb);
|
||||
content = xlnt::write_workbook(wb);
|
||||
TS_ASSERT(Helper::EqualsFileContent(PathHelper::GetDataDirectory() + "/writer/expected/workbook_auto_filter.xml", content));
|
||||
}
|
||||
|
||||
|
|
175
tests/test_write_workbook.hpp
Normal file
175
tests/test_write_workbook.hpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <xlnt/common/exceptions.hpp>
|
||||
#include <xlnt/writer/workbook_writer.hpp>
|
||||
|
||||
#include "helpers/path_helper.hpp"
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
xlnt::workbook load_workbook(const std::vector<std::uint8_t> &bytes)
|
||||
{
|
||||
return xlnt::workbook();
|
||||
}
|
||||
|
||||
std::string write_workbook_rels(xlnt::workbook &wb)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string write_root_rels(xlnt::workbook &wb)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string write_defined_names(xlnt::workbook &wb)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class test_write_workbook : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_write_auto_filter()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto ws = wb.create_sheet();
|
||||
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);
|
||||
TS_ASSERT(!diff);
|
||||
}
|
||||
|
||||
void test_write_hidden_worksheet()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
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 =
|
||||
"<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
|
||||
" <workbookPr/>"
|
||||
" <bookViews>"
|
||||
" <workbookView activeTab=\"0\"/>"
|
||||
" </bookViews>"
|
||||
" <sheets>"
|
||||
" <sheet name=\"Sheet\" sheetId=\"1\" state=\"hidden\" r:id=\"rId1\"/>"
|
||||
" <sheet name=\"Sheet1\" sheetId=\"2\" r:id=\"rId2\"/>"
|
||||
" </sheets>"
|
||||
" <definedNames/>"
|
||||
" <calcPr calcId=\"124519\" fullCalcOnLoad=\"1\"/>"
|
||||
"</workbook>";
|
||||
auto diff = Helper::compare_xml(xml, expected);
|
||||
TS_ASSERT(!diff);
|
||||
}
|
||||
|
||||
void test_write_hidden_single_worksheet()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void test_write_empty_workbook()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
std::string dest_filename = "empty_book.xlsx";
|
||||
xlnt::save_workbook(wb, dest_filename);
|
||||
TS_ASSERT(PathHelper::FileExists(dest_filename));
|
||||
}
|
||||
|
||||
void test_write_virtual_workbook()
|
||||
{
|
||||
xlnt::workbook old_wb;
|
||||
auto saved_wb = xlnt::save_virtual_workbook(old_wb);
|
||||
auto new_wb = xlnt::load_workbook(saved_wb);
|
||||
TS_ASSERT(new_wb != nullptr);
|
||||
}
|
||||
|
||||
void test_write_workbook_rels()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto content = xlnt::write_workbook_rels(wb);
|
||||
auto filename = "workbook.xml.rels";
|
||||
auto diff = Helper::compare_xml(PathHelper::read_file(filename), content);
|
||||
TS_ASSERT(!diff);
|
||||
}
|
||||
|
||||
void test_write_workbook_()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto content = xlnt::write_workbook(wb);
|
||||
auto filename = "workbook.xml";
|
||||
auto diff = Helper::compare_xml(PathHelper::read_file(filename), content);
|
||||
TS_ASSERT(!diff);
|
||||
}
|
||||
|
||||
void test_write_named_range()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto ws = wb.create_sheet();
|
||||
xlnt::named_range xlrange("test_range", {{ws, "A1:B5"}});
|
||||
wb.add_named_range(xlrange);
|
||||
auto xml = xlnt::write_defined_names(wb);
|
||||
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);
|
||||
TS_ASSERT(!diff);
|
||||
}
|
||||
|
||||
void test_read_workbook_code_name()
|
||||
{
|
||||
// with open(tmpl, "rb") as expected:
|
||||
// TS_ASSERT(read_workbook_code_name(expected.read()) == code_name
|
||||
}
|
||||
|
||||
void test_write_workbook_code_name()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
wb.set_code_name("MyWB");
|
||||
|
||||
auto content = xlnt::write_workbook(wb);
|
||||
std::string expected =
|
||||
"<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">"
|
||||
" <workbookPr codeName=\"MyWB\"/>"
|
||||
" <bookViews>"
|
||||
" <workbookView activeTab=\"0\"/>"
|
||||
" </bookViews>"
|
||||
" <sheets>"
|
||||
" <sheet name=\"Sheet\" sheetId=\"1\" r:id=\"rId1\"/>"
|
||||
" </sheets>"
|
||||
" <definedNames/>"
|
||||
" <calcPr calcId=\"124519\" fullCalcOnLoad=\"1\"/>"
|
||||
"</workbook>";
|
||||
auto diff = Helper::compare_xml(content, expected);
|
||||
TS_ASSERT(!diff);
|
||||
}
|
||||
|
||||
void test_write_root_rels()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
auto xml = xlnt::write_root_rels(wb);
|
||||
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);
|
||||
TS_ASSERT(!diff);
|
||||
}
|
||||
|
||||
private:
|
||||
xlnt::workbook wb_;
|
||||
};
|
Loading…
Reference in New Issue
Block a user