fix some xlsx consumption and production

This commit is contained in:
Thomas Fussell 2016-10-13 20:11:02 -04:00
parent cf019f6af6
commit 4d20ccaa67
7 changed files with 107 additions and 33 deletions

View File

@ -52,7 +52,7 @@ public:
optional<int> rotation() const; optional<int> rotation() const;
alignment &rotation(bool text_rotation); alignment &rotation(int text_rotation);
optional<horizontal_alignment> horizontal() const; optional<horizontal_alignment> horizontal() const;

View File

@ -54,6 +54,10 @@ public:
bool bold() const; bool bold() const;
font &superscript(bool superscript);
bool superscript() const;
font &italic(bool italic); font &italic(bool italic);
bool italic() const; bool italic() const;

View File

@ -673,9 +673,11 @@ void xlsx_consumer::read_pivot_table()
void xlsx_consumer::read_shared_string_table() void xlsx_consumer::read_shared_string_table()
{ {
static const auto xmlns = constants::get_namespace("shared-strings"); static const auto xmlns = constants::get_namespace("worksheet");
parser().next_expect(xml::parser::event_type::start_element, xmlns, "sst"); parser().next_expect(xml::parser::event_type::start_element, xmlns, "sst");
parser().content(xml::content::complex);
std::size_t unique_count = 0; std::size_t unique_count = 0;
if (parser().attribute_present("uniqueCount")) if (parser().attribute_present("uniqueCount"))
@ -690,12 +692,14 @@ void xlsx_consumer::read_shared_string_table()
if (parser().peek() == xml::parser::event_type::end_element) break; if (parser().peek() == xml::parser::event_type::end_element) break;
parser().next_expect(xml::parser::event_type::start_element, xmlns, "si"); parser().next_expect(xml::parser::event_type::start_element, xmlns, "si");
parser().content(xml::content::complex);
parser().next_expect(xml::parser::event_type::start_element); parser().next_expect(xml::parser::event_type::start_element);
text t; text t;
if (parser().name() == "t") if (parser().name() == "t")
{ {
parser().next_expect(xml::parser::event_type::characters);
t.set_plain_string(parser().value()); t.set_plain_string(parser().value());
} }
else if (parser().name() == "r") // possible multiple text entities. else if (parser().name() == "r") // possible multiple text entities.
@ -705,8 +709,8 @@ void xlsx_consumer::read_shared_string_table()
if (parser().peek() == xml::parser::event_type::end_element) break; if (parser().peek() == xml::parser::event_type::end_element) break;
parser().next_expect(xml::parser::event_type::start_element, xmlns, "t"); parser().next_expect(xml::parser::event_type::start_element, xmlns, "t");
parser().next_expect(xml::parser::event_type::characters);
text_run run; text_run run;
run.set_string(parser().value()); run.set_string(parser().value());
if (parser().peek() == xml::parser::event_type::start_element) if (parser().peek() == xml::parser::event_type::start_element)
@ -740,7 +744,7 @@ void xlsx_consumer::read_shared_string_table()
run.set_scheme(parser().attribute("val")); run.set_scheme(parser().attribute("val"));
} }
parser().next_expect(xml::parser::event_type::end_element, parser().qname()); parser().next_expect(xml::parser::event_type::end_element);
} }
} }
@ -748,6 +752,8 @@ void xlsx_consumer::read_shared_string_table()
} }
} }
parser().next_expect(xml::parser::event_type::end_element);
parser().next_expect(xml::parser::event_type::end_element);
strings.push_back(t); strings.push_back(t);
} }
@ -1022,6 +1028,10 @@ void xlsx_consumer::read_stylesheet()
new_font.bold(true); new_font.bold(true);
} }
} }
else if (parser().name() == "vertAlign")
{
new_font.superscript(parser().attribute("val") == "superscript");
}
else if (parser().name() == "strike") else if (parser().name() == "strike")
{ {
if (parser().attribute_present("val")) if (parser().attribute_present("val"))
@ -1127,6 +1137,7 @@ void xlsx_consumer::read_stylesheet()
if (parser().peek() == xml::parser::event_type::end_element) break; if (parser().peek() == xml::parser::event_type::end_element) break;
parser().next_expect(xml::parser::event_type::start_element, xmlns, "xf"); parser().next_expect(xml::parser::event_type::start_element, xmlns, "xf");
parser().content(xml::content::complex);
auto &record = *(!in_style_records auto &record = *(!in_style_records
? format_records.emplace(format_records.end()) ? format_records.emplace(format_records.end())
@ -1179,8 +1190,25 @@ void xlsx_consumer::read_stylesheet()
if (parser().qname() == xml::qname(xmlns, "alignment")) if (parser().qname() == xml::qname(xmlns, "alignment"))
{ {
record.alignment.first.wrap(is_true(parser().attribute("wrapText"))); if (parser().attribute_present("wrapText"))
record.alignment.first.shrink(is_true(parser().attribute("shrinkToFit"))); {
record.alignment.first.wrap(is_true(parser().attribute("wrapText")));
}
if (parser().attribute_present("shrinkToFit"))
{
record.alignment.first.shrink(is_true(parser().attribute("shrinkToFit")));
}
if (parser().attribute_present("indent"))
{
record.alignment.first.indent(parser().attribute<int>("indent"));
}
if (parser().attribute_present("textRotation"))
{
record.alignment.first.rotation(parser().attribute<int>("textRotation"));
}
if (parser().attribute_present("vertical")) if (parser().attribute_present("vertical"))
{ {
@ -1462,6 +1490,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
if (parser().peek() == xml::parser::event_type::end_element) break; if (parser().peek() == xml::parser::event_type::end_element) break;
parser().next_expect(xml::parser::event_type::start_element, xmlns, "row"); parser().next_expect(xml::parser::event_type::start_element, xmlns, "row");
parser().content(xml::content::complex);
auto row_index = static_cast<row_t>(std::stoull(parser().attribute("r"))); auto row_index = static_cast<row_t>(std::stoull(parser().attribute("r")));
@ -1470,6 +1499,16 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
ws.get_row_properties(row_index).height = std::stold(parser().attribute("ht")); ws.get_row_properties(row_index).height = std::stold(parser().attribute("ht"));
} }
if (parser().attribute_present("customHeight"))
{
ws.get_row_properties(row_index).height = std::stold(parser().attribute("customHeight"));
}
if (parser().attribute_present(xml::qname(xmlns_x14ac, "dyDescent")))
{
parser().attribute(xml::qname(xmlns_x14ac, "dyDescent"));
}
std::string span_string = parser().attribute("spans"); std::string span_string = parser().attribute("spans");
auto colon_index = span_string.find(':'); auto colon_index = span_string.find(':');
@ -1492,6 +1531,7 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
if (parser().peek() == xml::parser::event_type::end_element) break; if (parser().peek() == xml::parser::event_type::end_element) break;
parser().next_expect(xml::parser::event_type::start_element, xmlns, "c"); parser().next_expect(xml::parser::event_type::start_element, xmlns, "c");
parser().content(xml::content::complex);
auto cell = ws.get_cell(cell_reference(parser().attribute("r"))); auto cell = ws.get_cell(cell_reference(parser().attribute("r")));
auto has_type = parser().attribute_present("t"); auto has_type = parser().attribute_present("t");
@ -1516,22 +1556,26 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
if (parser().qname() == xml::qname(xmlns, "v")) if (parser().qname() == xml::qname(xmlns, "v"))
{ {
has_value = true; has_value = true;
parser().next_expect(xml::parser::event_type::characters);
value_string = parser().value(); value_string = parser().value();
} }
else if (parser().qname() == xml::qname(xmlns, "f")) else if (parser().qname() == xml::qname(xmlns, "f"))
{ {
has_formula = true; has_formula = true;
has_shared_formula = parser().attribute_present("t") && parser().attribute("t") == "shared"; has_shared_formula = parser().attribute_present("t")
&& parser().attribute("t") == "shared";
parser().next_expect(xml::parser::event_type::characters);
formula_value_string = parser().value(); formula_value_string = parser().value();
} }
else if (parser().qname() == xml::qname(xmlns, "is")) else if (parser().qname() == xml::qname(xmlns, "is"))
{ {
parser().next_expect(xml::parser::event_type::start_element, xmlns, "t"); parser().next_expect(xml::parser::event_type::start_element, xmlns, "t");
parser().next_expect(xml::parser::event_type::characters);
value_string = parser().value(); value_string = parser().value();
parser().next_expect(xml::parser::event_type::end_element, xmlns, "t"); parser().next_expect(xml::parser::event_type::end_element, xmlns, "t");
} }
parser().next_expect(xml::parser::event_type::end_element, parser().qname()); parser().next_expect(xml::parser::event_type::end_element);
} }
if (has_formula && !has_shared_formula && !ws.get_workbook().get_data_only()) if (has_formula && !has_shared_formula && !ws.get_workbook().get_data_only())
@ -1572,6 +1616,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
parser().next_expect(xml::parser::event_type::end_element, xmlns, "c"); parser().next_expect(xml::parser::event_type::end_element, xmlns, "c");
} }
parser().next_expect(xml::parser::event_type::end_element, xmlns, "row");
} }
parser().next_expect(xml::parser::event_type::end_element, xmlns, "sheetData"); parser().next_expect(xml::parser::event_type::end_element, xmlns, "sheetData");
@ -1602,6 +1648,11 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
ws.get_column_properties(min).custom = custom; ws.get_column_properties(min).custom = custom;
} }
if (parser().attribute_present("bestFit"))
{
parser().attribute("bestFit");
}
parser().next_expect(xml::parser::event_type::end_element, xmlns, "col"); parser().next_expect(xml::parser::event_type::end_element, xmlns, "col");
} }

