continue work on workbook metadata properties

This commit is contained in:
Thomas Fussell 2017-01-15 19:08:57 -05:00
parent f18e9dbc09
commit 571c0103b5
15 changed files with 1001 additions and 396 deletions

View File

@ -72,7 +72,60 @@ git submodule update --init --remote
## Documentation ## Documentation
More detailed documentation with examples can be found on [Read The Docs](http://xlnt.readthedocs.org/en/latest/) (Warning: As of November 9, 2016 this is very out of date). Properties
```c++
xlnt::workbook wb;
wb.core_property(xlnt::core_property::category, "hors categorie");
wb.core_property(xlnt::core_property::content_status, "good");
wb.core_property(xlnt::core_property::created, xlnt::datetime(2017, 1, 15));
wb.core_property(xlnt::core_property::creator, "me");
wb.core_property(xlnt::core_property::description, "description");
wb.core_property(xlnt::core_property::identifier, "id");
wb.core_property(xlnt::core_property::keywords, { "wow", "such" });
wb.core_property(xlnt::core_property::language, "Esperanto");
wb.core_property(xlnt::core_property::last_modified_by, "someone");
wb.core_property(xlnt::core_property::last_printed, xlnt::datetime(2017, 1, 15));
wb.core_property(xlnt::core_property::modified, xlnt::datetime(2017, 1, 15));
wb.core_property(xlnt::core_property::revision, "3");
wb.core_property(xlnt::core_property::subject, "subject");
wb.core_property(xlnt::core_property::title, "title");
wb.core_property(xlnt::core_property::version, "1.0");
wb.extended_property(xlnt::extended_property::application, "xlnt");
wb.extended_property(xlnt::extended_property::app_version, "0.9.3");
wb.extended_property(xlnt::extended_property::characters, 123);
wb.extended_property(xlnt::extended_property::characters_with_spaces, 124);
wb.extended_property(xlnt::extended_property::company, "Incorporated Inc.");
wb.extended_property(xlnt::extended_property::dig_sig, "?");
wb.extended_property(xlnt::extended_property::doc_security, 0);
wb.extended_property(xlnt::extended_property::heading_pairs, true);
wb.extended_property(xlnt::extended_property::hidden_slides, false);
wb.extended_property(xlnt::extended_property::h_links, 0);
wb.extended_property(xlnt::extended_property::hyperlink_base, 0);
wb.extended_property(xlnt::extended_property::hyperlinks_changed, true);
wb.extended_property(xlnt::extended_property::lines, 42);
wb.extended_property(xlnt::extended_property::links_up_to_date, false);
wb.extended_property(xlnt::extended_property::manager, "johnny");
wb.extended_property(xlnt::extended_property::m_m_clips, "?");
wb.extended_property(xlnt::extended_property::notes, "note");
wb.extended_property(xlnt::extended_property::pages, 19);
wb.extended_property(xlnt::extended_property::paragraphs, 18);
wb.extended_property(xlnt::extended_property::presentation_format, "format");
wb.extended_property(xlnt::extended_property::scale_crop, true);
wb.extended_property(xlnt::extended_property::shared_doc, false);
wb.extended_property(xlnt::extended_property::slides, 17);
wb.extended_property(xlnt::extended_property::template_, "template!");
wb.extended_property(xlnt::extended_property::titles_of_parts, { "title" });
wb.extended_property(xlnt::extended_property::total_time, 16);
wb.extended_property(xlnt::extended_property::words, 101);
wb.custom_property("test", { 1, 2, 3 });
wb.custom_property("Editor", "John Smith");
wb.save("lots_of_properties.xlsx");
```
## License ## License
xlnt is released to the public for free under the terms of the MIT License. See [LICENSE.md](https://github.com/tfussell/xlnt/blob/master/LICENCE.md) for the full text of the license and the licenses of xlnt's third-party dependencies. [LICENSE.md](https://github.com/tfussell/xlnt/blob/master/LICENCE.md) should be distributed alongside any assemblies that use xlnt in source or compiled form. xlnt is released to the public for free under the terms of the MIT License. See [LICENSE.md](https://github.com/tfussell/xlnt/blob/master/LICENCE.md) for the full text of the license and the licenses of xlnt's third-party dependencies. [LICENSE.md](https://github.com/tfussell/xlnt/blob/master/LICENCE.md) should be distributed alongside any assemblies that use xlnt in source or compiled form.

View File

@ -0,0 +1,102 @@
// Copyright (c) 2017 Thomas Fussell
//
// 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
#include <string>
#include <vector>
#include <xlnt/xlnt_config.hpp>
namespace xlnt {
struct datetime;
class XLNT_API variant
{
public:
enum class type
{
vector,
//array,
//blob,
//oblob,
//empty,
null,
//i1,
//i2,
i4,
//i8,
//integer,
//ui1,
//ui2,
//ui4,
//ui8,
//uint,
//r4,
//r8,
//decimal,
lpstr,
//lpwstr,
//bstr,
date,
//filetime,
boolean,
//cy,
//error,
//stream,
//ostream,
//storage,
//ostorage,
//vstream,
//clsid
};
variant();
variant(const std::string &value);
variant(const char *value);
variant(int value);
variant(bool value);
variant(const datetime &value);
variant(const std::initializer_list<int> &value);
variant(const std::vector<int> &value);
variant(const std::initializer_list<const char *> &value);
variant(const std::vector<const char *> &value);
variant(const std::initializer_list<std::string> &value);
variant(const std::vector<std::string> &value);
bool is(type t) const;
template<typename T>
T get() const;
type value_type() const;
private:
type type_;
std::vector<variant> vector_value_;
std::int32_t i4_value_;
std::string lpstr_value_;
};
} // namespace xlnt

View File

@ -0,0 +1,80 @@
// Copyright (c) 2017 Thomas Fussell
//
// 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
#include <xlnt/xlnt_config.hpp>
namespace xlnt {
enum class core_property
{
category,
content_status,
created,
creator,
description,
identifier,
keywords,
language,
last_modified_by,
last_printed,
modified,
revision,
subject,
title,
version
};
enum class extended_property
{
application,
app_version,
characters,
characters_with_spaces,
company,
dig_sig,
doc_security,
heading_pairs,
hidden_slides,
h_links,
hyperlink_base,
hyperlinks_changed,
lines,
links_up_to_date,
manager,
m_m_clips,
notes,
pages,
paragraphs,
presentation_format,
scale_crop,
shared_doc,
slides,
template_,
titles_of_parts,
total_time,
words
};
} // namespace xlnt

View File

@ -37,6 +37,8 @@
namespace xlnt { namespace xlnt {
enum class calendar; enum class calendar;
enum class core_property;
enum class extended_property;
enum class relationship_type; enum class relationship_type;
class alignment; class alignment;
@ -52,6 +54,7 @@ class font;
class format; class format;
class rich_text; class rich_text;
class manifest; class manifest;
class metadata_property;
class named_range; class named_range;
class number_format; class number_format;
class path; class path;
@ -63,6 +66,7 @@ class relationship;
class style; class style;
class style_serializer; class style_serializer;
class theme; class theme;
class variant;
class workbook_view; class workbook_view;
class worksheet; class worksheet;
class worksheet_iterator; class worksheet_iterator;
@ -289,46 +293,42 @@ public:
/// <summary> /// <summary>
/// Returns true if the workbook has the core property with the given name. /// Returns true if the workbook has the core property with the given name.
/// </summary> /// </summary>
bool has_core_property(const std::string &property_name) const; bool has_core_property(xlnt::core_property type) const;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
std::vector<std::string> core_properties() const; std::vector<xlnt::core_property> core_properties() const;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
template <typename T = std::string> variant core_property(xlnt::core_property type) const;
T core_property(const std::string &property_name) const;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
template <typename T = std::string> void core_property(xlnt::core_property type, const variant &value);
void core_property(const std::string &property_name, const T value);
/// <summary> /// <summary>
/// Returns true if the workbook has the extended property with the given name. /// Returns true if the workbook has the extended property with the given name.
/// </summary> /// </summary>
bool has_extended_property(const std::string &property_name) const; bool has_extended_property(xlnt::extended_property type) const;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
std::vector<std::string> extended_properties() const; std::vector<xlnt::extended_property> extended_properties() const;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
template <typename T = std::string> variant extended_property(xlnt::extended_property type) const;
T extended_property(const std::string &property_name) const;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
template <typename T = std::string> void extended_property(xlnt::extended_property type, const variant &value);
void extended_property(const std::string &property_name, const T value);
/// <summary> /// <summary>
/// Returns true if the workbook has the custom property with the given name. /// Returns true if the workbook has the custom property with the given name.
@ -343,14 +343,12 @@ public:
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
template <typename T = std::string> variant custom_property(const std::string &property_name) const;
T custom_property(const std::string &property_name) const;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
template <typename T = std::string> void custom_property(const std::string &property_name, const variant &value);
void custom_property(const std::string &property_name, const T value);
/// <summary> /// <summary>
/// ///
@ -746,32 +744,17 @@ private:
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
void register_app_properties_in_manifest(); void register_package_part(relationship_type type);
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
void register_core_properties_in_manifest(); void register_workbook_part(relationship_type type);
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
void register_shared_string_table_in_manifest(); void register_worksheet_part(worksheet ws, relationship_type type);
/// <summary>
///
/// </summary>
void register_stylesheet_in_manifest();
/// <summary>
///
/// </summary>
void register_theme_in_manifest();
/// <summary>
///
/// </summary>
void register_comments_in_manifest(worksheet ws);
/// <summary> /// <summary>
/// Removes calcChain part from manifest if no formulae remain in workbook. /// Removes calcChain part from manifest if no formulae remain in workbook.

View File

@ -61,11 +61,13 @@
#include <xlnt/utils/path.hpp> #include <xlnt/utils/path.hpp>
#include <xlnt/utils/time.hpp> #include <xlnt/utils/time.hpp>
#include <xlnt/utils/timedelta.hpp> #include <xlnt/utils/timedelta.hpp>
#include <xlnt/utils/variant.hpp>
// workbook // workbook
#include <xlnt/workbook/const_worksheet_iterator.hpp> #include <xlnt/workbook/const_worksheet_iterator.hpp>
#include <xlnt/workbook/document_security.hpp> #include <xlnt/workbook/document_security.hpp>
#include <xlnt/workbook/external_book.hpp> #include <xlnt/workbook/external_book.hpp>
#include <xlnt/workbook/metadata_property.hpp>
#include <xlnt/workbook/named_range.hpp> #include <xlnt/workbook/named_range.hpp>
#include <xlnt/workbook/theme.hpp> #include <xlnt/workbook/theme.hpp>
#include <xlnt/workbook/workbook.hpp> #include <xlnt/workbook/workbook.hpp>

View File

@ -262,5 +262,128 @@ std::string to_string(border_side side)
default_case("top"); default_case("top");
} }
std::string to_string(core_property prop)
{
switch (prop)
{
case core_property::category:
return "category";
case core_property::content_status:
return "contentStatus";
case core_property::created:
return "created";
case core_property::creator:
return "creator";
case core_property::description:
return "description";
case core_property::identifier:
return "identifier";
case core_property::keywords:
return "keywords";
case core_property::language:
return "language";
case core_property::last_modified_by:
return "lastModifiedBy";
case core_property::last_printed:
return "lastPrinted";
case core_property::modified:
return "modified";
case core_property::revision:
return "revision";
case core_property::subject:
return "subject";
case core_property::title:
return "title";
case core_property::version:
return "version";
}
default_case("category");
}
std::string to_string(extended_property prop)
{
switch (prop)
{
case extended_property::application:
return "Application";
case extended_property::app_version:
return "AppVersion";
case extended_property::characters:
return "Characters";
case extended_property::characters_with_spaces:
return "CharactersWithSpaces";
case extended_property::company:
return "Company";
case extended_property::dig_sig:
return "DigSig";
case extended_property::doc_security:
return "DocSecurity";
case extended_property::heading_pairs:
return "HeadingPairs";
case extended_property::hidden_slides:
return "HiddenSlides";
case extended_property::hyperlinks_changed:
return "HyperlinksChanged";
case extended_property::hyperlink_base:
return "HyperlinkBase";
case extended_property::h_links:
return "HLinks";
case extended_property::lines:
return "Lines";
case extended_property::links_up_to_date:
return "LinksUpToDate";
case extended_property::manager:
return "Manager";
case extended_property::m_m_clips:
return "MMClips";
case extended_property::notes:
return "Notes";
case extended_property::pages:
return "Pages";
case extended_property::paragraphs:
return "Paragraphs";
case extended_property::presentation_format:
return "PresentationFormat";
case extended_property::scale_crop:
return "ScaleCrop";
case extended_property::shared_doc:
return "SharedDoc";
case extended_property::slides:
return "Slides";
case extended_property::template_:
return "Template";
case extended_property::titles_of_parts:
return "TitlesOfParts";
case extended_property::total_time:
return "TotalTime";
case extended_property::words:
return "Words";
}
default_case("Application");
}
std::string to_string(variant::type type)
{
switch (type)
{
case variant::type::boolean:
return "bool";
case variant::type::date:
return "date";
case variant::type::i4:
return "i4";
case variant::type::lpstr:
return "lpstr";
case variant::type::null:
return "null";
case variant::type::vector:
return "vector";
}
default_case("null");
}
} // namespace detail } // namespace detail
} // namespace xlnt } // namespace xlnt

