implement abspath and archid flags, fixes some serialization problems

This commit is contained in:
Thomas Fussell 2018-05-28 23:13:57 -04:00
parent 6eb16243ca
commit e350a7734d
11 changed files with 139 additions and 30 deletions

View File

@ -67,7 +67,7 @@ public:
/// Clears any runs in this text and adds a single run with default formatting and /// Clears any runs in this text and adds a single run with default formatting and
/// the given string as its textual content. /// the given string as its textual content.
/// </summary> /// </summary>
void plain_text(const std::string &s); void plain_text(const std::string &s, bool preserve_space);
/// <summary> /// <summary>
/// Combines the textual content of each text run in order and returns the result. /// Combines the textual content of each text run in order and returns the result.

View File

@ -38,6 +38,7 @@ struct rich_text_run
{ {
std::string first; std::string first;
optional<font> second; optional<font> second;
bool preserve_space;
bool operator==(const rich_text_run &other) const; bool operator==(const rich_text_run &other) const;

View File

@ -390,6 +390,16 @@ public:
/// </summary> /// </summary>
void title(const std::string &title); void title(const std::string &title);
/// <summary>
/// Sets the absolute path of this workbook to path.
/// </summary>
void abs_path(const std::string &path);
/// <summary>
/// Sets the ArchID flags of this workbook to flags.
/// </summary>
void arch_id_flags(const std::size_t flags);
// Named Ranges // Named Ranges
/// <summary> /// <summary>

View File

@ -468,7 +468,7 @@ void cell::error(const std::string &error)
throw invalid_data_type(); throw invalid_data_type();
} }
d_->value_text_.plain_text(error); d_->value_text_.plain_text(error, false);
d_->type_ = type::error; d_->type_ = type::error;
} }

View File

@ -38,7 +38,7 @@ comment::comment(const rich_text &text, const std::string &author)
comment::comment(const std::string &text, const std::string &author) comment::comment(const std::string &text, const std::string &author)
: text_(), author_(author) : text_(), author_(author)
{ {
text_.plain_text(text); text_.plain_text(text, false);
} }
rich_text comment::text() const rich_text comment::text() const

View File

@ -48,10 +48,10 @@ void rich_text::clear()
runs_.clear(); runs_.clear();
} }
void rich_text::plain_text(const std::string &s) void rich_text::plain_text(const std::string &s, bool preserve_space = false)
{ {
clear(); clear();
add_run(rich_text_run{s, {}}); add_run(rich_text_run{s, {}, preserve_space});
} }
std::string rich_text::plain_text() const std::string rich_text::plain_text() const

View File

@ -121,6 +121,8 @@ struct workbook_impl
optional<file_version_t> file_version_; optional<file_version_t> file_version_;
optional<calculation_properties> calculation_properties_; optional<calculation_properties> calculation_properties_;
optional<std::string> abs_path_;
optional<std::size_t> arch_id_flags_;
}; };
} // namespace detail } // namespace detail

View File