View File

@ -758,9 +758,19 @@ void xlsx_producer::write_styles(const relationship &rel)
serializer().start_element(xmlns, "fonts"); serializer().start_element(xmlns, "fonts");
serializer().attribute("count", fonts.size()); serializer().attribute("count", fonts.size());
auto num_known_fonts = std::count_if(fonts.begin(), fonts.end(), [](const xlnt::font &f)
{
static const auto known_fonts = std::vector<xlnt::font>
{
xlnt::font().color(xlnt::theme_color(1)).scheme("minor").family(2)
};
return std::find(known_fonts.begin(), known_fonts.end(), f) != known_fonts.end();
});
if (source_.x15_enabled()) if (source_.x15_enabled())
{ {
serializer().attribute(xmlns_x14ac, "knownFonts", fonts.size()); serializer().attribute(xmlns_x14ac, "knownFonts", num_known_fonts);
} }
for (const auto &current_font : fonts) for (const auto &current_font : fonts)
@ -999,7 +1009,7 @@ void xlsx_producer::write_styles(const relationship &rel)
{ {
const auto current_alignment = current_style.alignment(); const auto current_alignment = current_style.alignment();
serializer().start_element("alignment"); serializer().start_element(xmlns, "alignment");
if (current_alignment.vertical()) if (current_alignment.vertical())
{ {
@ -1031,17 +1041,17 @@ void xlsx_producer::write_styles(const relationship &rel)
serializer().attribute("shrinkToFit", write_bool(*current_alignment.shrink())); serializer().attribute("shrinkToFit", write_bool(*current_alignment.shrink()));
} }
serializer().end_element("alignment"); serializer().end_element(xmlns, "alignment");
} }
if (current_style.protection_applied()) if (current_style.protection_applied())
{ {
const auto current_protection = current_style.protection(); const auto current_protection = current_style.protection();
serializer().start_element("protection"); serializer().start_element(xmlns, "protection");
serializer().attribute("locked", write_bool(current_protection.locked())); serializer().attribute("locked", write_bool(current_protection.locked()));
serializer().attribute("hidden", write_bool(current_protection.hidden())); serializer().attribute("hidden", write_bool(current_protection.hidden()));
serializer().end_element("protection"); serializer().end_element(xmlns, "protection");
} }
serializer().end_element(xmlns, "xf"); serializer().end_element(xmlns, "xf");
@ -1072,11 +1082,18 @@ void xlsx_producer::write_styles(const relationship &rel)
if (current_format.alignment_applied()) serializer().attribute("applyAlignment", write_bool(true)); if (current_format.alignment_applied()) serializer().attribute("applyAlignment", write_bool(true));
if (current_format.protection_applied()) serializer().attribute("applyProtection", write_bool(true)); if (current_format.protection_applied()) serializer().attribute("applyProtection", write_bool(true));
if (current_format.has_style())
{
serializer().attribute("xfId", std::distance(stylesheet.styles.begin(),
std::find_if(stylesheet.styles.begin(), stylesheet.styles.end(),
[&](const xlnt::style &s) { return s.name() == current_format.style().name(); })));
}
if (current_format.alignment_applied()) if (current_format.alignment_applied())
{ {
const auto current_alignment = current_format.alignment(); const auto current_alignment = current_format.alignment();
serializer().start_element("alignment"); serializer().start_element(xmlns, "alignment");
if (current_alignment.vertical()) if (current_alignment.vertical())
{ {
@ -1108,24 +1125,17 @@ void xlsx_producer::write_styles(const relationship &rel)
serializer().attribute("shrinkToFit", write_bool(*current_alignment.shrink())); serializer().attribute("shrinkToFit", write_bool(*current_alignment.shrink()));
} }
serializer().end_element("alignment"); serializer().end_element(xmlns, "alignment");
} }
if (current_format.protection_applied()) if (current_format.protection_applied())
{ {
const auto current_protection = current_format.protection(); const auto current_protection = current_format.protection();
serializer().start_element("protection"); serializer().start_element(xmlns, "protection");
serializer().attribute("locked", write_bool(current_protection.locked())); serializer().attribute("locked", write_bool(current_protection.locked()));
serializer().attribute("hidden", write_bool(current_protection.hidden())); serializer().attribute("hidden", write_bool(current_protection.hidden()));
serializer().end_element("protection"); serializer().end_element(xmlns, "protection");
}
if (current_format.has_style())
{
serializer().attribute("xfId", std::distance(stylesheet.styles.begin(),
std::find_if(stylesheet.styles.begin(), stylesheet.styles.end(),
[&](const xlnt::style &s) { return s.name() == current_format.style().name(); })));
} }
serializer().end_element(xmlns, "xf"); serializer().end_element(xmlns, "xf");
@ -1845,13 +1855,13 @@ void xlsx_producer::write_worksheet(const relationship &rel)
const auto &props = ws.get_column_properties(column); const auto &props = ws.get_column_properties(column);
serializer().end_element(xmlns, "col"); serializer().start_element(xmlns, "col");
serializer().attribute("min", column.index); serializer().attribute("min", column.index);
serializer().attribute("max", column.index); serializer().attribute("max", column.index);
serializer().attribute("width", props.width); serializer().attribute("width", props.width);
serializer().attribute("style", props.style); serializer().attribute("style", props.style);
serializer().attribute("customWidth", write_bool(props.custom)); serializer().attribute("customWidth", write_bool(props.custom));
serializer().end_element(xmlns, "cols"); serializer().end_element(xmlns, "col");
} }
serializer().end_element(xmlns, "cols"); serializer().end_element(xmlns, "cols");