View File

@ -9,7 +9,9 @@
#include <xlnt/styles/horizontal_alignment.hpp> #include <xlnt/styles/horizontal_alignment.hpp>
#include <xlnt/styles/vertical_alignment.hpp> #include <xlnt/styles/vertical_alignment.hpp>
#include <xlnt/utils/exceptions.hpp> #include <xlnt/utils/exceptions.hpp>
#include <xlnt/utils/variant.hpp>
#include <xlnt/worksheet/pane.hpp> #include <xlnt/worksheet/pane.hpp>
#include <xlnt/workbook/metadata_property.hpp>
namespace xlnt { namespace xlnt {
namespace detail { namespace detail {
@ -36,6 +38,12 @@ std::string to_string(horizontal_alignment horizontal_alignment);
std::string to_string(border_side side); std::string to_string(border_side side);
std::string to_string(core_property prop);
std::string to_string(extended_property prop);
std::string to_string(variant::type type);
} // namespace detail } // namespace detail
} // namespace xlnt } // namespace xlnt

View File

@ -31,6 +31,7 @@
#include <detail/worksheet_impl.hpp> #include <detail/worksheet_impl.hpp>
#include <xlnt/packaging/manifest.hpp> #include <xlnt/packaging/manifest.hpp>
#include <xlnt/utils/datetime.hpp> #include <xlnt/utils/datetime.hpp>
#include <xlnt/utils/variant.hpp>
#include <xlnt/workbook/calculation_properties.hpp> #include <xlnt/workbook/calculation_properties.hpp>
#include <xlnt/workbook/theme.hpp> #include <xlnt/workbook/theme.hpp>
#include <xlnt/workbook/workbook_view.hpp> #include <xlnt/workbook/workbook_view.hpp>
@ -94,9 +95,9 @@ struct workbook_impl
optional<theme> theme_; optional<theme> theme_;
std::unordered_map<std::string, std::vector<std::uint8_t>> images_; std::unordered_map<std::string, std::vector<std::uint8_t>> images_;
std::unordered_map<std::string, std::string> core_properties_; std::unordered_map<xlnt::core_property, variant, xlnt::scoped_enum_hash<xlnt::core_property>> core_properties_;
std::unordered_map<std::string, std::string> extended_properties_; std::unordered_map<xlnt::extended_property, variant, xlnt::scoped_enum_hash<xlnt::extended_property>> extended_properties_;
std::unordered_map<std::string, std::string> custom_properties_; std::unordered_map<std::string, variant> custom_properties_;
std::unordered_map<std::string, std::string> sheet_title_rel_id_map_; std::unordered_map<std::string, std::string> sheet_title_rel_id_map_;

View File

@ -20,9 +20,11 @@
// //
// @license: http://www.opensource.org/licenses/mit-license.php // @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file // @author: see AUTHORS file
#include <cmath> #include <cmath>
#include <numeric> // for std::accumulate #include <numeric> // for std::accumulate
#include <string> #include <string>
#include <unordered_set>
#include <xlnt/cell/cell.hpp> #include <xlnt/cell/cell.hpp>
#include <xlnt/packaging/manifest.hpp> #include <xlnt/packaging/manifest.hpp>
@ -91,15 +93,15 @@ void xlsx_producer::populate_archive()
if (rel.type() == relationship_type::core_properties) if (rel.type() == relationship_type::core_properties)
{ {
write_properties(rel); write_core_properties(rel);
} }
else if (rel.type() == relationship_type::extended_properties) else if (rel.type() == relationship_type::extended_properties)
{ {
write_properties(rel); write_extended_properties(rel);
} }
else if (rel.type() == relationship_type::custom_properties) else if (rel.type() == relationship_type::custom_properties)
{ {
write_properties(rel); write_custom_properties(rel);
} }
else if (rel.type() == relationship_type::office_document) else if (rel.type() == relationship_type::office_document)
{ {
@ -164,177 +166,207 @@ void xlsx_producer::write_content_types()
write_end_element(xmlns, "Types"); write_end_element(xmlns, "Types");
} }
/* void xlsx_producer::write_property(const std::string &name, const variant &value, const std::string &ns, bool custom)
Core Properties:
- category
- contentStatus
- dcterms:created
- dc:creator
- dc:description
- dc:identifier
- keywords
- dc:language
- lastModifiedBy
- lastPrinted
- dcterms:modified
- revision
- dc:subject
- dc:title
- version
Extended Properties (SpreadsheetML):
Custom Properties:
*/
void xlsx_producer::write_properties(const relationship &rel)
{ {
std::vector<std::pair<std::string, std::string>> properties; if (custom)
std::unordered_map<std::string, std::string> namespaces;
xml::qname root_element;
auto xmlns = ""s;
if (rel.type() == relationship_type::core_properties)
{ {
xmlns = "http://schemas.openxmlformats.org/officeDocument/2006/core-properties"; write_start_element(ns, "property");
root_element = xml::qname(constants::ns("core-properties"), "coreProperties"); write_attribute("name", name);
for (const auto &property_name : source_.core_properties())
{
properties.emplace_back(property_name, source_.core_property(property_name));
if (property_name == "created" || property_name == "modified")
{
namespaces.emplace(constants::ns("dcterms"), "dcterms");
namespaces.emplace(constants::ns("xsi"), "xsi");
} }
else if (property_name == "creator" || property_name == "description" else
|| property_name == "identifier" || property_name == "language"
|| property_name == "subject" || property_name == "title")
{ {
namespaces.emplace(constants::ns("dc"), "dc"); write_start_element(ns, name);
}
}
}
else if (rel.type() == relationship_type::extended_properties)
{
xmlns = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
root_element = xml::qname(xmlns, "Properties");
namespaces.emplace(xmlns, "");
for (const auto &property_name : source_.extended_properties())
{
properties.emplace_back(property_name, source_.extended_property(property_name));
if (property_name == "HeadingsOfParts" || property_name == "TitlesOfParts")
{
namespaces.emplace(constants::ns("vt"), "vt");
}
}
}
else if (rel.type() == relationship_type::custom_properties)
{
xmlns = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
root_element = xml::qname(xmlns, "Properties");
namespaces.emplace(xmlns, "");
namespaces.emplace(constants::ns("vt"), "vt");
for (const auto &property_name : source_.custom_properties())
{
properties.emplace_back(property_name, source_.custom_property(property_name));
}
} }
write_start_element(root_element.namespace_(), root_element.name()); switch (value.value_type())
for (const auto &ns : namespaces)
{ {
write_namespace(ns.first, ns.second); case variant::type::null:
break;
case variant::type::boolean:
if (custom)
{
write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
write_attribute("pid", 2);
} }
for (const auto &prop : properties) write_characters(write_bool(value.get<bool>()));
{ break;
auto property_type = "normal"s;
auto property_ns = xmlns;
if (rel.type() == relationship_type::core_properties) case variant::type::i4:
if (custom)
{ {
if (prop.first == "keywords") write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
{ write_attribute("pid", 2);
property_type = "keywords";
}
else if (prop.first == "modified" || prop.first == "created")
{
property_type = "w3cdtf";
property_ns = constants::ns("dcterms");
}
else if (prop.first == "creator" || prop.first == "description"
|| prop.first == "identifier" || prop.first == "language"
|| prop.first == "subject" || prop.first == "title")
{
property_ns = constants::ns("dc");
}
}
else if (rel.type() == relationship_type::extended_properties)
{
if (prop.first == "HeadingsOfParts" || prop.first == "TitlesOfParts")
{
property_type = "vt:vector";
}
} }
write_start_element(property_ns, prop.first); write_characters(value.get<std::int32_t>());
break;
if (property_type == "vt:vector") case variant::type::lpstr:
if (custom)
{
write_attribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
write_attribute("pid", 2);
write_start_element(constants::ns("vt"), "lpwstr");
}
write_characters(value.get<std::string>());
if (custom)
{
write_end_element(constants::ns("vt"), "lpwstr");
}
break;
case variant::type::date:
write_attribute(xml::qname(constants::ns("xsi"), "type"), "dcterms:W3CDTF");
write_characters(value.get<datetime>().to_iso_string());
break;
case variant::type::vector:
{ {
write_start_element(constants::ns("vt"), "vector"); write_start_element(constants::ns("vt"), "vector");
auto split = std::vector<std::string>(); auto vector = value.get<std::vector<variant>>();
auto delim = ' '; std::unordered_set<variant::type> types;
auto previous_index = std::size_t(0);
auto delim_index = prop.second.find(delim);
while (delim_index != std::string::npos) for (const auto &element : vector)
{ {
split.push_back(prop.second.substr(previous_index, delim_index - previous_index)); types.insert(element.value_type());
previous_index = delim_index;
delim_index = prop.second.find(delim);
} }
split.push_back(prop.second.substr(previous_index)); const auto is_mixed = types.size() > 1;
const auto vector_type = !is_mixed ? to_string(*types.begin()) : "variant";
write_attribute("size", split.size() / 2); write_attribute("size", vector.size());
write_attribute("baseType", "variant"); write_attribute("baseType", vector_type);
for (std::size_t i = 0; i < split.size() / 2; ++i) for (std::size_t i = 0; i < vector.size(); ++i)
{
const auto &vector_element = vector.at(i);
if (is_mixed)
{ {
auto vt_type = split[i * 2];
auto vt_value = split[i * 2 + 1];
write_start_element(constants::ns("vt"), "variant"); write_start_element(constants::ns("vt"), "variant");
write_element(constants::ns("vt"), vt_type, vt_value); }
switch (vector_element.value_type())
{
case variant::type::lpstr:
write_element(constants::ns("vt"), "lpstr", vector_element.get<std::string>());
break;
case variant::type::i4:
write_element(constants::ns("vt"), "i4", vector_element.get<std::int32_t>());
break;
}
if (is_mixed)
{
write_end_element(constants::ns("vt"), "variant"); write_end_element(constants::ns("vt"), "variant");
} }
}
write_end_element(constants::ns("vt"), "vector"); write_end_element(constants::ns("vt"), "vector");
} }
else if (property_type == "w3cdtf")
break;
}
if (custom)
{ {
write_attribute(xml::qname(constants::ns("xsi"), "type"), "dcterms:W3CDTF"); write_end_element(ns, "property");
write_characters(prop.second);
} }
else else
{ {
write_characters(prop.second); write_end_element(ns, name);
}
} }
write_end_element(property_ns, prop.first); std::vector<std::pair<std::string, std::string>> core_property_namespace(core_property type)
{
if (type == core_property::created
|| type == core_property::modified)
{
return {{constants::ns("dcterms"), "dcterms"},
{constants::ns("xsi"), "xsi"}};
}
else if (type == core_property::title
|| type == core_property::subject
|| type == core_property::creator
|| type == core_property::description)
{
return {{constants::ns("dc"), "dc"}};
}
else if (type == core_property::keywords)
{
return {{constants::ns("core-properties"), "cp"},
{constants::ns("vt"), "vt"}};
} }
write_end_element(root_element.namespace_(), root_element.name()); return {{constants::ns("core-properties"), "cp"}};
}
void xlsx_producer::write_core_properties(const relationship &/*rel*/)
{
write_start_element(constants::ns("core-properties"), "coreProperties");
auto core_properties = source_.core_properties();
std::unordered_map<std::string, std::string> namespaces;
for (const auto &prop : core_properties)
{
for (const auto &ns : core_property_namespace(prop))
{
if (namespaces.count(ns.first) > 0) continue;
write_namespace(ns.first, ns.second);
namespaces.emplace(ns);
}
}
for (const auto &prop : core_properties)
{
write_property(to_string(prop), source_.core_property(prop),
core_property_namespace(prop).front().first, false);
}
write_end_element(constants::ns("core-properties"), "coreProperties");
}
void xlsx_producer::write_extended_properties(const relationship &/*rel*/)
{
write_start_element(constants::ns("extended-properties"), "Properties");
write_namespace(constants::ns("extended-properties"), "");
if (source_.has_extended_property(extended_property::heading_pairs)
|| source_.has_extended_property(extended_property::titles_of_parts))
{
write_namespace(constants::ns("vt"), "vt");
}
for (const auto &prop : source_.extended_properties())
{
write_property(to_string(prop), source_.extended_property(prop),
constants::ns("extended-properties"), false);
}
write_end_element(constants::ns("extended-properties"), "Properties");
}
void xlsx_producer::write_custom_properties(const relationship &/*rel*/)
{
write_start_element(constants::ns("custom-properties"), "Properties");
write_namespace(constants::ns("custom-properties"), "");
write_namespace(constants::ns("vt"), "vt");
for (const auto &prop : source_.custom_properties())
{
write_property(prop, source_.custom_property(prop),
constants::ns("custom-properties"), true);
}
write_end_element(constants::ns("custom-properties"), "Properties");
} }
// Write SpreadsheetML-Specific Package Parts // Write SpreadsheetML-Specific Package Parts

View File

@ -71,7 +71,10 @@ private:
// Package Parts // Package Parts
void write_content_types(); void write_content_types();
void write_properties(const relationship &rel); void write_property(const std::string &name, const variant &value, const std::string &ns, bool custom);
void write_core_properties(const relationship &rel);
void write_extended_properties(const relationship &rel);
void write_custom_properties(const relationship &rel);
void write_image(const path &image_path); void write_image(const path &image_path);
// SpreadsheetML-Specific Package Parts // SpreadsheetML-Specific Package Parts

View File

@ -214,8 +214,8 @@ std::vector<path> manifest::parts() const
return std::vector<path>(parts.begin(), parts.end()); return std::vector<path>(parts.begin(), parts.end());
} }
std::string manifest::register_relationship( std::string manifest::register_relationship(const uri &source,
const uri &source, relationship_type type, const uri &target, target_mode mode) relationship_type type, const uri &target, target_mode mode)
{ {
xlnt::relationship rel(next_relationship_id(source.path()), type, source, target, mode); xlnt::relationship rel(next_relationship_id(source.path()), type, source, target, mode);
return register_relationship(rel); return register_relationship(rel);

159
source/utils/variant.cpp Normal file
View File

@ -0,0 +1,159 @@
// Copyright (c) 2017 Thomas Fussell
//
// 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
#include <xlnt/utils/variant.hpp>
#include <xlnt/utils/datetime.hpp>
namespace xlnt {
variant::variant()
{
}
variant::variant(const std::string &value)
: type_(type::lpstr),
lpstr_value_(value)
{
}
variant::variant(const char *value) : variant(std::string(value))
{
}
variant::variant(int value)
: type_(type::i4),
i4_value_(value)
{
}
variant::variant(bool value)
: type_(type::boolean),
i4_value_(value ? 1 : 0)
{
}
variant::variant(const datetime &value)
: type_(type::date),
lpstr_value_(value.to_iso_string())
{
}
variant::variant(const std::initializer_list<int> &value)
: type_(type::vector)
{
for (const auto &v : value)
{
vector_value_.emplace_back(v);
}
}
variant::variant(const std::vector<int> &value)
: type_(type::vector)
{
for (const auto &v : value)
{
vector_value_.emplace_back(v);
}
}
variant::variant(const std::initializer_list<const char *> &value)
: type_(type::vector)
{
for (const auto &v : value)
{
vector_value_.emplace_back(v);
}
}
variant::variant(const std::vector<const char *> &value)
: type_(type::vector)
{
for (const auto &v : value)
{
vector_value_.emplace_back(v);
}
}
variant::variant(const std::initializer_list<std::string> &value)
: type_(type::vector)
{
for (const auto &v : value)
{
vector_value_.emplace_back(v);
}
}
variant::variant(const std::vector<std::string> &value)
: type_(type::vector)
{
for (const auto &v : value)
{
vector_value_.emplace_back(v);
}
}
bool variant::is(type t) const
{
return type_ == t;
}
template<>
XLNT_API std::string variant::get() const
{
return lpstr_value_;
}
template<>
XLNT_API std::vector<variant> variant::get() const
{
return vector_value_;
}
template<>
XLNT_API bool variant::get() const
{
return i4_value_ != 0;
}
template<>
XLNT_API std::int32_t variant::get() const
{
return i4_value_;
}
template<>
XLNT_API datetime variant::get() const
{
return datetime::from_iso_string(lpstr_value_);
}
variant::type variant::value_type() const
{
return type_;
}
}

View File

@ -110,7 +110,7 @@ public:
xlnt::workbook wb; xlnt::workbook wb;
wb.load("data/21_custom_properties.xlsx"); wb.load("data/21_custom_properties.xlsx");
TS_ASSERT(wb.has_custom_property("Client")); TS_ASSERT(wb.has_custom_property("Client"));
TS_ASSERT_EQUALS(wb.custom_property("Client"), "me!"); TS_ASSERT_EQUALS(wb.custom_property("Client").get<std::string>(), "me!");
} }
void test_read_formulae() void test_read_formulae()

