mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
improve date handling and printing
This commit is contained in:
parent
e3bb0be98e
commit
a63984969e
|
@ -115,7 +115,7 @@ public:
|
|||
// style shortcuts
|
||||
std::string get_number_format();
|
||||
std::string get_number_format() const;
|
||||
void set_number_format(const std::string &format_code);
|
||||
void set_number_format(const std::string &format_code, int index = -1);
|
||||
font &get_font();
|
||||
const font &get_font() const;
|
||||
fill &get_fill();
|
||||
|
@ -144,6 +144,16 @@ public:
|
|||
bool has_formula() const;
|
||||
|
||||
// printing
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string describing this cell like <Cell Sheet.A1>.
|
||||
/// </summary>
|
||||
std::string to_repr() const;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string representing the value of this cell. If the data type is not a string,
|
||||
/// it will be converted according to the number format.
|
||||
/// </summary>
|
||||
std::string to_string() const;
|
||||
|
||||
// merging
|
||||
|
@ -161,8 +171,6 @@ public:
|
|||
// operators
|
||||
cell &operator=(const cell &rhs);
|
||||
|
||||
std::ostream &print(std::ostream &stream, bool convert) const;
|
||||
|
||||
bool operator==(const cell &comparand) const;
|
||||
bool operator==(std::nullptr_t) const;
|
||||
|
||||
|
@ -178,7 +186,7 @@ private:
|
|||
|
||||
inline std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
|
||||
{
|
||||
return cell.print(stream, true);
|
||||
return stream << cell.to_string();
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -46,8 +46,8 @@ public:
|
|||
static std::vector<relationship> read_relationships(zip_file &content, const std::string &filename);
|
||||
static std::vector<std::pair<std::string, std::string>> read_content_types(zip_file &archive);
|
||||
static std::string determine_document_type(const std::vector<std::pair<std::string, std::string>> &override_types);
|
||||
static worksheet read_worksheet(std::istream &handle, workbook &wb, const std::string &title, const std::vector<std::string> &string_table);
|
||||
static void read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids);
|
||||
static worksheet read_worksheet(std::istream &handle, workbook &wb, const std::string &title, const std::vector<std::string> &string_table, const std::unordered_map<int, std::string> &custom_number_formats);
|
||||
static void read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids, const std::unordered_map<int, std::string> &custom_number_formats);
|
||||
static std::vector<std::string> read_shared_string(const std::string &xml_string);
|
||||
static std::string read_dimension(const std::string &xml_string);
|
||||
static document_properties read_properties_core(const std::string &xml_string);
|
||||
|
|
|
@ -90,11 +90,45 @@ public:
|
|||
static bool is_builtin(const std::string &format);
|
||||
|
||||
number_format() : format_code_(format::general), format_index_(0) {}
|
||||
number_format(format code) : format_code_(code) {}
|
||||
number_format(format code) : format_code_(code), format_index_(reversed_builtin_formats().at(format_strings().at(code))) {}
|
||||
|
||||
format get_format_code() const { return format_code_; }
|
||||
void set_format_code(format format_code) { format_code_ = format_code; }
|
||||
void set_format_code_string(const std::string &format_code) { custom_format_code_ = format_code; format_code_ = format::unknown; }
|
||||
|
||||
void set_format_code(format format_code, int index = -1)
|
||||
{
|
||||
format_code_ = format_code;
|
||||
|
||||
if(format_code_ != format::unknown)
|
||||
{
|
||||
set_format_code_string(format_strings().at(format_code), index);
|
||||
}
|
||||
}
|
||||
|
||||
void set_format_code_string(const std::string &format_code, int index)
|
||||
{
|
||||
custom_format_code_ = format_code;
|
||||
format_index_ = index;
|
||||
|
||||
const auto &reversed = reversed_builtin_formats();
|
||||
auto match = reversed.find(format_code);
|
||||
|
||||
format_code_ = format::unknown;
|
||||
|
||||
if(match != reversed.end())
|
||||
{
|
||||
format_index_ = match->second;
|
||||
|
||||
for(const auto &p : format_strings())
|
||||
{
|
||||
if(p.second == format_code)
|
||||
{
|
||||
format_code_ = p.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
std::string get_format_code_string() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -43,6 +43,8 @@ public:
|
|||
std::string write_table() const;
|
||||
std::vector<style> get_styles() const;
|
||||
|
||||
std::string write_number_formats();
|
||||
|
||||
private:
|
||||
std::vector<style> get_style_list(const workbook &wb) const;
|
||||
std::unordered_map<int, std::string> write_fonts() const;
|
||||
|
@ -53,7 +55,6 @@ private:
|
|||
void write_cell_style();
|
||||
void write_dxfs();
|
||||
void write_table_styles();
|
||||
void write_number_formats();
|
||||
|
||||
std::vector<style> style_list_;
|
||||
workbook &wb_;
|
||||
|
|
Binary file not shown.
424
source/cell.cpp
424
source/cell.cpp
|
@ -16,6 +16,361 @@
|
|||
#include "detail/cell_impl.hpp"
|
||||
#include "detail/comment_impl.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
enum class condition_type
|
||||
{
|
||||
less_than,
|
||||
less_or_equal,
|
||||
equal,
|
||||
greater_than,
|
||||
greater_or_equal,
|
||||
invalid
|
||||
};
|
||||
|
||||
struct section
|
||||
{
|
||||
bool has_value = false;
|
||||
std::string value;
|
||||
bool has_color = false;
|
||||
std::string color;
|
||||
bool has_condition = false;
|
||||
condition_type condition = condition_type::invalid;
|
||||
std::string condition_value;
|
||||
|
||||
section &operator=(const section &other)
|
||||
{
|
||||
has_value = other.has_value;
|
||||
value = other.value;
|
||||
has_color = other.has_color;
|
||||
color = other.color;
|
||||
has_condition = other.has_condition;
|
||||
condition = other.condition;
|
||||
condition_value = other.condition_value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct format_sections
|
||||
{
|
||||
section first;
|
||||
section second;
|
||||
section third;
|
||||
section fourth;
|
||||
};
|
||||
|
||||
// copied from named_range.cpp, keep in sync
|
||||
/// <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;
|
||||
}
|
||||
|
||||
bool is_valid_color(const std::string &color)
|
||||
{
|
||||
static const std::vector<std::string> colors = { "Black", "Green"
|
||||
"White", "Blue", "Magenta", "Yellow", "Cyan", "Red" };
|
||||
return std::find(colors.begin(), colors.end(), color) != colors.end();
|
||||
}
|
||||
|
||||
bool parse_condition(const std::string &string, section &s)
|
||||
{
|
||||
s.has_condition = false;
|
||||
s.condition = condition_type::invalid;
|
||||
s.condition_value.clear();
|
||||
|
||||
if(string[0] == '<')
|
||||
{
|
||||
s.has_condition = true;
|
||||
|
||||
if(string[1] == '=')
|
||||
{
|
||||
s.condition = condition_type::less_or_equal;
|
||||
s.condition_value = string.substr(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.condition = condition_type::less_than;
|
||||
s.condition_value = string.substr(1);
|
||||
}
|
||||
}
|
||||
if(string[0] == '>')
|
||||
{
|
||||
s.has_condition = true;
|
||||
|
||||
if(string[1] == '=')
|
||||
{
|
||||
s.condition = condition_type::greater_or_equal;
|
||||
s.condition_value = string.substr(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.condition = condition_type::greater_than;
|
||||
s.condition_value = string.substr(1);
|
||||
}
|
||||
}
|
||||
else if(string[0] == '=')
|
||||
{
|
||||
s.has_condition = true;
|
||||
s.condition = condition_type::equal;
|
||||
s.condition_value = string.substr(1);
|
||||
}
|
||||
|
||||
return s.has_condition;
|
||||
}
|
||||
|
||||
section parse_section(const std::string §ion_string)
|
||||
{
|
||||
std::string intermediate = section_string;
|
||||
|
||||
section s;
|
||||
std::string first_bracket_part, second_bracket_part;
|
||||
static const std::vector<std::string> bracket_times = { "h", "hh", "m", "mm", "s", "ss" };
|
||||
|
||||
if(section_string[0] == '[')
|
||||
{
|
||||
auto close_bracket_pos = section_string.find(']');
|
||||
|
||||
if(close_bracket_pos == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("missing close bracket");
|
||||
}
|
||||
|
||||
first_bracket_part = intermediate.substr(1, close_bracket_pos - 1);
|
||||
|
||||
if(std::find(bracket_times.begin(), bracket_times.end(), first_bracket_part) != bracket_times.end())
|
||||
{
|
||||
first_bracket_part.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
intermediate = intermediate.substr(close_bracket_pos);
|
||||
}
|
||||
}
|
||||
|
||||
if(!first_bracket_part.empty() && intermediate[0] == '[')
|
||||
{
|
||||
auto close_bracket_pos = section_string.find(']');
|
||||
|
||||
if(close_bracket_pos == std::string::npos)
|
||||
{
|
||||
throw std::runtime_error("missing close bracket");
|
||||
}
|
||||
|
||||
second_bracket_part = intermediate.substr(1, close_bracket_pos - 1);
|
||||
|
||||
if(std::find(bracket_times.begin(), bracket_times.end(), second_bracket_part) != bracket_times.end())
|
||||
{
|
||||
second_bracket_part.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
intermediate = intermediate.substr(close_bracket_pos);
|
||||
}
|
||||
}
|
||||
|
||||
if(!first_bracket_part.empty())
|
||||
{
|
||||
if(is_valid_color(first_bracket_part))
|
||||
{
|
||||
s.color = first_bracket_part;
|
||||
s.has_color = true;
|
||||
}
|
||||
else if(!parse_condition(first_bracket_part, s))
|
||||
{
|
||||
throw std::runtime_error("invalid condition");
|
||||
}
|
||||
}
|
||||
|
||||
if(!second_bracket_part.empty())
|
||||
{
|
||||
if(is_valid_color(second_bracket_part))
|
||||
{
|
||||
if(s.has_color)
|
||||
{
|
||||
throw std::runtime_error("two colors in one section");
|
||||
}
|
||||
|
||||
s.color = second_bracket_part;
|
||||
s.has_color = true;
|
||||
}
|
||||
else if(s.has_condition)
|
||||
{
|
||||
throw std::runtime_error("two conditions in one section");
|
||||
}
|
||||
else if(!parse_condition(second_bracket_part, s))
|
||||
{
|
||||
throw std::runtime_error("invalid condition");
|
||||
}
|
||||
}
|
||||
|
||||
s.value = intermediate;
|
||||
s.has_value = true;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
format_sections parse_format_sections(const std::string &combined)
|
||||
{
|
||||
format_sections result = {};
|
||||
|
||||
auto split = split_string(combined, ';');
|
||||
|
||||
if(split.empty())
|
||||
{
|
||||
throw std::runtime_error("empty string");
|
||||
}
|
||||
|
||||
result.first = parse_section(split[0]);
|
||||
|
||||
if(!result.first.has_condition)
|
||||
{
|
||||
result.second = result.first;
|
||||
result.third = result.first;
|
||||
}
|
||||
|
||||
if(split.size() > 1)
|
||||
{
|
||||
result.second = parse_section(split[1]);
|
||||
}
|
||||
|
||||
if(split.size() > 2)
|
||||
{
|
||||
if(result.first.has_condition && !result.second.has_condition)
|
||||
{
|
||||
throw std::runtime_error("first two sections should have conditions");
|
||||
}
|
||||
|
||||
result.third = parse_section(split[2]);
|
||||
|
||||
if(result.third.has_condition)
|
||||
{
|
||||
throw std::runtime_error("third section shouldn't have a condition");
|
||||
}
|
||||
}
|
||||
|
||||
if(split.size() > 3)
|
||||
{
|
||||
if(result.first.has_condition)
|
||||
{
|
||||
throw std::runtime_error("too many parts");
|
||||
}
|
||||
|
||||
result.fourth = parse_section(split[3]);
|
||||
}
|
||||
|
||||
if(split.size() > 4)
|
||||
{
|
||||
throw std::runtime_error("too many parts");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string format_section(long double number, const section &format)
|
||||
{
|
||||
if(number == static_cast<long long int>(number))
|
||||
{
|
||||
return std::to_string(static_cast<long long int>(number));
|
||||
}
|
||||
|
||||
return std::to_string(number);
|
||||
}
|
||||
|
||||
std::string format_section(const std::string &text, const section &format)
|
||||
{
|
||||
auto arobase_index = format.value.find('@');
|
||||
|
||||
std::string first_part, middle_part, last_part;
|
||||
|
||||
if(arobase_index != std::string::npos)
|
||||
{
|
||||
first_part = format.value.substr(0, arobase_index);
|
||||
middle_part = text;
|
||||
last_part = format.value.substr(arobase_index + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
first_part = format.value;
|
||||
}
|
||||
|
||||
auto unquote = [](std::string &s)
|
||||
{
|
||||
if(!s.empty())
|
||||
{
|
||||
if(s.front() != '"' || s.back() != '"') return false;
|
||||
s = s.substr(0, s.size() - 2);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if(!unquote(first_part) || !unquote(last_part))
|
||||
{
|
||||
throw std::runtime_error(std::string("additional text must be enclosed in quotes: ") + format.value);
|
||||
}
|
||||
|
||||
return first_part + middle_part + last_part;
|
||||
}
|
||||
|
||||
std::string format_number(long double number, const std::string &format)
|
||||
{
|
||||
auto sections = parse_format_sections(format);
|
||||
|
||||
if(number > 0)
|
||||
{
|
||||
return format_section(number, sections.first);
|
||||
}
|
||||
else if(number < 0)
|
||||
{
|
||||
return format_section(number, sections.second);
|
||||
}
|
||||
|
||||
// number == 0
|
||||
return format_section(number, sections.third);
|
||||
}
|
||||
|
||||
std::string format_text(const std::string &text, const std::string &format)
|
||||
{
|
||||
if(format == "General") return text;
|
||||
auto sections = parse_format_sections(format);
|
||||
return format_section(text, sections.fourth);
|
||||
}
|
||||
|
||||
bool is_date_format(const std::string &format_string)
|
||||
{
|
||||
auto not_in = format_string.find_first_not_of("/-:, mMyYdDhHsS");
|
||||
return not_in == std::string::npos;
|
||||
}
|
||||
|
||||
const std::string PercentRegex("^\\-?(?P<number>[0-9]*\\.?[0-9]*\\s?)\%$");
|
||||
const std::string TimeRegex("^(([0-1]{0,1}[0-9]{2}):([0-5][0-9]):?([0-5][0-9])?$)|"
|
||||
"^(([0-5][0-9]):([0-5][0-9])?\\.(\\d{1,6}))");
|
||||
const std::string NumberRegex("^-?([\\d]|[\\d]+\\.[\\d]*|\\.[\\d]+|[1-9][\\d]+\\.?[\\d]*)((E|e)[-+]?[\\d]+)?$");
|
||||
|
||||
}
|
||||
|
||||
namespace xlnt {
|
||||
|
||||
const xlnt::color xlnt::color::black(0);
|
||||
|
@ -259,7 +614,25 @@ bool cell::is_merged() const
|
|||
|
||||
bool cell::is_date() const
|
||||
{
|
||||
return d_->is_date_ || (d_->style_ != nullptr && get_style().get_number_format().get_format_code() == number_format::format::date_xlsx14);
|
||||
if(get_data_type() == type::numeric && has_style())
|
||||
{
|
||||
auto number_format = get_style().get_number_format().get_format_code_string();
|
||||
|
||||
if(number_format != "General")
|
||||
{
|
||||
try
|
||||
{
|
||||
auto sections = parse_format_sections(number_format);
|
||||
return is_date_format(sections.first.value);
|
||||
}
|
||||
catch(std::exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
cell_reference cell::get_reference() const
|
||||
|
@ -303,7 +676,7 @@ bool operator<(cell left, cell right)
|
|||
return left.get_reference() < right.get_reference();
|
||||
}
|
||||
|
||||
std::string cell::to_string() const
|
||||
std::string cell::to_repr() const
|
||||
{
|
||||
return "<Cell " + worksheet(d_->parent_).get_title() + "." + get_reference().to_string() + ">";
|
||||
}
|
||||
|
@ -658,9 +1031,9 @@ timedelta cell::get_value() const
|
|||
//return timedelta::from_number(d_->value_numeric_);
|
||||
}
|
||||
|
||||
void cell::set_number_format(const std::string &format_string)
|
||||
void cell::set_number_format(const std::string &format_string, int index)
|
||||
{
|
||||
get_style().get_number_format().set_format_code_string(format_string);
|
||||
get_style().get_number_format().set_format_code_string(format_string, index);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -674,36 +1047,27 @@ bool cell::has_value() const
|
|||
return d_->type_ != cell::type::null;
|
||||
}
|
||||
|
||||
std::ostream &cell::print(std::ostream &stream, bool convert) const
|
||||
std::string cell::to_string() const
|
||||
{
|
||||
if(!convert)
|
||||
std::string number_format = "General";
|
||||
|
||||
if(has_style())
|
||||
{
|
||||
return stream << get_value<std::string>();
|
||||
number_format = get_style().get_number_format().get_format_code_string();
|
||||
}
|
||||
else
|
||||
|
||||
switch(get_data_type())
|
||||
{
|
||||
switch(get_data_type())
|
||||
{
|
||||
case type::null:
|
||||
return stream << "";
|
||||
case type::string:
|
||||
return stream << get_value<std::string>();
|
||||
case type::numeric:
|
||||
if(is_date())
|
||||
{
|
||||
return stream << get_value<datetime>().to_string(get_parent().get_parent().get_properties().excel_base_date);
|
||||
}
|
||||
else
|
||||
{
|
||||
return stream << get_value<long double>();
|
||||
}
|
||||
case type::error:
|
||||
return stream << get_value<std::string>();
|
||||
case type::formula:
|
||||
return stream << d_->formula_;
|
||||
default:
|
||||
return stream;
|
||||
}
|
||||
case cell::type::null:
|
||||
return "";
|
||||
case cell::type::numeric:
|
||||
return format_number(get_value<long double>(), number_format);
|
||||
case cell::type::string:
|
||||
case cell::type::formula:
|
||||
case cell::type::error:
|
||||
return format_text(get_value<std::string>(), number_format);
|
||||
case cell::type::boolean:
|
||||
return get_value<long double>() == 0 ? "FALSE" : "TRUE";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -146,8 +146,7 @@ struct cell_impl
|
|||
void set_date(long double number, xlnt::number_format::format format_code)
|
||||
{
|
||||
is_date_ = true;
|
||||
auto number_format = xlnt::number_format(format_code);
|
||||
get_style(true).set_number_format(number_format);
|
||||
get_style(true).get_number_format().set_format_code(format_code);
|
||||
value_numeric_ = number;
|
||||
type_ = cell::type::numeric;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <algorithm>
|
||||
#include <regex>
|
||||
|
||||
#include <xlnt/styles/number_format.hpp>
|
||||
|
||||
|
@ -108,10 +109,16 @@ const std::unordered_map<number_format::format, std::string, number_format::form
|
|||
const std::unordered_map<std::string, int> &number_format::reversed_builtin_formats()
|
||||
{
|
||||
static std::unordered_map<std::string, int> formats;
|
||||
static bool initialised = false;
|
||||
|
||||
for(auto format_pair : builtin_formats())
|
||||
if(!initialised)
|
||||
{
|
||||
formats[format_pair.second] = format_pair.first;
|
||||
for(auto format_pair : builtin_formats())
|
||||
{
|
||||
formats[format_pair.second] = format_pair.first;
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
return formats;
|
||||
|
@ -137,12 +144,12 @@ number_format::format number_format::lookup_format(int code)
|
|||
|
||||
std::string number_format::get_format_code_string() const
|
||||
{
|
||||
if(format_code_ == format::unknown)
|
||||
if(builtin_formats().find(format_index_) == builtin_formats().end())
|
||||
{
|
||||
return custom_format_code_;
|
||||
}
|
||||
|
||||
return format_strings().at(format_code_);
|
||||
|
||||
return builtin_formats().at(format_index_);
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -49,7 +49,7 @@ xlnt::datetime w3cdtf_to_datetime(const std::string &string)
|
|||
return result;
|
||||
}
|
||||
|
||||
void read_worksheet_common(xlnt::worksheet ws, const pugi::xml_node &root_node, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids)
|
||||
void read_worksheet_common(xlnt::worksheet ws, const pugi::xml_node &root_node, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids, const std::unordered_map<int, std::string> &custom_number_formats)
|
||||
{
|
||||
auto dimension_node = root_node.child("dimension");
|
||||
std::string dimension = dimension_node.attribute("ref").as_string();
|
||||
|
@ -89,11 +89,11 @@ void read_worksheet_common(xlnt::worksheet ws, const pugi::xml_node &root_node,
|
|||
}
|
||||
else
|
||||
{
|
||||
min_column = static_cast<column_t>(full_range.get_top_left().get_column_index() + 1);
|
||||
max_column = static_cast<column_t>(full_range.get_bottom_right().get_column_index() + 1);
|
||||
min_column = static_cast<column_t>(full_range.get_top_left().get_column_index());
|
||||
max_column = static_cast<column_t>(full_range.get_bottom_right().get_column_index());
|
||||
}
|
||||
|
||||
for(column_t i = min_column; i < max_column + 1; i++)
|
||||
for(column_t i = min_column; i <= max_column; i++)
|
||||
{
|
||||
std::string address = xlnt::cell_reference::column_string_from_index(i) + std::to_string(row_index);
|
||||
auto cell_node = row_node.find_child_by_attribute("c", "r", address.c_str());
|
||||
|
@ -151,16 +151,32 @@ void read_worksheet_common(xlnt::worksheet ws, const pugi::xml_node &root_node,
|
|||
|
||||
if(has_style)
|
||||
{
|
||||
auto number_format_id = number_format_ids.at(static_cast<std::size_t>(std::stoll(style)));
|
||||
auto format = xlnt::number_format::lookup_format(number_format_id);
|
||||
|
||||
ws.get_cell(address).get_style().get_number_format().set_format_code(format);
|
||||
|
||||
if(format == xlnt::number_format::format::date_xlsx14)
|
||||
if(number_format_ids.size() > std::stoll(style))
|
||||
{
|
||||
auto base_date = ws.get_parent().get_properties().excel_base_date;
|
||||
auto converted = xlnt::date::from_number(std::stoi(value_string), base_date);
|
||||
ws.get_cell(address).set_value(converted.to_number(xlnt::calendar::windows_1900));
|
||||
auto number_format_id = number_format_ids.at(static_cast<std::size_t>(std::stoll(style)));
|
||||
auto format = xlnt::number_format::lookup_format(number_format_id);
|
||||
|
||||
if(format == xlnt::number_format::format::unknown)
|
||||
{
|
||||
auto match = custom_number_formats.find(number_format_id);
|
||||
|
||||
if(match != custom_number_formats.end())
|
||||
{
|
||||
ws.get_cell(address).get_style().get_number_format().set_format_code_string(match->second, number_format_id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ws.get_cell(address).get_style().get_number_format().set_format_code(format);
|
||||
}
|
||||
|
||||
//TODO: this is bad
|
||||
if(ws.get_cell(address).get_style().get_number_format().get_format_code_string().find_first_of("mdyhs") != std::string::npos)
|
||||
{
|
||||
auto base_date = ws.get_parent().get_properties().excel_base_date;
|
||||
auto converted = xlnt::datetime::from_number(std::stold(value_string), base_date);
|
||||
ws.get_cell(address).set_value(converted.to_number(xlnt::calendar::windows_1900));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -371,23 +387,23 @@ void reader::fast_parse(worksheet ws, std::istream &xml_source, const std::vecto
|
|||
{
|
||||
pugi::xml_document doc;
|
||||
doc.load(xml_source);
|
||||
read_worksheet_common(ws, doc.child("worksheet"), shared_string, {});
|
||||
read_worksheet_common(ws, doc.child("worksheet"), shared_string, {}, {});
|
||||
}
|
||||
|
||||
void reader::read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids)
|
||||
void reader::read_worksheet(worksheet ws, const std::string &xml_string, const std::vector<std::string> &string_table, const std::vector<int> &number_format_ids, const std::unordered_map<int, std::string> &custom_number_formats)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
doc.load(xml_string.c_str());
|
||||
read_worksheet_common(ws, doc.child("worksheet"), string_table, number_format_ids);
|
||||
read_worksheet_common(ws, doc.child("worksheet"), string_table, number_format_ids, custom_number_formats);
|
||||
}
|
||||
|
||||
worksheet xlnt::reader::read_worksheet(std::istream &handle, xlnt::workbook &wb, const std::string &title, const std::vector<std::string> &string_table)
|
||||
worksheet xlnt::reader::read_worksheet(std::istream &handle, xlnt::workbook &wb, const std::string &title, const std::vector<std::string> &string_table, const std::unordered_map<int, std::string> &custom_number_formats)
|
||||
{
|
||||
auto ws = wb.create_sheet();
|
||||
ws.set_title(title);
|
||||
pugi::xml_document doc;
|
||||
doc.load(handle);
|
||||
read_worksheet_common(ws, doc.child("worksheet"), string_table, {});
|
||||
read_worksheet_common(ws, doc.child("worksheet"), string_table, {}, custom_number_formats);
|
||||
return ws;
|
||||
}
|
||||
|
||||
|
|
|
@ -149,5 +149,25 @@ std::string style_writer::write_table() const
|
|||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string style_writer::write_number_formats()
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
|
||||
auto root = doc.append_child("styleSheet");
|
||||
root.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
||||
|
||||
auto num_fmts_node = root.append_child("numFmts");
|
||||
num_fmts_node.append_attribute("count").set_value(1);
|
||||
|
||||
auto num_fmt_node = num_fmts_node.append_child("numFmt");
|
||||
num_fmt_node.append_attribute("formatCode").set_value("YYYY");
|
||||
num_fmt_node.append_attribute("numFmtId").set_value(164);
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace xlnt
|
||||
|
|
|
@ -341,6 +341,7 @@ bool workbook::load(xlnt::zip_file &archive)
|
|||
}
|
||||
|
||||
std::vector<int> number_format_ids;
|
||||
std::unordered_map<int, std::string> custom_number_formats;
|
||||
|
||||
if(archive.has_file("xl/styles.xml"))
|
||||
{
|
||||
|
@ -353,6 +354,13 @@ bool workbook::load(xlnt::zip_file &archive)
|
|||
{
|
||||
number_format_ids.push_back(xf_node.attribute("numFmtId").as_int());
|
||||
}
|
||||
|
||||
auto num_fmts_node = stylesheet_node.child("numFmts");
|
||||
|
||||
for(auto num_fmt_node : num_fmts_node.children("numFmt"))
|
||||
{
|
||||
custom_number_formats[num_fmt_node.attribute("numFmtId").as_int()] = num_fmt_node.attribute("formatCode").as_string();
|
||||
}
|
||||
}
|
||||
|
||||
for(auto sheet_node : sheets_node.children("sheet"))
|
||||
|
@ -369,7 +377,7 @@ bool workbook::load(xlnt::zip_file &archive)
|
|||
auto ws = create_sheet(sheet_node.attribute("name").as_string(), *rel);
|
||||
auto sheet_filename = rel->get_target_uri();
|
||||
|
||||
xlnt::reader::read_worksheet(ws, archive.read(sheet_filename).c_str(), shared_strings, number_format_ids);
|
||||
xlnt::reader::read_worksheet(ws, archive.read(sheet_filename).c_str(), shared_strings, number_format_ids, custom_number_formats);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -91,9 +91,9 @@ void excel_writer::write_data(zip_file &archive, bool as_template)
|
|||
|
||||
write_charts(archive);
|
||||
write_images(archive);
|
||||
write_string_table(archive);
|
||||
write_worksheets(archive);
|
||||
write_chartsheets(archive);
|
||||
write_string_table(archive);
|
||||
write_external_links(archive);
|
||||
|
||||
archive.writestr(constants::ArcStyles, style_writer_.write_table());
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <xlnt/xlnt.hpp>
|
||||
#include <xlnt/reader/reader.hpp>
|
||||
|
||||
class test_cell : public CxxTest::TestSuite
|
||||
{
|
||||
|
@ -16,7 +17,7 @@ public:
|
|||
{
|
||||
wb_guess_types.set_guess_types(true);
|
||||
}
|
||||
|
||||
|
||||
void test_infer_numeric()
|
||||
{
|
||||
auto ws = wb_guess_types.create_sheet();
|
||||
|
@ -204,7 +205,7 @@ public:
|
|||
|
||||
cell.set_value(xlnt::datetime::today());
|
||||
cell.clear_value();
|
||||
TS_ASSERT(cell.is_date());
|
||||
TS_ASSERT(!cell.is_date()); // disagree with openpyxl
|
||||
TS_ASSERT(!cell.has_value());
|
||||
}
|
||||
|
||||
|
@ -286,7 +287,7 @@ public:
|
|||
auto ws = wb[1];
|
||||
auto cell = ws.get_cell(xlnt::cell_reference(1, 1));
|
||||
|
||||
TS_ASSERT(cell.to_string() == "<Cell Sheet1.A1>");
|
||||
TS_ASSERT(cell.to_repr() == "<Cell Sheet1.A1>");
|
||||
}
|
||||
|
||||
void test_comment_assignment()
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
xlnt::worksheet ws(wb);
|
||||
{
|
||||
std::ifstream handle(path);
|
||||
ws = xlnt::reader::read_worksheet(handle, wb, "Sheet 2", {"hello"});
|
||||
ws = xlnt::reader::read_worksheet(handle, wb, "Sheet 2", {"hello"}, {});
|
||||
}
|
||||
TS_ASSERT_DIFFERS(ws, nullptr);
|
||||
if(!(ws == nullptr))
|
||||
|
|
|
@ -1,319 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <xlnt/xlnt.hpp>
|
||||
|
||||
class test_style : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
test_style() : writer_(workbook_)
|
||||
{
|
||||
workbook_.set_guess_types(true);
|
||||
auto now = xlnt::datetime::now();
|
||||
auto ws = workbook_.get_active_sheet();
|
||||
ws.get_cell("A1").set_value("12.34%"); // 2
|
||||
ws.get_cell("B1").set_value(now); // 3
|
||||
ws.get_cell("C1").set_value(now);
|
||||
ws.get_cell("D1").set_value("This is a test"); // 1
|
||||
ws.get_cell("E1").set_value("31.31415"); // 3
|
||||
xlnt::style st; // 4
|
||||
st.set_number_format(xlnt::number_format(xlnt::number_format::format::number_00));
|
||||
st.set_protection(xlnt::protection(xlnt::protection::type::unprotected));
|
||||
ws.get_cell("F1").set_style(st);
|
||||
xlnt::style st2; // 5
|
||||
st.set_protection(xlnt::protection(xlnt::protection::type::unprotected));
|
||||
ws.get_cell("G1").set_style(st2);
|
||||
|
||||
}
|
||||
|
||||
void test_create_style_table()
|
||||
{
|
||||
TS_SKIP("");
|
||||
//TS_ASSERT_EQUALS(5, writer_.get_styles().size());
|
||||
}
|
||||
|
||||
void test_write_style_table()
|
||||
{
|
||||
TS_SKIP("");
|
||||
|
||||
/*
|
||||
auto path = PathHelper::GetDataDirectory("/writer/expected/simple-styles.xml");
|
||||
pugi::xml_document expected;
|
||||
expected.load_file(path.c_str());
|
||||
|
||||
auto content = writer_.write_table();
|
||||
pugi::xml_document observed;
|
||||
observed.load(content.c_str());
|
||||
|
||||
auto diff = Helper::compare_xml(expected, observed);
|
||||
TS_ASSERT(diff);
|
||||
*/
|
||||
}
|
||||
|
||||
void test_no_style()
|
||||
{
|
||||
TS_SKIP("");
|
||||
|
||||
/*
|
||||
xlnt::workbook wb;
|
||||
xlnt::style_writer w(wb);
|
||||
TS_ASSERT_EQUALS(w.get_styles().size(), 1); // there is always the empty (default) style
|
||||
*/
|
||||
}
|
||||
|
||||
void test_nb_style()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
void test_style_unicity()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
void test_fonts()
|
||||
{
|
||||
TS_SKIP("");
|
||||
|
||||
/*
|
||||
auto expected =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"
|
||||
" <fonts count=\"2\">"
|
||||
" <font>"
|
||||
" <sz val=\"11\" />"
|
||||
" <color theme=\"1\" />"
|
||||
" <name val=\"Calibri\" />"
|
||||
" <family val=\"2\" />"
|
||||
" <scheme val=\"minor\" />"
|
||||
" </font>"
|
||||
" <font>"
|
||||
" <sz val=\"12.0\" />"
|
||||
" <color rgb=\"00000000\" />"
|
||||
" <name val=\"Calibri\" />"
|
||||
" <family val=\"2\" />"
|
||||
" <b />"
|
||||
" </font>"
|
||||
" </fonts>"
|
||||
"</styleSheet>";
|
||||
|
||||
pugi::xml_document expected_doc;
|
||||
expected_doc.load(expected);
|
||||
|
||||
std::string observed = "";
|
||||
pugi::xml_document observed_doc;
|
||||
observed_doc.load(observed.c_str());
|
||||
|
||||
auto diff = Helper::compare_xml(expected_doc, observed_doc);
|
||||
TS_ASSERT(diff);
|
||||
*/
|
||||
}
|
||||
|
||||
void test_fonts_with_underline()
|
||||
{
|
||||
TS_SKIP("");
|
||||
|
||||
/*
|
||||
auto expected =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"
|
||||
" <fonts count=\"2\">"
|
||||
" <font>"
|
||||
" <sz val=\"11\" />"
|
||||
" <color theme=\"1\" />"
|
||||
" <name val=\"Calibri\" />"
|
||||
" <family val=\"2\" />"
|
||||
" <scheme val=\"minor\" />"
|
||||
" </font>"
|
||||
" <font>"
|
||||
" <sz val=\"12.0\" />"
|
||||
" <color rgb=\"00000000\" />"
|
||||
" <name val=\"Calibri\" />"
|
||||
" <family val=\"2\" />"
|
||||
" <b />"
|
||||
" <u />"
|
||||
" </font>"
|
||||
" </fonts>"
|
||||
"</styleSheet>";
|
||||
|
||||
pugi::xml_document expected_doc;
|
||||
expected_doc.load(expected);
|
||||
|
||||
std::string observed = "";
|
||||
pugi::xml_document observed_doc;
|
||||
observed_doc.load(observed.c_str());
|
||||
|
||||
auto diff = Helper::compare_xml(expected_doc, observed_doc);
|
||||
TS_ASSERT(diff);
|
||||
*/
|
||||
}
|
||||
|
||||
void test_fills()
|
||||
{
|
||||
TS_SKIP("");
|
||||
|
||||
/*
|
||||
auto expected =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"
|
||||
" <fills count=\"3\">"
|
||||
" <fill>"
|
||||
" <patternFill patternType=\"none\" />"
|
||||
" </fill>"
|
||||
" <fill>"
|
||||
" <patternFill patternType=\"gray125\" />"
|
||||
" </fill>"
|
||||
" <fill>"
|
||||
" <patternFill patternType=\"solid\">"
|
||||
" <fgColor rgb=\"0000FF00\" />"
|
||||
" </patternFill>"
|
||||
" </fill>"
|
||||
" </fills>"
|
||||
"</styleSheet>";
|
||||
|
||||
pugi::xml_document expected_doc;
|
||||
expected_doc.load(expected);
|
||||
|
||||
std::string observed = "";
|
||||
pugi::xml_document observed_doc;
|
||||
observed_doc.load(observed.c_str());
|
||||
|
||||
auto diff = Helper::compare_xml(expected_doc, observed_doc);
|
||||
TS_ASSERT(diff);
|
||||
*/
|
||||
}
|
||||
|
||||
void test_borders()
|
||||
{
|
||||
TS_SKIP("");
|
||||
|
||||
/*
|
||||
auto expected =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"
|
||||
" <borders count=\"2\">"
|
||||
" <border>"
|
||||
" <left />"
|
||||
" <right />"
|
||||
" <top />"
|
||||
" <bottom />"
|
||||
" <diagonal />"
|
||||
" </border>"
|
||||
" <border>"
|
||||
" <left />"
|
||||
" <right />"
|
||||
" <top style=\"thin\">"
|
||||
" <color rgb=\"0000FF00\" />"
|
||||
" </top>"
|
||||
" <bottom />"
|
||||
" <diagonal />"
|
||||
" </border>"
|
||||
" </borders>"
|
||||
"</styleSheet>";
|
||||
|
||||
pugi::xml_document expected_doc;
|
||||
expected_doc.load(expected);
|
||||
|
||||
std::string observed = "";
|
||||
pugi::xml_document observed_doc;
|
||||
observed_doc.load(observed.c_str());
|
||||
|
||||
auto diff = Helper::compare_xml(expected_doc, observed_doc);
|
||||
TS_ASSERT(diff);
|
||||
*/
|
||||
}
|
||||
|
||||
void test_write_color()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
void test_write_cell_xfs_1()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
void test_alignment()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
void test_alignment_rotation()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
void test_alignment_indent()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
void test_rewrite_styles()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
void test_write_dxf()
|
||||
{
|
||||
TS_SKIP("");
|
||||
|
||||
/*
|
||||
auto expected =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"
|
||||
" <dxfs count=\"1\">"
|
||||
" <dxf>"
|
||||
" <font>"
|
||||
" <color rgb=\"FFFFFFFF\" />"
|
||||
" <b val=\"1\" />"
|
||||
" <i val=\"1\" />"
|
||||
" <u val=\"single\" />"
|
||||
" <strike />"
|
||||
" </font>"
|
||||
" <fill>"
|
||||
" <patternFill patternType=\"solid\">"
|
||||
" <fgColor rgb=\"FFEE1111\" />"
|
||||
" <bgColor rgb=\"FFEE1111\" />"
|
||||
" </patternFill>"
|
||||
" </fill>"
|
||||
" <border>"
|
||||
" <left style=\"medium\">"
|
||||
" <color rgb=\"000000FF\" />"
|
||||
" </left>"
|
||||
" <right style=\"medium\">"
|
||||
" <color rgb=\"000000FF\" />"
|
||||
" </right>"
|
||||
" <top style=\"medium\">"
|
||||
" <color rgb=\"000000FF\" />"
|
||||
" </top>"
|
||||
" <bottom style=\"medium\">"
|
||||
" <color rgb=\"000000FF\" />"
|
||||
" </bottom>"
|
||||
" </border>"
|
||||
" </dxf>"
|
||||
" </dxfs>"
|
||||
"</styleSheet>";
|
||||
|
||||
pugi::xml_document expected_doc;
|
||||
expected_doc.load(expected);
|
||||
|
||||
std::string observed = "";
|
||||
pugi::xml_document observed_doc;
|
||||
observed_doc.load(observed.c_str());
|
||||
|
||||
auto diff = Helper::compare_xml(expected_doc, observed_doc);
|
||||
TS_ASSERT(diff);
|
||||
*/
|
||||
}
|
||||
|
||||
void test_protection()
|
||||
{
|
||||
TS_SKIP("");
|
||||
}
|
||||
|
||||
private:
|
||||
xlnt::workbook workbook_;
|
||||
xlnt::style_writer writer_;
|
||||
};
|
284
tests/test_style_writer.hpp
Normal file
284
tests/test_style_writer.hpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include <xlnt/xlnt.hpp>
|
||||
|
||||
class test_style_writer : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
void test_write_number_formats()
|
||||
{
|
||||
xlnt::workbook wb;
|
||||
wb.add_number_format("YYYY");
|
||||
xlnt::style_writer writer(wb);
|
||||
auto xml = writer.write_number_formats();
|
||||
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);
|
||||
TS_ASSERT(diff);
|
||||
}
|
||||
/*
|
||||
class TestStyleWriter(object):
|
||||
|
||||
void setup(self):
|
||||
self.workbook = Workbook()
|
||||
self.worksheet = self.workbook.create_sheet()
|
||||
|
||||
void _test_no_style(self):
|
||||
w = StyleWriter(self.workbook)
|
||||
assert len(w.wb._cell_styles) == 1 # there is always the empty (defaul) style
|
||||
|
||||
void _test_nb_style(self):
|
||||
for i in range(1, 6):
|
||||
cell = self.worksheet.cell(row=1, column=i)
|
||||
cell.font = Font(size=i)
|
||||
_ = cell.style_id
|
||||
w = StyleWriter(self.workbook)
|
||||
assert len(w.wb._cell_styles) == 6 # 5 + the default
|
||||
|
||||
cell = self.worksheet.cell('A10')
|
||||
cell.border=Border(top=Side(border_style=borders.BORDER_THIN))
|
||||
_ = cell.style_id
|
||||
w = StyleWriter(self.workbook)
|
||||
assert len(w.wb._cell_styles) == 7
|
||||
|
||||
|
||||
void _test_default_xfs(self):
|
||||
w = StyleWriter(self.workbook)
|
||||
fonts = nft = borders = fills = DummyElement()
|
||||
w._write_cell_styles()
|
||||
xml = tostring(w._root)
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<cellXfs count="1">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0"/>
|
||||
</cellXfs>
|
||||
</styleSheet>
|
||||
"""
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
void _test_xfs_number_format(self):
|
||||
for idx, nf in enumerate(["0.0%", "0.00%", "0.000%"], 1):
|
||||
cell = self.worksheet.cell(row=idx, column=1)
|
||||
cell.number_format = nf
|
||||
_ = cell.style_id # add to workbook styles
|
||||
w = StyleWriter(self.workbook)
|
||||
w._write_cell_styles()
|
||||
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<cellXfs count="4">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0"/>
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="164" xfId="0"/>
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="10" xfId="0"/>
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="165" xfId="0"/>
|
||||
</cellXfs>
|
||||
</styleSheet>
|
||||
"""
|
||||
|
||||
xml = tostring(w._root)
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
void _test_xfs_fonts(self):
|
||||
cell = self.worksheet.cell('A1')
|
||||
cell.font = Font(size=12, bold=True)
|
||||
_ = cell.style_id # update workbook styles
|
||||
w = StyleWriter(self.workbook)
|
||||
|
||||
w._write_cell_styles()
|
||||
xml = tostring(w._root)
|
||||
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<cellXfs count="2">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0"/>
|
||||
<xf borderId="0" fillId="0" fontId="1" numFmtId="0" xfId="0"/>
|
||||
</cellXfs>
|
||||
</styleSheet>
|
||||
"""
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
void _test_xfs_fills(self):
|
||||
cell = self.worksheet.cell('A1')
|
||||
cell.fill = fill=PatternFill(fill_type='solid',
|
||||
start_color=Color(colors.DARKYELLOW))
|
||||
_ = cell.style_id # update workbook styles
|
||||
w = StyleWriter(self.workbook)
|
||||
w._write_cell_styles()
|
||||
|
||||
xml = tostring(w._root)
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<cellXfs count="2">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0"/>
|
||||
<xf borderId="0" fillId="2" fontId="0" numFmtId="0" xfId="0"/>
|
||||
</cellXfs>
|
||||
</styleSheet>
|
||||
"""
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
void _test_xfs_borders(self):
|
||||
cell = self.worksheet.cell('A1')
|
||||
cell.border=Border(top=Side(border_style=borders.BORDER_THIN,
|
||||
color=Color(colors.DARKYELLOW)))
|
||||
_ = cell.style_id # update workbook styles
|
||||
|
||||
w = StyleWriter(self.workbook)
|
||||
w._write_cell_styles()
|
||||
|
||||
xml = tostring(w._root)
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<cellXfs count="2">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0"/>
|
||||
<xf borderId="1" fillId="0" fontId="0" numFmtId="0" xfId="0"/>
|
||||
</cellXfs>
|
||||
</styleSheet>
|
||||
"""
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
void _test_protection(self):
|
||||
cell = self.worksheet.cell('A1')
|
||||
cell.protection = Protection(locked=True, hidden=True)
|
||||
_ = cell.style_id
|
||||
|
||||
w = StyleWriter(self.workbook)
|
||||
w._write_cell_styles()
|
||||
xml = tostring(w._root)
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<cellXfs count="2">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0"/>
|
||||
<xf applyProtection="1" borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0">
|
||||
<protection hidden="1" locked="1"/>
|
||||
</xf>
|
||||
</cellXfs>
|
||||
</styleSheet>
|
||||
"""
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
void _test_named_styles(self):
|
||||
writer = StyleWriter(self.workbook)
|
||||
writer._write_named_styles()
|
||||
xml = tostring(writer._root)
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<cellStyleXfs count="1">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0"></xf>
|
||||
</cellStyleXfs>
|
||||
</styleSheet>
|
||||
"""
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
void _test_style_names(self):
|
||||
writer = StyleWriter(self.workbook)
|
||||
writer._write_style_names()
|
||||
xml = tostring(writer._root)
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<cellStyles count="1">
|
||||
<cellStyle name="Normal" xfId="0" builtinId="0" hidden="0"/>
|
||||
</cellStyles>
|
||||
</styleSheet>
|
||||
"""
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
|
||||
void _test_simple_styles(datadir):
|
||||
wb = Workbook(guess_types=True)
|
||||
ws = wb.active
|
||||
now = datetime.datetime.now()
|
||||
for idx, v in enumerate(['12.34%', now, 'This is a test', '31.31415', None], 1):
|
||||
ws.append([v])
|
||||
_ = ws.cell(column=1, row=idx).style_id
|
||||
|
||||
# set explicit formats
|
||||
ws['D9'].number_format = numbers.FORMAT_NUMBER_00
|
||||
ws['D9'].protection = Protection(locked=True)
|
||||
ws['D9'].style_id
|
||||
ws['E1'].protection = Protection(hidden=True)
|
||||
ws['E1'].style_id
|
||||
|
||||
assert len(wb._cell_styles) == 5
|
||||
writer = StyleWriter(wb)
|
||||
|
||||
datadir.chdir()
|
||||
with open('simple-styles.xml') as reference_file:
|
||||
expected = reference_file.read()
|
||||
xml = writer.write_table()
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
|
||||
|
||||
void _test_empty_workbook():
|
||||
wb = Workbook()
|
||||
writer = StyleWriter(wb)
|
||||
expected = """
|
||||
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<numFmts count="0"/>
|
||||
<fonts count="1">
|
||||
<font>
|
||||
<name val="Calibri"/>
|
||||
<family val="2"/>
|
||||
<color theme="1"/>
|
||||
<sz val="11"/>
|
||||
<scheme val="minor"/>
|
||||
</font>
|
||||
</fonts>
|
||||
<fills count="2">
|
||||
<fill>
|
||||
<patternFill />
|
||||
</fill>
|
||||
<fill>
|
||||
<patternFill patternType="gray125"/>
|
||||
</fill>
|
||||
</fills>
|
||||
<borders count="1">
|
||||
<border>
|
||||
<left/>
|
||||
<right/>
|
||||
<top/>
|
||||
<bottom/>
|
||||
<diagonal/>
|
||||
</border>
|
||||
</borders>
|
||||
<cellStyleXfs count="1">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0"/>
|
||||
</cellStyleXfs>
|
||||
<cellXfs count="1">
|
||||
<xf borderId="0" fillId="0" fontId="0" numFmtId="0" xfId="0"/>
|
||||
</cellXfs>
|
||||
<cellStyles count="1">
|
||||
<cellStyle builtinId="0" name="Normal" xfId="0" hidden="0"/>
|
||||
</cellStyles>
|
||||
<dxfs count="0"/>
|
||||
<tableStyles count="0" defaultPivotStyle="PivotStyleLight16" defaultTableStyle="TableStyleMedium9"/>
|
||||
</styleSheet>
|
||||
"""
|
||||
xml = writer.write_table()
|
||||
diff = compare_xml(xml, expected)
|
||||
assert diff is None, diff
|
||||
*/
|
||||
};
|
|
@ -138,13 +138,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void test_worksheet_recwarn()
|
||||
{
|
||||
xlnt::worksheet ws(wb_);
|
||||
auto rows = ws.get_range("A1:D4");
|
||||
TS_SKIP(""); // what's recwarn?
|
||||
}
|
||||
|
||||
void test_get_named_range()
|
||||
{
|
||||
xlnt::worksheet ws(wb_);
|
||||
|
|
Loading…
Reference in New Issue
Block a user