@ -1504,6 +1504,31 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
{ {
skip_remaining_content(current_workbook_element); skip_remaining_content(current_workbook_element);
} }
else if (current_workbook_element == qn("mc", "AlternateContent"))
{
while (in_element(qn("mc", "AlternateContent")))
{
auto alternate_content_element = expect_start_element(xml::content::complex);
if (alternate_content_element == qn("mc", "Choice")
&& parser().attribute_present("Requires")
&& parser().attribute("Requires") == "x15")
{
auto x15_element = expect_start_element(xml::content::simple);
if (x15_element == qn("x15ac", "absPath"))
{
target_.d_->abs_path_ = parser().attribute("url");
}
skip_remaining_content(x15_element);
expect_end_element(x15_element);
}
skip_remaining_content(alternate_content_element);
expect_end_element(alternate_content_element);
}
}
else if (current_workbook_element == qn("workbook", "workbookPr")) // CT_WorkbookPr 0-1 else if (current_workbook_element == qn("workbook", "workbookPr")) // CT_WorkbookPr 0-1
{ {
target_.base_date(parser().attribute_present("date1904") // optional, bool=false target_.base_date(parser().attribute_present("date1904") // optional, bool=false
@ -1656,11 +1681,28 @@ void xlsx_consumer::read_office_document(const std::string &content_type) // CT_
} }
else if (current_workbook_element == qn("workbook", "extLst")) // CT_ExtensionList 0-1 else if (current_workbook_element == qn("workbook", "extLst")) // CT_ExtensionList 0-1
{ {
skip_remaining_content(current_workbook_element); while (in_element(qn("workbook", "extLst")))
}
else if (current_workbook_element == qn("mc", "AlternateContent"))
{ {
skip_remaining_content(current_workbook_element); auto extension_element = expect_start_element(xml::content::complex);
if (extension_element == qn("workbook", "ext")
&& parser().attribute_present("uri")
&& parser().attribute("uri") == "{7523E5D3-25F3-A5E0-1632-64F254C22452}")
{
auto arch_id_extension_element = expect_start_element(xml::content::simple);
if (arch_id_extension_element == qn("mx", "ArchID"))
{
target_.d_->arch_id_flags_ = parser().attribute<std::size_t>("Flags");
}
skip_remaining_content(arch_id_extension_element);
expect_end_element(arch_id_extension_element);
}
skip_remaining_content(extension_element);
expect_end_element(extension_element);
}
} }
else else
{ {
@ -2735,12 +2777,15 @@ rich_text xlsx_consumer::read_rich_text(const xml::qname &parent)
while (in_element(parent)) while (in_element(parent))
{ {
auto text_element = expect_start_element(xml::content::mixed); auto text_element = expect_start_element(xml::content::mixed);
const auto xml_space = qn("xml", "space");
const auto preserve_space = parser().attribute_present(xml_space)
? parser().attribute(xml_space) == "preserve" : false;
skip_attributes(); skip_attributes();
auto text = read_text(); auto text = read_text();
if (text_element == xml::qname(xmlns, "t")) if (text_element == xml::qname(xmlns, "t"))
{ {
t.plain_text(text); t.plain_text(text, preserve_space);
} }
else if (text_element == xml::qname(xmlns, "r")) else if (text_element == xml::qname(xmlns, "r"))
{ {

View File

@ -462,11 +462,22 @@ void xlsx_producer::write_workbook(const relationship &rel)
static const auto &xmlns = constants::ns("workbook"); static const auto &xmlns = constants::ns("workbook");
static const auto &xmlns_r = constants::ns("r"); static const auto &xmlns_r = constants::ns("r");
static const auto &xmlns_s = constants::ns("spreadsheetml"); static const auto &xmlns_s = constants::ns("spreadsheetml");
static const auto &xmlns_mx = constants::ns("mx");
static const auto &xmlns_x15ac = constants::ns("x15ac");
static const auto &xmlns_x15 = constants::ns("x15");
static const auto &xmlns_mc = constants::ns("mc");
write_start_element(xmlns, "workbook"); write_start_element(xmlns, "workbook");
write_namespace(xmlns, ""); write_namespace(xmlns, "");
write_namespace(xmlns_r, "r"); write_namespace(xmlns_r, "r");
if (source_.d_->abs_path_.is_set())
{
write_namespace(xmlns_mc, "mc");
write_namespace(xmlns_x15, "x15");
write_attribute(xml::qname(xmlns_mc, "Ignorable"), "x15");
}
if (source_.has_file_version()) if (source_.has_file_version())
{ {
write_start_element(xmlns, "fileVersion"); write_start_element(xmlns, "fileVersion");
@ -493,6 +504,20 @@ void xlsx_producer::write_workbook(const relationship &rel)
write_end_element(xmlns, "workbookPr"); write_end_element(xmlns, "workbookPr");
if (source_.d_->abs_path_.is_set())
{
write_start_element(xmlns_mc, "AlternateContent");
write_namespace(xmlns_mc, "mc");
write_start_element(xmlns_mc, "Choice");
write_attribute("Requires", "x15");
write_start_element(xmlns_x15ac, "absPath");
write_namespace(xmlns_x15ac, "x15ac");
write_attribute("url", source_.d_->abs_path_.get());
write_end_element(xmlns_x15ac, "absPath");
write_end_element(xmlns_mc, "Choice");
write_end_element(xmlns_mc, "AlternateContent");
}
if (source_.has_view()) if (source_.has_view())
{ {
write_start_element(xmlns, "bookViews"); write_start_element(xmlns, "bookViews");
@ -634,6 +659,19 @@ void xlsx_producer::write_workbook(const relationship &rel)
write_end_element(xmlns, "definedNames"); write_end_element(xmlns, "definedNames");
} }
if (source_.d_->arch_id_flags_.is_set())
{
write_start_element(xmlns, "extLst");
write_start_element(xmlns, "ext");
write_namespace(xmlns_mx, "mx");
write_attribute("uri", "{7523E5D3-25F3-A5E0-1632-64F254C22452}");
write_start_element(xmlns_mx, "ArchID");
write_attribute("Flags", source_.d_->arch_id_flags_.get());
write_end_element(xmlns_mx, "ArchID");
write_end_element(xmlns, "ext");
write_end_element(xmlns, "extLst");
}
write_end_element(xmlns, "workbook"); write_end_element(xmlns, "workbook");
auto workbook_rels = source_.manifest().relationships(rel.target().path()); auto workbook_rels = source_.manifest().relationships(rel.target().path());
@ -785,6 +823,7 @@ void xlsx_producer::write_pivot_table(const relationship & /*rel*/)
void xlsx_producer::write_shared_string_table(const relationship & /*rel*/) void xlsx_producer::write_shared_string_table(const relationship & /*rel*/)
{ {
static const auto &xmlns = constants::ns("spreadsheetml"); static const auto &xmlns = constants::ns("spreadsheetml");
static const auto &xmlns_xml = constants::ns("xml");
write_start_element(xmlns, "sst"); write_start_element(xmlns, "sst");
write_namespace(xmlns, ""); write_namespace(xmlns, "");
@ -832,6 +871,10 @@ void xlsx_producer::write_shared_string_table(const relationship & /*rel*/)
{ {
write_start_element(xmlns, "si"); write_start_element(xmlns, "si");
write_start_element(xmlns, "t"); write_start_element(xmlns, "t");
if (string.runs().front().preserve_space)
{
write_attribute(xml::qname(xmlns_xml, "space"), "preserve");
}
write_characters(string.plain_text(), has_trailing_whitespace(string.plain_text())); write_characters(string.plain_text(), has_trailing_whitespace(string.plain_text()));
write_end_element(xmlns, "t"); write_end_element(xmlns, "t");
write_end_element(xmlns, "si"); write_end_element(xmlns, "si");
@ -941,6 +984,12 @@ void xlsx_producer::write_font(const font &f)
write_end_element(xmlns, "i"); write_end_element(xmlns, "i");
} }
if (f.strikethrough())
{
write_start_element(xmlns, "strike");
write_end_element(xmlns, "strike");
}
if (f.underlined()) if (f.underlined())
{ {
write_start_element(xmlns, "u"); write_start_element(xmlns, "u");
@ -951,12 +1000,6 @@ void xlsx_producer::write_font(const font &f)
write_end_element(xmlns, "u"); write_end_element(xmlns, "u");
} }
if (f.strikethrough())
{
write_start_element(xmlns, "strike");
write_end_element(xmlns, "strike");
}
if (f.superscript()) if (f.superscript())
{ {
write_start_element(xmlns, "vertAlign"); write_start_element(xmlns, "vertAlign");
@ -1431,6 +1474,11 @@ void xlsx_producer::write_styles(const relationship & /*rel*/)
write_attribute("borderId", current_format_impl.border_id.get()); write_attribute("borderId", current_format_impl.border_id.get());
} }
if (current_format_impl.style.is_set())
{
write_attribute("xfId", stylesheet.style_index(current_format_impl.style.get()));
}
if (current_format_impl.number_format_id.is_set() if (current_format_impl.number_format_id.is_set()
&& current_format_impl.number_format_applied.is_set()) && current_format_impl.number_format_applied.is_set())
{ {
@ -1459,15 +1507,13 @@ void xlsx_producer::write_styles(const relationship & /*rel*/)
write_bool(current_format_impl.border_applied.get())); write_bool(current_format_impl.border_applied.get()));
} }
if (current_format_impl.alignment_id.is_set() if (current_format_impl.alignment_applied.is_set())
&& current_format_impl.alignment_applied.is_set())
{ {
write_attribute("applyAlignment", write_attribute("applyAlignment",
write_bool(current_format_impl.alignment_applied.get())); write_bool(current_format_impl.alignment_applied.get()));
} }
if (current_format_impl.protection_id.is_set() if (current_format_impl.protection_applied.is_set())
&& current_format_impl.protection_applied.is_set())
{ {
write_attribute("applyProtection", write_attribute("applyProtection",
write_bool(current_format_impl.protection_applied.get())); write_bool(current_format_impl.protection_applied.get()));
@ -1483,11 +1529,6 @@ void xlsx_producer::write_styles(const relationship & /*rel*/)
write_attribute("quotePrefix", write_bool(true)); write_attribute("quotePrefix", write_bool(true));
} }
if (current_format_impl.style.is_set())
{
write_attribute("xfId", stylesheet.style_index(current_format_impl.style.get()));
}
if (current_format_impl.alignment_id.is_set()) if (current_format_impl.alignment_id.is_set())
{ {
const auto &current_alignment = stylesheet.alignments[current_format_impl.alignment_id.get()]; const auto &current_alignment = stylesheet.alignments[current_format_impl.alignment_id.get()];

View File

@ -374,6 +374,16 @@ variant workbook::custom_property(const std::string &property_name) const
throw xlnt::exception("workbook doesn't have custom property"); throw xlnt::exception("workbook doesn't have custom property");
} }
void workbook::abs_path(const std::string &path)
{
d_->abs_path_ = path;
}
void workbook::arch_id_flags(const std::size_t flags)
{
d_->arch_id_flags_ = flags;
}
workbook workbook::empty() workbook workbook::empty()
{ {
auto impl = new detail::workbook_impl(); auto impl = new detail::workbook_impl();

Binary file not shown.