View File

@ -45,7 +45,9 @@
#include <xlnt/styles/style.hpp> #include <xlnt/styles/style.hpp>
#include <xlnt/utils/exceptions.hpp> #include <xlnt/utils/exceptions.hpp>
#include <xlnt/utils/path.hpp> #include <xlnt/utils/path.hpp>
#include <xlnt/utils/variant.hpp>
#include <xlnt/workbook/const_worksheet_iterator.hpp> #include <xlnt/workbook/const_worksheet_iterator.hpp>
#include <xlnt/workbook/metadata_property.hpp>
#include <xlnt/workbook/named_range.hpp> #include <xlnt/workbook/named_range.hpp>
#include <xlnt/workbook/theme.hpp> #include <xlnt/workbook/theme.hpp>
#include <xlnt/workbook/workbook.hpp> #include <xlnt/workbook/workbook.hpp>
@ -104,9 +106,9 @@ void open_stream(std::ofstream &stream, const std::string &path)
#endif #endif
template<typename T> template<typename T>
std::vector<std::string> keys(const T &container) std::vector<typename T::key_type> keys(const T &container)
{ {
auto result = std::vector<std::string>(); auto result = std::vector<typename T::key_type>();
auto iter = container.begin(); auto iter = container.begin();
while (iter != container.end()) while (iter != container.end())
@ -121,72 +123,46 @@ std::vector<std::string> keys(const T &container)
namespace xlnt { namespace xlnt {
bool workbook::has_core_property(const std::string &property_name) const bool workbook::has_core_property(xlnt::core_property type) const
{ {
return d_->core_properties_.count(property_name) > 0; return d_->core_properties_.count(type) > 0;
} }
std::vector<std::string> workbook::core_properties() const std::vector<xlnt::core_property> workbook::core_properties() const
{ {
return keys(d_->core_properties_); return keys(d_->core_properties_);
} }
template <> variant workbook::core_property(xlnt::core_property type) const
XLNT_API std::string workbook::core_property(const std::string &property_name) const
{ {
return d_->core_properties_.at(property_name); return d_->core_properties_.at(type);
} }
template <> void workbook::core_property(xlnt::core_property type, const variant &value)
XLNT_API void workbook::core_property(const std::string &property_name, const std::string value)
{ {
d_->core_properties_[property_name] = value; register_package_part(relationship_type::core_properties);
d_->core_properties_[type] = value;
} }
template <> bool workbook::has_extended_property(xlnt::extended_property type) const
XLNT_API void workbook::core_property(const std::string &property_name, const char *value)
{ {
d_->core_properties_[property_name] = value; return d_->extended_properties_.count(type) > 0;
} }
template <> std::vector<xlnt::extended_property> workbook::extended_properties() const
XLNT_API void workbook::core_property(const std::string &property_name, const datetime value)
{
d_->core_properties_[property_name] = value.to_iso_string();
}
bool workbook::has_extended_property(const std::string &property_name) const
{
return d_->extended_properties_.count(property_name) > 0;
}
std::vector<std::string> workbook::extended_properties() const
{ {
return keys(d_->extended_properties_); return keys(d_->extended_properties_);
} }
template <> void workbook::extended_property(xlnt::extended_property type, const variant &value)
XLNT_API void workbook::extended_property(const std::string &property_name, const std::string value)
{ {
d_->extended_properties_[property_name] = value; register_package_part(relationship_type::extended_properties);
d_->extended_properties_[type] = value;
} }
template <> variant workbook::extended_property(xlnt::extended_property type) const
XLNT_API void workbook::extended_property(const std::string &property_name, const char *value)
{ {
d_->extended_properties_[property_name] = value; return d_->extended_properties_.at(type);
}
template <>
XLNT_API void workbook::extended_property(const std::string &property_name, const datetime value)
{
d_->extended_properties_[property_name] = value.to_iso_string();
}
template <>
XLNT_API std::string workbook::extended_property(const std::string &property_name) const
{
return d_->extended_properties_.at(property_name);
} }
bool workbook::has_custom_property(const std::string &property_name) const bool workbook::has_custom_property(const std::string &property_name) const
@ -199,20 +175,13 @@ std::vector<std::string> workbook::custom_properties() const
return keys(d_->custom_properties_); return keys(d_->custom_properties_);
} }
template <> void workbook::custom_property(const std::string &property_name, const variant &value)
XLNT_API void workbook::custom_property(const std::string &property_name, const std::string value)
{ {
register_package_part(relationship_type::custom_properties);
d_->custom_properties_[property_name] = value; d_->custom_properties_[property_name] = value;
} }
template <> variant workbook::custom_property(const std::string &property_name) const
XLNT_API void workbook::custom_property(const std::string &property_name, const char *value)
{
d_->custom_properties_[property_name] = value;
}
template <>
XLNT_API std::string workbook::custom_property(const std::string &property_name) const
{ {
return d_->custom_properties_.at(property_name); return d_->custom_properties_.at(property_name);
} }
@ -222,10 +191,7 @@ workbook workbook::empty()
auto impl = new detail::workbook_impl(); auto impl = new detail::workbook_impl();
workbook wb(impl); workbook wb(impl);
wb.d_->manifest_.register_override_type(path("/xl/workbook.xml"), wb.register_package_part(relationship_type::office_document);
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml");
wb.d_->manifest_.register_relationship(uri("/"), relationship_type::office_document,
uri("xl/workbook.xml"), target_mode::internal);
wb.d_->manifest_.register_default_type("rels", wb.d_->manifest_.register_default_type("rels",
"application/vnd.openxmlformats-package.relationships+xml"); "application/vnd.openxmlformats-package.relationships+xml");
@ -234,29 +200,19 @@ workbook workbook::empty()
wb.thumbnail(excel_thumbnail(), "jpeg", "image/jpeg"); wb.thumbnail(excel_thumbnail(), "jpeg", "image/jpeg");
wb.d_->manifest_.register_override_type(path("/docProps/core.xml"), wb.core_property(xlnt::core_property::creator, "Microsoft Office User");
"application/vnd.openxmlformats-package.core-properties+xml"); wb.core_property(xlnt::core_property::last_modified_by, "Microsoft Office User");
wb.d_->manifest_.register_relationship(uri("/"), relationship_type::core_properties, wb.core_property(xlnt::core_property::created, datetime(2016, 8, 12, 3, 16, 56));
uri("docProps/core.xml"), target_mode::internal); wb.core_property(xlnt::core_property::modified, datetime(2016, 8, 12, 3, 17, 16));
wb.d_->manifest_.register_override_type(path("/docProps/app.xml"), wb.extended_property(xlnt::extended_property::application, "Microsoft Macintosh Excel");
"application/vnd.openxmlformats-officedocument.extended-properties+xml"); wb.extended_property(xlnt::extended_property::doc_security, 0);
wb.d_->manifest_.register_relationship(uri("/"), relationship_type::extended_properties, wb.extended_property(xlnt::extended_property::scale_crop, "false");
uri("docProps/app.xml"), target_mode::internal); wb.extended_property(xlnt::extended_property::company, "");
wb.extended_property(xlnt::extended_property::links_up_to_date, false);
wb.core_property("creator", "Microsoft Office User"); wb.extended_property(xlnt::extended_property::shared_doc, false);
wb.core_property("lastModifiedBy", "Microsoft Office User"); wb.extended_property(xlnt::extended_property::hyperlinks_changed, false);
wb.core_property("created", datetime(2016, 8, 12, 3, 16, 56)); wb.extended_property(xlnt::extended_property::app_version, "15.0300");
wb.core_property("modified", datetime(2016, 8, 12, 3, 17, 16));
wb.extended_property("Application", "Microsoft Macintosh Excel");
wb.extended_property("DocSecurity", "0");
wb.extended_property("ScaleCrop", "false");
wb.extended_property("Company", "");
wb.extended_property("LinksUpToDate", "false");
wb.extended_property("SharedDoc", "false");
wb.extended_property("HyperlinksChanged", "false");
wb.extended_property("AppVersion", "15.0300");
auto file_version = detail::workbook_impl::file_version_t{"xl", 6, 6, 26709}; auto file_version = detail::workbook_impl::file_version_t{"xl", 6, 6, 26709};
wb.d_->file_version_ = file_version; wb.d_->file_version_ = file_version;
@ -352,82 +308,182 @@ workbook::workbook(detail::workbook_impl *impl)
} }
} }
void workbook::register_app_properties_in_manifest() path default_path(relationship_type type, std::size_t index = 0)
{ {
auto wb_rel = manifest().relationship(path("/"), switch (type)
relationship_type::office_document);
if (!manifest().has_relationship(wb_rel.target().path(),
relationship_type::extended_properties))
{ {
manifest().register_override_type(path("/docProps/app.xml"), case relationship_type::calculation_chain:
"application/vnd.openxmlformats-officedocument.extended-properties+xml"); return path("/xl/calcChain.xml");
manifest().register_relationship(uri("/"), relationship_type::extended_properties, case relationship_type::chartsheet:
uri("docProps/app.xml"), target_mode::internal); return path("/xl/sheets/.xml");
case relationship_type::comments:
return path("/xl/comments.xml");
case relationship_type::connections:
return path("/xl/connections.xml");
case relationship_type::core_properties:
return path("/docProps/core.xml");
case relationship_type::custom_properties:
return path("/docProps/custom.xml");
case relationship_type::custom_property:
return path("/xl/customProperty.xml");
case relationship_type::custom_xml_mappings:
return path("/xl/customXmlMappings.xml");
case relationship_type::dialogsheet:
return path("/xl/dialogsheets/sheet.xml");
case relationship_type::drawings:
return path("/xl/drawings/drawing.xml");
case relationship_type::extended_properties:
return path("/docProps/app.xml");
case relationship_type::external_workbook_references:
return path("/xl/external.xml");
case relationship_type::hyperlink:
return path("/xl/hyperlink.xml");
case relationship_type::image:
return path("?");
case relationship_type::office_document:
return path("/xl/workbook.xml");
case relationship_type::pivot_table:
return path("/xl/pivotTable.xml");
case relationship_type::pivot_table_cache_definition:
return path("?");
case relationship_type::pivot_table_cache_records:
return path("?");
case relationship_type::printer_settings:
return path("/xl/printerSettings.xml");
case relationship_type::query_table:
return path("/xl/queryTable.xml");
case relationship_type::revision_log:
return path("/xl/revisionLog.xml");
case relationship_type::shared_string_table:
return path("/xl/sharedStrings.xml");
case relationship_type::shared_workbook:
return path("/xl/sharedWorkbook.xml");
case relationship_type::shared_workbook_revision_headers:
return path("?");
case relationship_type::shared_workbook_user_data:
return path("?");
case relationship_type::single_cell_table_definitions:
return path("?");
case relationship_type::stylesheet:
return path("/xl/styles.xml");
case relationship_type::table_definition:
return path("/xl/tableDefinition.xml");
case relationship_type::theme:
return path("/xl/theme/theme1.xml");
case relationship_type::thumbnail:
return path("/docProps/thumbnail.jpg");
case relationship_type::unknown:
return path("/xl/unknown.xml");
case relationship_type::vml_drawing:
return path("/xl/vmlDrawing.xml");
case relationship_type::volatile_dependencies:
return path("/xl/volatileDependencies.xml");
case relationship_type::worksheet:
return path("/xl/worksheets/sheet" + std::to_string(index) + ".xml");
} }
} }
void workbook::register_core_properties_in_manifest() std::string content_type(relationship_type type)
{ {
auto wb_rel = manifest().relationship(path("/"), switch (type)
relationship_type::office_document);
if (!manifest().has_relationship(wb_rel.target().path(),
relationship_type::core_properties))
{ {
manifest().register_override_type(path("/docProps/core.xml"), case relationship_type::calculation_chain:
"application/vnd.openxmlformats-package.core-properties+xml"); return "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml";
manifest().register_relationship(uri("/"), relationship_type::core_properties, case relationship_type::chartsheet:
uri("docProps/core.xml"), target_mode::internal); return "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml";
case relationship_type::comments:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml";
case relationship_type::connections:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml";
case relationship_type::core_properties:
return "application/vnd.openxmlformats-package.core-properties+xml";
case relationship_type::custom_properties:
return "application/vnd.openxmlformats-officedocument.custom-properties+xml";
case relationship_type::custom_property:
return "";
case relationship_type::custom_xml_mappings:
return "application/xml";
case relationship_type::dialogsheet:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml";
case relationship_type::drawings:
return "application/vnd.openxmlformats-officedocument.drawing+xml";
case relationship_type::extended_properties:
return "application/vnd.openxmlformats-officedocument.extended-properties+xml";
case relationship_type::external_workbook_references:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml";
case relationship_type::hyperlink:
return "";
case relationship_type::image:
return "";
case relationship_type::office_document:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
case relationship_type::pivot_table:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml";
case relationship_type::pivot_table_cache_definition:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml";
case relationship_type::pivot_table_cache_records:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml";
case relationship_type::printer_settings:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings";
case relationship_type::query_table:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml";
case relationship_type::revision_log:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml";
case relationship_type::shared_string_table:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
case relationship_type::shared_workbook:
return "";
case relationship_type::shared_workbook_revision_headers:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml";
case relationship_type::shared_workbook_user_data:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml";
case relationship_type::single_cell_table_definitions:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml";
case relationship_type::stylesheet:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml";
case relationship_type::table_definition:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml";
case relationship_type::theme:
return "application/vnd.openxmlformats-officedocument.theme+xml";
case relationship_type::thumbnail:
return "image/jpeg";
case relationship_type::unknown:
return "";
case relationship_type::vml_drawing:
return "application/vnd.openxmlformats-officedocument.vmlDrawing";
case relationship_type::volatile_dependencies:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml";
case relationship_type::worksheet:
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
} }
} }
void workbook::register_shared_string_table_in_manifest() void workbook::register_package_part(relationship_type type)
{ {
auto wb_rel = manifest().relationship(path("/"), if (!manifest().has_relationship(path("/"), type))
relationship_type::office_document);
if (!manifest().has_relationship(wb_rel.target().path(),
relationship_type::shared_string_table))
{ {
manifest().register_override_type(constants::part_shared_strings(), manifest().register_override_type(default_path(type), content_type(type));
"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"); manifest().register_relationship(uri("/"), type,
manifest().register_relationship(wb_rel.target(), relationship_type::shared_string_table, uri(default_path(type).relative_to(path("/")).string()),
uri("sharedStrings.xml"), target_mode::internal); target_mode::internal);
} }
} }
void workbook::register_stylesheet_in_manifest() void workbook::register_workbook_part(relationship_type type)
{ {
auto wb_rel = manifest().relationship(path("/"), auto wb_rel = manifest().relationship(path("/"), relationship_type::office_document);
relationship_type::office_document); auto wb_path = manifest().canonicalize({ wb_rel });
if (!manifest().has_relationship(wb_rel.target().path(), if (!manifest().has_relationship(wb_path, type))
relationship_type::stylesheet))
{ {
manifest().register_override_type(constants::part_styles(), manifest().register_override_type(default_path(type), content_type(type));
"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"); manifest().register_relationship(uri(wb_path.string()), type,
manifest().register_relationship(wb_rel.target(), relationship_type::stylesheet, uri(default_path(type).relative_to(wb_path.resolve(path("/"))).string()),
uri("styles.xml"), target_mode::internal); target_mode::internal);
} }
} }
void workbook::register_theme_in_manifest() void workbook::register_worksheet_part(worksheet ws, relationship_type type)
{
auto wb_rel = manifest().relationship(path("/"),
relationship_type::office_document);
if (!manifest().has_relationship(wb_rel.target().path(),
relationship_type::theme))
{
manifest().register_override_type(constants::part_theme(),
"application/vnd.openxmlformats-officedocument.theme+xml");
manifest().register_relationship(wb_rel.target(), relationship_type::theme,
uri("theme/theme1.xml"), target_mode::internal);
}
}
void workbook::register_comments_in_manifest(worksheet ws)
{ {
auto wb_rel = manifest().relationship(path("/"), auto wb_rel = manifest().relationship(path("/"),
relationship_type::office_document); relationship_type::office_document);
@ -435,6 +491,8 @@ void workbook::register_comments_in_manifest(worksheet ws)
d_->sheet_title_rel_id_map_.at(ws.title())); d_->sheet_title_rel_id_map_.at(ws.title()));
path ws_path(ws_rel.source().path().parent().append(ws_rel.target().path())); path ws_path(ws_rel.source().path().parent().append(ws_rel.target().path()));
if (type == relationship_type::comments)
{
if (!manifest().has_relationship(ws_path, relationship_type::vml_drawing)) if (!manifest().has_relationship(ws_path, relationship_type::vml_drawing))
{ {
std::size_t file_number = 1; std::size_t file_number = 1;
@ -498,6 +556,7 @@ void workbook::register_comments_in_manifest(worksheet ws)
uri(ws_path.string()), relationship_type::comments, uri(relative_path.string()), target_mode::internal); uri(ws_path.string()), relationship_type::comments, uri(relative_path.string()), target_mode::internal);
} }
} }
}
const worksheet workbook::sheet_by_title(const std::string &title) const const worksheet workbook::sheet_by_title(const std::string &title) const
{ {
@ -1043,8 +1102,8 @@ const theme &workbook::theme() const
void workbook::theme(const class theme &value) void workbook::theme(const class theme &value)
{ {
register_theme_in_manifest();
d_->theme_ = value; d_->theme_ = value;
register_workbook_part(relationship_type::theme);
} }
std::vector<named_range> workbook::named_ranges() const std::vector<named_range> workbook::named_ranges() const
@ -1064,7 +1123,7 @@ std::vector<named_range> workbook::named_ranges() const
format workbook::create_format(bool default_format) format workbook::create_format(bool default_format)
{ {
register_stylesheet_in_manifest(); register_workbook_part(relationship_type::stylesheet);
return d_->stylesheet_.get().create_format(default_format); return d_->stylesheet_.get().create_format(default_format);
} }
@ -1132,7 +1191,7 @@ const std::vector<rich_text> &workbook::shared_strings() const
void workbook::add_shared_string(const rich_text &shared, bool allow_duplicates) void workbook::add_shared_string(const rich_text &shared, bool allow_duplicates)
{ {
register_shared_string_table_in_manifest(); register_workbook_part(relationship_type::shared_string_table);
if (!allow_duplicates) if (!allow_duplicates)
{ {
@ -1156,8 +1215,8 @@ bool workbook::contains(const std::string &sheet_title) const
return false; return false;
} }
void workbook::thumbnail( void workbook::thumbnail(const std::vector<std::uint8_t> &thumbnail,
const std::vector<std::uint8_t> &thumbnail, const std::string &extension, const std::string &content_type) const std::string &extension, const std::string &content_type)
{ {
if (!d_->manifest_.has_relationship(path("/"), relationship_type::thumbnail)) if (!d_->manifest_.has_relationship(path("/"), relationship_type::thumbnail))
{ {

View File

@ -1007,7 +1007,7 @@ void worksheet::add_view(const sheet_view &new_view)
void worksheet::register_comments_in_manifest() void worksheet::register_comments_in_manifest()
{ {
workbook().register_comments_in_manifest(*this); workbook().register_worksheet_part(*this, relationship_type::comments);
} }
bool worksheet::has_header_footer() const bool worksheet::has_header_footer() const