View File

@ -81,9 +81,9 @@ optional<int> alignment::indent() const
return indent_; return indent_;
} }
alignment &alignment::rotation(bool value) alignment &alignment::rotation(int value)
{ {
text_rotation_ = 0; text_rotation_ = value;
return *this; return *this;
} }

View File

@ -50,6 +50,17 @@ bool font::bold() const
return bold_; return bold_;
} }
font &font::superscript(bool superscript)
{
superscript_ = superscript;
return *this;
}
bool font::superscript() const
{
return superscript_;
}
font &font::italic(bool italic) font &font::italic(bool italic)
{ {
italic_ = italic; italic_ = italic;

View File

@ -93,7 +93,6 @@ public:
void test_round_trip_empty_excel_rw() void test_round_trip_empty_excel_rw()
{ {
TS_SKIP("");
auto path = path_helper::get_data_directory("9_default-excel.xlsx"); auto path = path_helper::get_data_directory("9_default-excel.xlsx");
TS_ASSERT(round_trip_matches_rw(path)); TS_ASSERT(round_trip_matches_rw(path));
} }
@ -107,13 +106,12 @@ public:
void test_round_trip_all_styles_rw() void test_round_trip_all_styles_rw()
{ {
TS_SKIP("");
auto path = path_helper::get_data_directory("13_all_styles.xlsx"); auto path = path_helper::get_data_directory("13_all_styles.xlsx");
xlnt::workbook original_workbook; xlnt::workbook original_workbook;
original_workbook.load(path); original_workbook.load(path);
std::vector<std::uint8_t> buffer; std::vector<std::uint8_t> buffer;
original_workbook.save(buffer); original_workbook.save(buffer);
// TS_ASSERT(round_trip_matches_rw(path)); //TS_ASSERT(round_trip_matches_rw(path));
} }
}; };