mirror of
https://github.com/tfussell/xlnt.git
synced 2024-03-22 13:11:17 +08:00
start refactoring serialization code
This commit is contained in:
parent
3176ee828c
commit
c884ad7f82
|
@ -27,15 +27,20 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "../styles/style.hpp"
|
#include <xlnt/common/types.hpp>
|
||||||
#include "../common/types.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
enum class calendar;
|
enum class calendar;
|
||||||
|
|
||||||
|
class alignment;
|
||||||
|
class border;
|
||||||
class cell_reference;
|
class cell_reference;
|
||||||
class comment;
|
class comment;
|
||||||
|
class fill;
|
||||||
|
class font;
|
||||||
|
class number_format;
|
||||||
|
class protection;
|
||||||
class relationship;
|
class relationship;
|
||||||
class worksheet;
|
class worksheet;
|
||||||
|
|
||||||
|
@ -62,6 +67,9 @@ struct cell_impl;
|
||||||
class cell
|
class cell
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Enumerates the possible types a cell can be determined by it's current value.
|
||||||
|
/// </summary>
|
||||||
enum class type
|
enum class type
|
||||||
{
|
{
|
||||||
null,
|
null,
|
||||||
|
@ -72,14 +80,38 @@ public:
|
||||||
boolean
|
boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::unordered_map<std::string, int> ErrorCodes;
|
/// <summary>
|
||||||
|
/// Return a map of error strings such as #DIV/0! and their associated indices.
|
||||||
|
/// </summary>
|
||||||
|
static const std::unordered_map<std::string, int> error_codes();
|
||||||
|
|
||||||
|
//TODO: Should it be possible to construct and use a cell without a parent worksheet?
|
||||||
|
//(cont'd) If so, it would need to be responsible for allocating and deleting its PIMPL.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct a null cell without a parent.
|
||||||
|
/// Most methods will throw an exception if this cell is not further initialized.
|
||||||
|
/// </summary>
|
||||||
cell();
|
cell();
|
||||||
cell(worksheet worksheet, const cell_reference &reference);
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construct a cell in worksheet, sheet, at the given reference location (e.g. A1).
|
||||||
|
/// </summary>
|
||||||
|
cell(worksheet sheet, const cell_reference &reference);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This constructor, provided for convenience, is equivalent to calling:
|
||||||
|
/// cell c(sheet, reference);
|
||||||
|
/// c.set_value(initial_value);
|
||||||
|
/// </summary>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
cell(worksheet worksheet, const cell_reference &reference, const T &initial_value);
|
cell(worksheet sheet, const cell_reference &reference, const T &initial_value);
|
||||||
|
|
||||||
// value
|
// value
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return true if value has been set and has not been cleared using cell::clear_value().
|
||||||
|
/// </summary>
|
||||||
bool has_value() const;
|
bool has_value() const;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -93,10 +125,18 @@ public:
|
||||||
type get_data_type() const;
|
type get_data_type() const;
|
||||||
void set_data_type(type t);
|
void set_data_type(type t);
|
||||||
|
|
||||||
// characteristics
|
// properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// There's no reason to keep a cell which has no value and is not a placeholder.
|
||||||
|
/// Return true if this cell has no value, style, isn't merged, etc.
|
||||||
|
/// </summary>
|
||||||
bool garbage_collectible() const;
|
bool garbage_collectible() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return true iff this cell's number format matches a date format.
|
||||||
|
/// </summary>
|
||||||
bool is_date() const;
|
bool is_date() const;
|
||||||
std::size_t get_xf_index() const;
|
|
||||||
|
|
||||||
// position
|
// position
|
||||||
cell_reference get_reference() const;
|
cell_reference get_reference() const;
|
||||||
|
@ -176,6 +216,7 @@ public:
|
||||||
bool operator==(const cell &comparand) const;
|
bool operator==(const cell &comparand) const;
|
||||||
bool operator==(std::nullptr_t) const;
|
bool operator==(std::nullptr_t) const;
|
||||||
|
|
||||||
|
// friend operators, so we can put cell on either side of comparisons with other types
|
||||||
friend bool operator==(std::nullptr_t, const cell &cell);
|
friend bool operator==(std::nullptr_t, const cell &cell);
|
||||||
friend bool operator<(cell left, cell right);
|
friend bool operator<(cell left, cell right);
|
||||||
|
|
||||||
|
@ -188,6 +229,10 @@ private:
|
||||||
detail::cell_impl *d_;
|
detail::cell_impl *d_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience function for writing cell to an ostream.
|
||||||
|
/// Uses cell::to_string() internally.
|
||||||
|
/// </summary>
|
||||||
inline std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
|
inline std::ostream &operator<<(std::ostream &stream, const xlnt::cell &cell)
|
||||||
{
|
{
|
||||||
return stream << cell.to_string();
|
return stream << cell.to_string();
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class comment_reader
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,88 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "xlnt/workbook/workbook.hpp"
|
|
||||||
|
|
||||||
namespace pugi {
|
|
||||||
class xml_node;
|
|
||||||
} // namespace pugi
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class border;
|
|
||||||
class fill;
|
|
||||||
class font;
|
|
||||||
class named_style;
|
|
||||||
class number_format;
|
|
||||||
class style;
|
|
||||||
class zip_file;
|
|
||||||
|
|
||||||
class style_reader
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
style_reader(workbook &wb);
|
|
||||||
|
|
||||||
void read_styles(zip_file &archive);
|
|
||||||
|
|
||||||
const std::vector<style> &get_styles() const { return styles_; }
|
|
||||||
|
|
||||||
const std::vector<border> &get_borders() const { return borders_; }
|
|
||||||
const std::vector<fill> &get_fills() const { return fills_; }
|
|
||||||
const std::vector<font> &get_fonts() const { return fonts_; }
|
|
||||||
const std::vector<number_format> &get_number_formats() const { return number_formats_; }
|
|
||||||
const std::vector<std::string> &get_colors() const { return colors_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
style read_style(pugi::xml_node stylesheet_node, pugi::xml_node xf_node);
|
|
||||||
|
|
||||||
void read_borders(pugi::xml_node borders_node);
|
|
||||||
void read_fills(pugi::xml_node fills_node);
|
|
||||||
void read_fonts(pugi::xml_node fonts_node);
|
|
||||||
void read_number_formats(pugi::xml_node num_fmt_node);
|
|
||||||
void read_colors(pugi::xml_node colors_node);
|
|
||||||
|
|
||||||
void read_dxfs();
|
|
||||||
void read_named_styles(pugi::xml_node named_styles_node);
|
|
||||||
void read_style_names();
|
|
||||||
void read_cell_styles();
|
|
||||||
void read_xfs();
|
|
||||||
void read_style_table();
|
|
||||||
|
|
||||||
workbook wb_;
|
|
||||||
|
|
||||||
std::vector<style> styles_;
|
|
||||||
|
|
||||||
std::vector<std::string> colors_;
|
|
||||||
std::vector<border> borders_;
|
|
||||||
std::vector<fill> fills_;
|
|
||||||
std::vector<font> fonts_;
|
|
||||||
std::vector<number_format> number_formats_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -23,43 +23,28 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "charts/chart.h"
|
#include <xlnt/cell/comment.hpp>
|
||||||
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class chart_writer
|
class xml_node;
|
||||||
|
|
||||||
|
class comment_serializer
|
||||||
{
|
{
|
||||||
|
comment_serializer(worksheet sheet);
|
||||||
|
|
||||||
};
|
void read_comments(const xml_node &xml);
|
||||||
|
void read_comments_vml(const xml_node &xml);
|
||||||
|
|
||||||
class pie_chart_writer : public chart_writer
|
xml_node write_comments();
|
||||||
{
|
xml_node write_comments_vml();
|
||||||
|
|
||||||
};
|
private:
|
||||||
|
worksheet sheet_;
|
||||||
class pie_chart_writer : public chart_writer
|
std::vector<comment> comments_;
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class pie_chart_writer : public chart_writer
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class pie_chart_writer : public chart_writer
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class chart_writer_factory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static std::unique_ptr<chart_writer> create_writer(chart c);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
|
@ -23,23 +23,53 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iostream>
|
#include <cstdint>
|
||||||
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xlnt/common/zip_file.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class workbook;
|
class workbook;
|
||||||
|
|
||||||
class excel_reader
|
class excel_serializer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::string CentralDirectorySignature();
|
static std::string central_directory_signature();
|
||||||
static std::string repair_central_directory(const std::string &original);
|
static std::string repair_central_directory(const std::string &original);
|
||||||
|
|
||||||
static workbook load_workbook(std::istream &stream, bool guess_types = false, bool data_only = false);
|
excel_serializer(workbook &wb);
|
||||||
static workbook load_workbook(const std::string &filename, bool guess_types = false, bool data_only = false);
|
|
||||||
static workbook load_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types = false, bool data_only = false);
|
bool load_workbook(const std::string &filename, bool guess_types = false, bool data_only = false);
|
||||||
|
bool load_stream_workbook(std::istream &stream, bool guess_types = false, bool data_only = false);
|
||||||
|
bool load_virtual_workbook(const std::vector<std::uint8_t> &bytes, bool guess_types = false, bool data_only = false);
|
||||||
|
|
||||||
|
bool save_workbook(workbook &wb, const std::string &filename, bool as_template = false);
|
||||||
|
bool save_virtual_workbook(xlnt::workbook &wb, std::vector<std::uint8_t> &bytes, bool as_template = false);
|
||||||
|
bool save_stream_workbook(xlnt::workbook &wb, std::ostream &stream, bool as_template = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void read_data(bool guess_types, bool data_only);
|
||||||
|
void read_shared_strings();
|
||||||
|
void read_images();
|
||||||
|
void read_charts();
|
||||||
|
void read_chartsheets();
|
||||||
|
void read_worksheets();
|
||||||
|
void read_external_links();
|
||||||
|
|
||||||
|
void write_data(bool as_template);
|
||||||
|
void write_shared_strings();
|
||||||
|
void write_images();
|
||||||
|
void write_charts();
|
||||||
|
void write_chartsheets();
|
||||||
|
void write_worksheets();
|
||||||
|
void write_external_links();
|
||||||
|
|
||||||
|
workbook &wb_;
|
||||||
|
std::vector<std::string> shared_strings_;
|
||||||
|
zip_file archive_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
24
include/xlnt/s11n/manifest_serializer.hpp
Normal file
24
include/xlnt/s11n/manifest_serializer.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class manifest;
|
||||||
|
class workbook;
|
||||||
|
class xml_document;
|
||||||
|
class zip_file;
|
||||||
|
|
||||||
|
class manifest_serializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
manifest_serializer(manifest &m);
|
||||||
|
|
||||||
|
bool read_mainfest(const xml_document &xml);
|
||||||
|
bool write_manifest(xml_document &xml);
|
||||||
|
|
||||||
|
private:
|
||||||
|
manifest &manifest_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace xlnt
|
17
include/xlnt/s11n/relationship_serializer.hpp
Normal file
17
include/xlnt/s11n/relationship_serializer.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class relationship;
|
||||||
|
class xml_document;
|
||||||
|
|
||||||
|
class relationship_serializer
|
||||||
|
{
|
||||||
|
bool read_relationships(const xml_document &xml, const std::string &dir, std::vector<relationship> &relationships);
|
||||||
|
bool write_relationships(const std::vector<relationship> &relationships, const std::string &dir, xml_document &xml);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -28,15 +28,13 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class zip_file;
|
class xml_document;
|
||||||
|
|
||||||
class shared_strings_reader
|
class shared_strings_serializer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<std::string> read_strings(zip_file &archive);
|
bool read_strings(const xml_document &xml, std::vector<std::string> &strings);
|
||||||
void read_string_table(const std::string &xml_source);
|
bool write_strings(const std::vector<std::string> &strings, xml_document &xml);
|
||||||
std::string get_string();
|
|
||||||
std::string get_text();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
255
include/xlnt/s11n/style_serializer.hpp
Normal file
255
include/xlnt/s11n/style_serializer.hpp
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
// Copyright (c) 2015 Thomas Fussell
|
||||||
|
// Copyright (c) 2010-2015 openpyxl
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE
|
||||||
|
//
|
||||||
|
// @license: http://www.opensource.org/licenses/mit-license.php
|
||||||
|
// @author: see AUTHORS file
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class alignment;
|
||||||
|
class border;
|
||||||
|
class color;
|
||||||
|
class conditional_format;
|
||||||
|
class fill;
|
||||||
|
class font;
|
||||||
|
class named_style;
|
||||||
|
class number_format;
|
||||||
|
class protection;
|
||||||
|
class side;
|
||||||
|
class style;
|
||||||
|
class xml_document;
|
||||||
|
class xml_node;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads and writes xl/styles.xml from/to an associated workbook.
|
||||||
|
/// </summary>
|
||||||
|
class style_serializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// <summary>
|
||||||
|
/// Construct a style_serializer which can write styles.xml based on wb or populate wb
|
||||||
|
/// with styles from an existing styles.xml.
|
||||||
|
style_serializer(workbook &wb);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load all styles from xml_document into workbook given in constructor.
|
||||||
|
/// </summary>
|
||||||
|
bool read_stylesheet(const xml_document &xml);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Populate parameter xml with an XML tree representing the styles contained in the workbook
|
||||||
|
/// given in the constructor.
|
||||||
|
/// </summary>
|
||||||
|
bool write_stylesheet(xml_document &xml) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// <summary>
|
||||||
|
/// Read a single style from the given node. In styles.xml, this is an "xf" element.
|
||||||
|
/// A style has an optional border id, fill id, font id, and number format id where
|
||||||
|
/// each id is an index in the corresponding list of borders, etc. A style also has
|
||||||
|
/// optional alignment and protection children. A style also defines whether each of
|
||||||
|
/// these is "applied". For example, a style with a defined font id, font=# but with
|
||||||
|
/// "applyFont=0" will not use the font in formatting.
|
||||||
|
/// </summary>
|
||||||
|
style read_style(const xml_node &style_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return an alignment from alignment_node.
|
||||||
|
/// </summary>
|
||||||
|
alignment read_alignment(const xml_node &alignment_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a border side from side_node.
|
||||||
|
/// </summary>
|
||||||
|
side read_side(const xml_node &side_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read all borders from borders_node and add them to workbook.
|
||||||
|
/// Return true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool read_borders(const xml_node &borders_node);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a border from border_node.
|
||||||
|
/// </summary>
|
||||||
|
border read_border(const xml_node &border_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read all fills from fills_node and add them to workbook.
|
||||||
|
/// Return true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool read_fills(const xml_node &fills_node);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a fill from fill_node.
|
||||||
|
/// </summary>
|
||||||
|
fill read_fill(const xml_node &fill_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read all fonts from fonts_node and add them to workbook.
|
||||||
|
/// Return true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool read_fonts(const xml_node &fonts_node);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a font from font_node.
|
||||||
|
/// </summary>
|
||||||
|
font read_font(const xml_node &font_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read all borders from number_formats_node and add them to workbook.
|
||||||
|
/// Return true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool read_number_formats(const xml_node &number_formats_node);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a number format from number_format_node.
|
||||||
|
/// </summary>
|
||||||
|
number_format read_number_format(const xml_node &number_format_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a protection from protection_node.
|
||||||
|
/// </summary>
|
||||||
|
protection read_protection(const xml_node &protection_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read all colors from colors_node and add them to workbook.
|
||||||
|
/// Return true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool read_colors(const xml_node &colors_node);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return all indexed colors from indexed_colors_node.
|
||||||
|
/// </summary>
|
||||||
|
std::vector<color> read_indexed_colors(const xml_node &indexed_colors_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a color from color_node.
|
||||||
|
/// </summary>
|
||||||
|
color read_color(const xml_node &color_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a conditional format, dxf, from conditional_format_node.
|
||||||
|
/// </summary>
|
||||||
|
conditional_format read_conditional_format(const xml_node &conditional_formats_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read all named styles from named_style_node and cell_styles_node and add them to workbook.
|
||||||
|
/// Return true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool read_named_styles(const xml_node &named_styles_node);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read and return a pair containing a name and corresponding style from named_style_node.
|
||||||
|
/// </summary>
|
||||||
|
std::pair<std::string, style> read_named_style(const xml_node &named_style_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build and return an xml tree representing alignment_.
|
||||||
|
/// </summary>
|
||||||
|
xml_node write_alignment(const alignment &alignment_) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build and return an xml tree representing border_.
|
||||||
|
/// </summary>
|
||||||
|
xml_node write_border(const border &border_) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build an xml tree representing all borders in workbook into borders_node.
|
||||||
|
/// Returns true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool write_borders(xml_node &borders_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build and return an xml tree representing fill_.
|
||||||
|
/// </summary>
|
||||||
|
xml_node write_fill(const fill &fill_) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build an xml tree representing all fills in workbook into fills_node.
|
||||||
|
/// Returns true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool write_fills(xml_node &fills_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build and return an xml tree representing font_.
|
||||||
|
/// </summary>
|
||||||
|
xml_node write_font(const font &font_) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build an xml tree representing all fonts in workbook into fonts_node.
|
||||||
|
/// Returns true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool write_fonts(xml_node &fonts_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build and return an xml tree representing number_format_.
|
||||||
|
/// </summary>
|
||||||
|
xml_node write_number_format(const number_format &number_format_) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build an xml tree representing all number formats in workbook into number_formats_node.
|
||||||
|
/// Returns true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool write_number_formats(xml_node &fonts_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build and return two xml trees, first=cell style and second=named style, representing named_style_.
|
||||||
|
/// </summary>
|
||||||
|
std::pair<xml_node, xml_node> write_named_style(const named_style &named_style_) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build an xml tree representing all named styles in workbook into named_styles_node and cell_styles_node.
|
||||||
|
/// Returns true on success.
|
||||||
|
/// </summary>
|
||||||
|
void write_named_styles(xml_node &named_styles_node, xml_node &cell_styles_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build an xml tree representing the given style into style_node.
|
||||||
|
/// Returns true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool write_style(const style &style_, xml_node &style_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build and return an xml tree representing conditional_format_.
|
||||||
|
/// </summary>
|
||||||
|
xml_node write_conditional_format(const conditional_format &conditional_format_) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build an xml tree representing all conditional formats in workbook into conditional_formats_node.
|
||||||
|
/// Returns true on success.
|
||||||
|
/// </summary>
|
||||||
|
bool write_conditional_formats(xml_node &conditional_formats_node) const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set in the constructor, this workbook is used as the source or target for all writing or reading, respectively.
|
||||||
|
/// </summary>
|
||||||
|
workbook &wb_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -27,7 +27,11 @@
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
std::string write_theme();
|
class theme_serializer
|
||||||
//void write_theme(const theme &t);
|
{
|
||||||
|
public:
|
||||||
|
theme read_theme(const xml_document &xml);
|
||||||
|
xml_document write_theme(const theme &theme_);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
|
@ -23,23 +23,44 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class document_properties;
|
class document_properties;
|
||||||
|
class manifest;
|
||||||
class relationship;
|
class relationship;
|
||||||
|
class worksheet;
|
||||||
class workbook;
|
class workbook;
|
||||||
class zip_file;
|
class zip_file;
|
||||||
|
class xml_document;
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> read_content_types(zip_file &archive);
|
class workbook_serializer
|
||||||
std::string determine_document_type(const std::vector<std::pair<std::string, std::string>> &override_types);
|
{
|
||||||
document_properties read_properties_core(const std::string &xml_string);
|
public:
|
||||||
|
workbook_serializer(workbook &wb);
|
||||||
|
|
||||||
std::vector<std::pair<std::string,std::string>> read_sheets(zip_file &archive);
|
void read_workbook(const xml_document &xml);
|
||||||
std::vector<std::pair<std::string, std::string>> detect_worksheets(zip_file &archive);
|
void read_properties_app(const xml_document &xml);
|
||||||
std::vector<relationship> read_relationships(zip_file &content, const std::string &filename);
|
void read_properties_core(const xml_document &xml);
|
||||||
|
|
||||||
|
xml_document write_workbook() const;
|
||||||
|
xml_document write_properties_app() const;
|
||||||
|
xml_document write_properties_core() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//workbook_view, sheets, sheet, defined_names
|
||||||
|
std::string determine_document_type(const manifest &manifest_);
|
||||||
|
|
||||||
|
using string_pair = std::pair<std::string, std::string>;
|
||||||
|
|
||||||
|
std::vector<string_pair> read_sheets(zip_file &archive);
|
||||||
|
std::vector<string_pair> detect_worksheets(zip_file &archive);
|
||||||
|
|
||||||
|
std::string write_defined_names(const workbook &wb);
|
||||||
|
|
||||||
|
workbook &wb_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
|
@ -26,13 +26,27 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xlnt/worksheet/worksheet.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class relationship;
|
class relationship;
|
||||||
class workbook;
|
class workbook;
|
||||||
class zip_file;
|
class worksheet;
|
||||||
|
class xml_document;
|
||||||
|
class xml_node;
|
||||||
|
|
||||||
void read_worksheet(worksheet ws, zip_file &archive, const relationship &rel, const std::vector<std::string> &shared_strings);
|
class worksheet_serializer
|
||||||
std::string read_dimension(const std::string &xml_string);
|
{
|
||||||
|
public:
|
||||||
|
worksheet_serializer(worksheet sheet);
|
||||||
|
|
||||||
|
bool read_worksheet(const xml_document &xml, const std::vector<std::string> &shared_strings, const relationship &rel, worksheet ws);
|
||||||
|
std::string read_dimension(const xml_node &dimension_node);
|
||||||
|
bool write_worksheet(const worksheet ws, const std::vector<std::string> &string_table, xml_document &xml);
|
||||||
|
|
||||||
|
private:
|
||||||
|
worksheet sheet_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
25
include/xlnt/s11n/xml_document.hpp
Normal file
25
include/xlnt/s11n/xml_document.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xlnt/s11n/xml_node.hpp>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class xml_document
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void set_encoding(const std::string &encoding);
|
||||||
|
void add_namespace(const std::string &id, const std::string &uri);
|
||||||
|
|
||||||
|
xml_node &root();
|
||||||
|
const xml_node &root() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
xml_node root_;
|
||||||
|
std::string encoding_;
|
||||||
|
std::vector<string_pair> namespaces_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
42
include/xlnt/s11n/xml_node.hpp
Normal file
42
include/xlnt/s11n/xml_node.hpp
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
using string_pair = std::pair<std::string, std::string>;
|
||||||
|
|
||||||
|
class xml_node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
xml_node();
|
||||||
|
explicit xml_node(const std::string &name);
|
||||||
|
|
||||||
|
std::string get_name() const;
|
||||||
|
void set_name(const std::string &name);
|
||||||
|
|
||||||
|
bool has_text() const;
|
||||||
|
std::string get_text() const;
|
||||||
|
void set_text(const std::string &text);
|
||||||
|
|
||||||
|
const std::vector<xml_node> &get_children() const;
|
||||||
|
bool has_child(const std::string &child_name) const;
|
||||||
|
const xml_node &get_child(const std::string &child_name) const;
|
||||||
|
xml_node &add_child(const xml_node &child);
|
||||||
|
xml_node &add_child(const std::string &child_name);
|
||||||
|
|
||||||
|
const std::vector<string_pair> &get_attributes() const;
|
||||||
|
bool has_attribute(const std::string &attribute_name) const;
|
||||||
|
std::string get_attribute(const std::string &attribute_name) const;
|
||||||
|
void add_attribute(const std::string &name, const std::string &value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name_;
|
||||||
|
bool has_text_ = false;
|
||||||
|
std::string text_;
|
||||||
|
std::vector<string_pair> attributes_;
|
||||||
|
std::vector<xml_node> children_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
16
include/xlnt/s11n/xml_serializer.hpp
Normal file
16
include/xlnt/s11n/xml_serializer.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class xml_document;
|
||||||
|
|
||||||
|
class xml_serializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string serialize(const xml_document &xml);
|
||||||
|
static xml_document deserialize(const std::string &xml_string);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -23,6 +23,10 @@
|
||||||
// @author: see AUTHORS file
|
// @author: see AUTHORS file
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <xlnt/common/hash_combine.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
class color
|
class color
|
||||||
|
@ -57,12 +61,6 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const color &other) const
|
|
||||||
{
|
|
||||||
if(type_ != other.type_) return false;
|
|
||||||
return index_ == other.index_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_auto(int auto_index)
|
void set_auto(int auto_index)
|
||||||
{
|
{
|
||||||
type_ = type::auto_;
|
type_ = type::auto_;
|
||||||
|
@ -126,6 +124,27 @@ public:
|
||||||
return rgb_string_;
|
return rgb_string_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t hash() const
|
||||||
|
{
|
||||||
|
auto seed = static_cast<std::size_t>(type_);
|
||||||
|
|
||||||
|
if(type_ != type::rgb)
|
||||||
|
{
|
||||||
|
hash_combine(seed, index_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hash_combine(seed, rgb_string_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const color &other) const
|
||||||
|
{
|
||||||
|
return hash() == other.hash();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
type type_ = type::indexed;
|
type type_ = type::indexed;
|
||||||
int index_ = 0;
|
int index_ = 0;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include "../common/hash_combine.hpp"
|
#include <xlnt/styles/color.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -73,8 +73,7 @@ public:
|
||||||
|
|
||||||
if(color_assigned_)
|
if(color_assigned_)
|
||||||
{
|
{
|
||||||
hash_combine(seed, static_cast<std::size_t>(color_type_));
|
hash_combine(seed, color_.hash());
|
||||||
hash_combine(seed, color_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return seed;
|
return seed;
|
||||||
|
@ -85,12 +84,7 @@ public:
|
||||||
return style_;
|
return style_;
|
||||||
}
|
}
|
||||||
|
|
||||||
color_type get_color_type() const
|
color get_color() const
|
||||||
{
|
|
||||||
return color_type_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t get_color() const
|
|
||||||
{
|
{
|
||||||
return color_;
|
return color_;
|
||||||
}
|
}
|
||||||
|
@ -107,7 +101,7 @@ public:
|
||||||
|
|
||||||
bool operator==(const side &other) const
|
bool operator==(const side &other) const
|
||||||
{
|
{
|
||||||
return other.style_ == style_ && color_type_ == other.color_type_ && color_ == other.color_;
|
return other.style_ == style_ && color_ == other.color_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_border_style(border_style bs)
|
void set_border_style(border_style bs)
|
||||||
|
@ -116,19 +110,17 @@ public:
|
||||||
style_ = bs;
|
style_ = bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_color(color_type type, std::size_t color)
|
void set_color(color new_color)
|
||||||
{
|
{
|
||||||
color_assigned_ = true;
|
color_assigned_ = true;
|
||||||
color_type_ = type;
|
color_ = new_color;
|
||||||
color_ = color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool style_assigned_ = false;
|
bool style_assigned_ = false;
|
||||||
border_style style_ = border_style::none;
|
border_style style_ = border_style::none;
|
||||||
bool color_assigned_ = false;
|
bool color_assigned_ = false;
|
||||||
color_type color_type_ = color_type::indexed;
|
color color_ = color::black;
|
||||||
std::size_t color_ = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -72,8 +72,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class style_reader;
|
friend class style_serializer;
|
||||||
friend class style_writer;
|
|
||||||
friend class workbook;
|
friend class workbook;
|
||||||
|
|
||||||
std::size_t id_;
|
std::size_t id_;
|
||||||
|
|
60
include/xlnt/workbook/manifest.hpp
Normal file
60
include/xlnt/workbook/manifest.hpp
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class default_type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
default_type();
|
||||||
|
default_type(const std::string &extension, const std::string &content_type);
|
||||||
|
default_type(const default_type &other);
|
||||||
|
default_type &operator=(const default_type &other);
|
||||||
|
|
||||||
|
std::string get_extension() const { return extension_; }
|
||||||
|
std::string get_content_type() const { return content_type_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string extension_;
|
||||||
|
std::string content_type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class override_type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
override_type();
|
||||||
|
override_type(const std::string &extension, const std::string &content_type);
|
||||||
|
override_type(const override_type &other);
|
||||||
|
override_type &operator=(const override_type &other);
|
||||||
|
|
||||||
|
std::string get_part_name() const { return part_name_; }
|
||||||
|
std::string get_content_type() const { return content_type_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string part_name_;
|
||||||
|
std::string content_type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class manifest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void add_default_type(const std::string &extension, const std::string &content_type);
|
||||||
|
void add_override_type(const std::string &part_name, const std::string &content_type);
|
||||||
|
|
||||||
|
const std::vector<default_type> &get_default_types() const { return default_types_; }
|
||||||
|
const std::vector<override_type> &get_override_types() const { return override_types_; }
|
||||||
|
|
||||||
|
bool has_default_type(const std::string &extension) const;
|
||||||
|
bool has_override_type(const std::string &part_name) const;
|
||||||
|
|
||||||
|
std::string get_default_type(const std::string &extension) const;
|
||||||
|
std::string get_override_type(const std::string &part_name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<default_type> default_types_;
|
||||||
|
std::vector<override_type> override_types_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
10
include/xlnt/workbook/theme.hpp
Normal file
10
include/xlnt/workbook/theme.hpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
class theme
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -29,7 +29,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "../common/relationship.hpp"
|
#include <xlnt/common/relationship.hpp>
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ class document_properties;
|
||||||
class drawing;
|
class drawing;
|
||||||
class fill;
|
class fill;
|
||||||
class font;
|
class font;
|
||||||
|
class manifest;
|
||||||
class named_range;
|
class named_range;
|
||||||
class number_format;
|
class number_format;
|
||||||
class pattern_fill;
|
class pattern_fill;
|
||||||
|
@ -242,6 +243,9 @@ public:
|
||||||
const style &get_style(std::size_t style_id) const;
|
const style &get_style(std::size_t style_id) const;
|
||||||
std::size_t add_style(const style &style_);
|
std::size_t add_style(const style &style_);
|
||||||
|
|
||||||
|
manifest &get_manifest();
|
||||||
|
const manifest &get_manifest() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class worksheet;
|
friend class worksheet;
|
||||||
std::shared_ptr<detail::workbook_impl> d_;
|
std::shared_ptr<detail::workbook_impl> d_;
|
||||||
|
|
|
@ -262,8 +262,8 @@ public:
|
||||||
const range operator()(const cell_reference &top_left, const cell_reference &bottom_right) const;
|
const range operator()(const cell_reference &top_left, const cell_reference &bottom_right) const;
|
||||||
|
|
||||||
// page
|
// page
|
||||||
page_setup &get_page_setup();
|
const page_setup &get_page_setup() const;
|
||||||
margins &get_page_margins();
|
const margins &get_page_margins() const;
|
||||||
|
|
||||||
// auto filter
|
// auto filter
|
||||||
range_reference get_auto_filter() const;
|
range_reference get_auto_filter() const;
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class comment_writer
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,56 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class workbook;
|
|
||||||
class zip_file;
|
|
||||||
|
|
||||||
class excel_writer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
excel_writer(workbook &wb);
|
|
||||||
|
|
||||||
void save(const std::string &filename, bool as_template);
|
|
||||||
|
|
||||||
void write_data(zip_file &archive, bool as_template);
|
|
||||||
void write_shared_strings(zip_file &archive, const std::vector<std::string> &shared_strings);
|
|
||||||
void write_images(zip_file &archive);
|
|
||||||
void write_charts(zip_file &archive);
|
|
||||||
void write_chartsheets(zip_file &archive);
|
|
||||||
void write_worksheets(zip_file &archive, const std::vector<std::string> &shared_strings);
|
|
||||||
void write_external_links(zip_file &archive);
|
|
||||||
|
|
||||||
private:
|
|
||||||
workbook wb_;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool save_workbook(workbook &wb, const std::string &filename, bool as_template = false);
|
|
||||||
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template = false);
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,11 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class workbook;
|
|
||||||
|
|
||||||
std::string write_content_types(const workbook &wb, bool as_template = false);
|
|
||||||
|
|
||||||
};
|
|
|
@ -1,12 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class relationship;
|
|
||||||
|
|
||||||
std::string write_relationships(const std::vector<relationship> &relationships, const std::string &dir);
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,33 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class string_writer
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,61 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "../styles/style.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class workbook;
|
|
||||||
|
|
||||||
class style_writer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
style_writer(workbook &wb);
|
|
||||||
style_writer(const style_writer &);
|
|
||||||
style_writer &operator=(const style_writer &);
|
|
||||||
|
|
||||||
std::string write_table() 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;
|
|
||||||
std::unordered_map<int, std::string> write_fills() const;
|
|
||||||
std::unordered_map<int, std::string> write_borders() const;
|
|
||||||
void write_cell_style_xfs();
|
|
||||||
void write_cell_xfs();
|
|
||||||
void write_cell_style();
|
|
||||||
void write_dxfs();
|
|
||||||
void write_table_styles();
|
|
||||||
|
|
||||||
workbook &wb_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,43 +0,0 @@
|
||||||
// Copyright (c) 2015 Thomas Fussell
|
|
||||||
// Copyright (c) 2010-2015 openpyxl
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in
|
|
||||||
// all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
// THE SOFTWARE
|
|
||||||
//
|
|
||||||
// @license: http://www.opensource.org/licenses/mit-license.php
|
|
||||||
// @author: see AUTHORS file
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <xlnt/writer/style_writer.hpp>
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
std::string write_shared_strings(const std::vector<std::string> &string_table);
|
|
||||||
std::string write_properties_core(const document_properties &prop);
|
|
||||||
std::string write_worksheet_rels(worksheet ws);
|
|
||||||
std::string write_theme();
|
|
||||||
std::string write_properties_app(const workbook &wb);
|
|
||||||
std::string write_root_rels(const workbook &wb);
|
|
||||||
std::string write_workbook(const workbook &wb);
|
|
||||||
std::string write_workbook_rels(const workbook &wb);
|
|
||||||
std::string write_defined_names(const xlnt::workbook &wb);
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,13 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
class worksheet;
|
|
||||||
|
|
||||||
std::string write_worksheet(worksheet ws, const std::vector<std::string> &string_table);
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -799,15 +799,20 @@ std::string format_text(const std::string &text, const std::string &format)
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
const std::unordered_map<std::string, int> cell::ErrorCodes =
|
const std::unordered_map<std::string, int> cell::error_codes()
|
||||||
{
|
{
|
||||||
{"#NULL!", 0},
|
static const std::unordered_map<std::string, int> codes =
|
||||||
{"#DIV/0!", 1},
|
{
|
||||||
{"#VALUE!", 2},
|
{"#NULL!", 0},
|
||||||
{"#REF!", 3},
|
{"#DIV/0!", 1},
|
||||||
{"#NAME?", 4},
|
{"#VALUE!", 2},
|
||||||
{"#NUM!", 5},
|
{"#REF!", 3},
|
||||||
{"#N/A!", 6}
|
{"#NAME?", 4},
|
||||||
|
{"#NUM!", 5},
|
||||||
|
{"#N/A!", 6}
|
||||||
|
};
|
||||||
|
|
||||||
|
return codes;
|
||||||
};
|
};
|
||||||
|
|
||||||
cell::cell() : d_(nullptr)
|
cell::cell() : d_(nullptr)
|
||||||
|
@ -1271,11 +1276,6 @@ void cell::set_data_type(type t)
|
||||||
d_->type_ = t;
|
d_->type_ = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t cell::get_xf_index() const
|
|
||||||
{
|
|
||||||
return d_->xf_index_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const number_format &cell::get_number_format() const
|
const number_format &cell::get_number_format() const
|
||||||
{
|
{
|
||||||
static const number_format default_format;
|
static const number_format default_format;
|
||||||
|
|
|
@ -22,7 +22,6 @@ cell_impl::cell_impl(worksheet_impl *parent, column_t column, row_t row)
|
||||||
value_numeric_(0),
|
value_numeric_(0),
|
||||||
has_hyperlink_(false),
|
has_hyperlink_(false),
|
||||||
is_merged_(false),
|
is_merged_(false),
|
||||||
xf_index_(0),
|
|
||||||
has_style_(false),
|
has_style_(false),
|
||||||
style_id_(0),
|
style_id_(0),
|
||||||
comment_(nullptr)
|
comment_(nullptr)
|
||||||
|
|
|
@ -140,7 +140,7 @@ struct cell_impl
|
||||||
type_ = cell::type::formula;
|
type_ = cell::type::formula;
|
||||||
value_string_.clear();
|
value_string_.clear();
|
||||||
}
|
}
|
||||||
else if(cell::ErrorCodes.find(s) != cell::ErrorCodes.end())
|
else if(cell::error_codes().find(s) != cell::error_codes().end())
|
||||||
{
|
{
|
||||||
type_ = cell::type::error;
|
type_ = cell::type::error;
|
||||||
}
|
}
|
||||||
|
@ -195,8 +195,6 @@ struct cell_impl
|
||||||
|
|
||||||
bool is_merged_;
|
bool is_merged_;
|
||||||
|
|
||||||
std::size_t xf_index_;
|
|
||||||
|
|
||||||
bool has_style_;
|
bool has_style_;
|
||||||
std::size_t style_id_;
|
std::size_t style_id_;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ struct workbook_impl
|
||||||
borders_(other.borders_),
|
borders_(other.borders_),
|
||||||
fills_(other.fills_),
|
fills_(other.fills_),
|
||||||
fonts_(other.fonts_),
|
fonts_(other.fonts_),
|
||||||
number_formats_(other.number_formats_)
|
number_formats_(other.number_formats_),
|
||||||
|
manifest_(other.manifest_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +46,7 @@ struct workbook_impl
|
||||||
fonts_ = other.fonts_;
|
fonts_ = other.fonts_;
|
||||||
number_formats_ = other.number_formats_;
|
number_formats_ = other.number_formats_;
|
||||||
colors_ = other.colors_;
|
colors_ = other.colors_;
|
||||||
|
manifest_ = other.manifest_;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -69,6 +71,7 @@ struct workbook_impl
|
||||||
std::vector<font> fonts_;
|
std::vector<font> fonts_;
|
||||||
std::vector<number_format> number_formats_;
|
std::vector<number_format> number_formats_;
|
||||||
|
|
||||||
|
manifest manifest_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#include <xlnt/common/zip_file.hpp>
|
|
||||||
#include <xlnt/reader/shared_strings_reader.hpp>
|
|
||||||
|
|
||||||
#include "detail/include_pugixml.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
std::vector<std::string> shared_strings_reader::read_strings(zip_file &archive)
|
|
||||||
{
|
|
||||||
static const std::string shared_strings_filename = "xl/sharedStrings.xml";
|
|
||||||
|
|
||||||
if(!archive.has_file(shared_strings_filename))
|
|
||||||
{
|
|
||||||
return { };
|
|
||||||
}
|
|
||||||
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.load(archive.read(shared_strings_filename).c_str());
|
|
||||||
|
|
||||||
auto root_node = doc.child("sst");
|
|
||||||
int unique_count = root_node.attribute("uniqueCount").as_int();
|
|
||||||
|
|
||||||
std::vector<std::string> shared_strings;
|
|
||||||
|
|
||||||
for(auto si_node : root_node)
|
|
||||||
{
|
|
||||||
shared_strings.push_back(si_node.child("t").text().as_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(unique_count != (int)shared_strings.size())
|
|
||||||
{
|
|
||||||
throw std::runtime_error("counts don't match");
|
|
||||||
}
|
|
||||||
|
|
||||||
return shared_strings;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,484 +0,0 @@
|
||||||
#include <xlnt/common/zip_file.hpp>
|
|
||||||
#include <xlnt/styles/border.hpp>
|
|
||||||
#include <xlnt/styles/fill.hpp>
|
|
||||||
#include <xlnt/styles/font.hpp>
|
|
||||||
#include <xlnt/styles/named_style.hpp>
|
|
||||||
#include <xlnt/styles/number_format.hpp>
|
|
||||||
#include <xlnt/styles/style.hpp>
|
|
||||||
#include <xlnt/reader/style_reader.hpp>
|
|
||||||
|
|
||||||
#include "detail/include_pugixml.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
protection read_protection(pugi::xml_node node)
|
|
||||||
{
|
|
||||||
auto prot_type_from_string = [](const std::string &type_string)
|
|
||||||
{
|
|
||||||
if(type_string == "true") return protection::type::protected_;
|
|
||||||
else if(type_string == "inherit") return protection::type::inherit;
|
|
||||||
return protection::type::unprotected;
|
|
||||||
};
|
|
||||||
|
|
||||||
protection prot;
|
|
||||||
prot.set_locked(prot_type_from_string(node.attribute("locked").as_string()));
|
|
||||||
prot.set_hidden(prot_type_from_string(node.attribute("hidden").as_string()));
|
|
||||||
return prot;
|
|
||||||
}
|
|
||||||
|
|
||||||
alignment read_alignment(pugi::xml_node node)
|
|
||||||
{
|
|
||||||
alignment align;
|
|
||||||
|
|
||||||
align.set_wrap_text(node.attribute("wrapText").as_bool());
|
|
||||||
|
|
||||||
bool has_vertical = node.attribute("vertical") != nullptr;
|
|
||||||
std::string vertical = has_vertical ? node.attribute("vertical").as_string() : "";
|
|
||||||
|
|
||||||
if(has_vertical)
|
|
||||||
{
|
|
||||||
if(vertical == "bottom")
|
|
||||||
{
|
|
||||||
align.set_vertical(alignment::vertical_alignment::bottom);
|
|
||||||
}
|
|
||||||
else if(vertical =="center")
|
|
||||||
{
|
|
||||||
align.set_vertical(alignment::vertical_alignment::center);
|
|
||||||
}
|
|
||||||
else if(vertical =="justify")
|
|
||||||
{
|
|
||||||
align.set_vertical(alignment::vertical_alignment::justify);
|
|
||||||
}
|
|
||||||
else if(vertical =="top")
|
|
||||||
{
|
|
||||||
align.set_vertical(alignment::vertical_alignment::top);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw "unknown alignment";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_horizontal = node.attribute("horizontal") != nullptr;
|
|
||||||
std::string horizontal = has_horizontal ? node.attribute("horizontal").as_string() : "";
|
|
||||||
|
|
||||||
if(has_horizontal)
|
|
||||||
{
|
|
||||||
if(horizontal == "left")
|
|
||||||
{
|
|
||||||
align.set_horizontal(alignment::horizontal_alignment::left);
|
|
||||||
}
|
|
||||||
else if(horizontal == "center")
|
|
||||||
{
|
|
||||||
align.set_horizontal(alignment::horizontal_alignment::center);
|
|
||||||
}
|
|
||||||
else if(horizontal == "center-continuous")
|
|
||||||
{
|
|
||||||
align.set_horizontal(alignment::horizontal_alignment::center_continuous);
|
|
||||||
}
|
|
||||||
else if(horizontal == "right")
|
|
||||||
{
|
|
||||||
align.set_horizontal(alignment::horizontal_alignment::right);
|
|
||||||
}
|
|
||||||
else if(horizontal == "justify")
|
|
||||||
{
|
|
||||||
align.set_horizontal(alignment::horizontal_alignment::justify);
|
|
||||||
}
|
|
||||||
else if(horizontal == "general")
|
|
||||||
{
|
|
||||||
align.set_horizontal(alignment::horizontal_alignment::general);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw "unknown alignment";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return align;
|
|
||||||
}
|
|
||||||
|
|
||||||
style style_reader::read_style(pugi::xml_node stylesheet_node, pugi::xml_node xf_node)
|
|
||||||
{
|
|
||||||
style s;
|
|
||||||
|
|
||||||
s.apply_number_format(xf_node.attribute("applyNumberFormat").as_bool());
|
|
||||||
s.number_format_id_ = xf_node.attribute("numFmtId").as_int();
|
|
||||||
|
|
||||||
bool builtin_format = true;
|
|
||||||
|
|
||||||
for(auto num_fmt : number_formats_)
|
|
||||||
{
|
|
||||||
if(num_fmt.get_id() == s.get_number_format_id())
|
|
||||||
{
|
|
||||||
s.number_format_ = num_fmt;
|
|
||||||
builtin_format = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(builtin_format)
|
|
||||||
{
|
|
||||||
s.number_format_ = number_format::from_builtin_id(s.get_number_format_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
s.apply_font(xf_node.attribute("applyFont").as_bool());
|
|
||||||
s.font_id_ = xf_node.attribute("fontId") != nullptr ? xf_node.attribute("fontId").as_int() : 0;
|
|
||||||
s.font_ = fonts_[s.font_id_];
|
|
||||||
|
|
||||||
s.apply_fill(xf_node.attribute("applyFill").as_bool());
|
|
||||||
s.fill_id_ = xf_node.attribute("fillId").as_int();
|
|
||||||
s.fill_ = fills_[s.fill_id_];
|
|
||||||
|
|
||||||
s.apply_border(xf_node.attribute("applyBorder").as_bool());
|
|
||||||
s.border_id_ = xf_node.attribute("borderId").as_int();
|
|
||||||
s.border_ = borders_[s.border_id_];
|
|
||||||
|
|
||||||
s.apply_protection(xf_node.attribute("protection") != nullptr);
|
|
||||||
|
|
||||||
if(s.protection_apply_)
|
|
||||||
{
|
|
||||||
auto inline_protection = read_protection(xf_node.child("protection"));
|
|
||||||
s.protection_ = inline_protection;
|
|
||||||
}
|
|
||||||
|
|
||||||
s.apply_alignment(xf_node.child("alignment") != nullptr);
|
|
||||||
|
|
||||||
if(s.alignment_apply_)
|
|
||||||
{
|
|
||||||
auto inline_alignment = read_alignment(xf_node.child("alignment"));
|
|
||||||
s.alignment_ = inline_alignment;
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
style_reader::style_reader(workbook &wb)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_styles(zip_file &archive)
|
|
||||||
{
|
|
||||||
auto xml = archive.read("xl/styles.xml");
|
|
||||||
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.load_string(xml.c_str());
|
|
||||||
|
|
||||||
auto root = doc.root();
|
|
||||||
auto stylesheet_node = root.child("styleSheet");
|
|
||||||
|
|
||||||
read_borders(stylesheet_node.child("borders"));
|
|
||||||
read_fills(stylesheet_node.child("fills"));
|
|
||||||
read_fonts(stylesheet_node.child("fonts"));
|
|
||||||
read_number_formats(stylesheet_node.child("numFmts"));
|
|
||||||
|
|
||||||
auto cell_xfs_node = stylesheet_node.child("cellXfs");
|
|
||||||
|
|
||||||
for(auto xf_node : cell_xfs_node.children("xf"))
|
|
||||||
{
|
|
||||||
styles_.push_back(read_style(stylesheet_node, xf_node));
|
|
||||||
styles_.back().id_ = styles_.size() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
read_colors(stylesheet_node.child("colors"));
|
|
||||||
|
|
||||||
read_dxfs();
|
|
||||||
read_cell_styles();
|
|
||||||
read_named_styles(root.child("namedStyles"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_number_formats(pugi::xml_node num_fmts_node)
|
|
||||||
{
|
|
||||||
for(auto num_fmt_node : num_fmts_node.children("numFmt"))
|
|
||||||
{
|
|
||||||
number_format nf;
|
|
||||||
|
|
||||||
nf.set_format_string(num_fmt_node.attribute("formatCode").as_string());
|
|
||||||
if(nf.get_format_string() == "GENERAL")
|
|
||||||
{
|
|
||||||
nf.set_format_string("General");
|
|
||||||
}
|
|
||||||
nf.set_id(num_fmt_node.attribute("numFmtId").as_int());
|
|
||||||
|
|
||||||
number_formats_.push_back(nf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_dxfs()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_fonts(pugi::xml_node fonts_node)
|
|
||||||
{
|
|
||||||
for(auto font_node : fonts_node)
|
|
||||||
{
|
|
||||||
font new_font;
|
|
||||||
|
|
||||||
new_font.set_size(font_node.child("sz").attribute("val").as_int());
|
|
||||||
new_font.set_name(font_node.child("name").attribute("val").as_string());
|
|
||||||
|
|
||||||
if(font_node.child("color").attribute("theme") != nullptr)
|
|
||||||
{
|
|
||||||
new_font.set_color(color(color::type::theme, font_node.child("color").attribute("theme").as_ullong()));
|
|
||||||
}
|
|
||||||
else if(font_node.child("color").attribute("indexed") != nullptr)
|
|
||||||
{
|
|
||||||
new_font.set_color(color(color::type::indexed, font_node.child("color").attribute("indexed").as_ullong()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(font_node.child("family") != nullptr)
|
|
||||||
{
|
|
||||||
new_font.set_family(font_node.child("family").attribute("val").as_int());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(font_node.child("scheme") != nullptr)
|
|
||||||
{
|
|
||||||
new_font.set_scheme(font_node.child("scheme").attribute("val").as_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(font_node.child("b") != nullptr)
|
|
||||||
{
|
|
||||||
new_font.set_bold(font_node.child("b").attribute("val").as_bool());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(font_node.child("strike") != nullptr)
|
|
||||||
{
|
|
||||||
new_font.set_strikethrough(font_node.child("strike").attribute("val").as_bool());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(font_node.child("i") != nullptr)
|
|
||||||
{
|
|
||||||
new_font.set_italic(font_node.child("i").attribute("val").as_bool());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(font_node.child("u") != nullptr)
|
|
||||||
{
|
|
||||||
std::string underline_string = font_node.child("u").attribute("val").as_string();
|
|
||||||
|
|
||||||
if(underline_string == "single")
|
|
||||||
{
|
|
||||||
new_font.set_underline(font::underline_style::single);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fonts_.push_back(new_font);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_colors(pugi::xml_node colors_node)
|
|
||||||
{
|
|
||||||
auto indexed_colors_node = colors_node.child("indexedColors");
|
|
||||||
|
|
||||||
for(auto rgb_color_node : indexed_colors_node.children("rgbColor"))
|
|
||||||
{
|
|
||||||
colors_.push_back(rgb_color_node.attribute("rgb").as_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_fills(pugi::xml_node fills_node)
|
|
||||||
{
|
|
||||||
auto pattern_fill_type_from_string = [](const std::string &fill_type)
|
|
||||||
{
|
|
||||||
if(fill_type == "none") return fill::pattern_type::none;
|
|
||||||
if(fill_type == "solid") return fill::pattern_type::solid;
|
|
||||||
if(fill_type == "gray125") return fill::pattern_type::gray125;
|
|
||||||
throw std::runtime_error("invalid fill type");
|
|
||||||
};
|
|
||||||
|
|
||||||
for(auto fill_node : fills_node)
|
|
||||||
{
|
|
||||||
fill new_fill;
|
|
||||||
|
|
||||||
if(fill_node.child("patternFill") != nullptr)
|
|
||||||
{
|
|
||||||
auto pattern_fill_node = fill_node.child("patternFill");
|
|
||||||
new_fill.set_type(fill::type::pattern);
|
|
||||||
std::string pattern_type_string = pattern_fill_node.attribute("patternType").as_string();
|
|
||||||
auto pattern_type = pattern_fill_type_from_string(pattern_type_string);
|
|
||||||
new_fill.set_pattern_type(pattern_type);
|
|
||||||
|
|
||||||
auto bg_color_node = pattern_fill_node.child("bgColor");
|
|
||||||
|
|
||||||
if(bg_color_node != nullptr)
|
|
||||||
{
|
|
||||||
if(bg_color_node.attribute("indexed") != nullptr)
|
|
||||||
{
|
|
||||||
new_fill.set_background_color(color(color::type::indexed, bg_color_node.attribute("indexed").as_ullong()));
|
|
||||||
}
|
|
||||||
else if(bg_color_node.attribute("auto") != nullptr)
|
|
||||||
{
|
|
||||||
new_fill.set_background_color(color(color::type::auto_, bg_color_node.attribute("auto").as_ullong()));
|
|
||||||
}
|
|
||||||
else if(bg_color_node.attribute("theme") != nullptr)
|
|
||||||
{
|
|
||||||
new_fill.set_background_color(color(color::type::theme, bg_color_node.attribute("theme").as_ullong()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fg_color_node = pattern_fill_node.child("fgColor");
|
|
||||||
|
|
||||||
if(fg_color_node != nullptr)
|
|
||||||
{
|
|
||||||
if(fg_color_node.attribute("indexed") != nullptr)
|
|
||||||
{
|
|
||||||
new_fill.set_foreground_color(color(color::type::indexed, fg_color_node.attribute("indexed").as_ullong()));
|
|
||||||
}
|
|
||||||
else if(fg_color_node.attribute("auto") != nullptr)
|
|
||||||
{
|
|
||||||
new_fill.set_foreground_color(color(color::type::auto_, fg_color_node.attribute("auto").as_ullong()));
|
|
||||||
}
|
|
||||||
else if(fg_color_node.attribute("theme") != nullptr)
|
|
||||||
{
|
|
||||||
new_fill.set_foreground_color(color(color::type::theme, fg_color_node.attribute("theme").as_ullong()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fills_.push_back(new_fill);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void read_side(pugi::xml_node side_node, side &side, bool &assigned)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(side_node != nullptr)
|
|
||||||
{
|
|
||||||
assigned = true;
|
|
||||||
|
|
||||||
if(side_node.attribute("style") != nullptr)
|
|
||||||
{
|
|
||||||
std::string border_style_string = side_node.attribute("style").as_string();
|
|
||||||
|
|
||||||
if(border_style_string == "none")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::none);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "dashdot")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::dashdot);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "dashdotdot")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::dashdotdot);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "dashed")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::dashed);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "dotted")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::dotted);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "double")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::double_);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "hair")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::hair);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "medium")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::medium);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "mediumdashdot")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::mediumdashdot);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "mediumdashdotdot")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::mediumdashdotdot);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "mediumdashed")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::mediumdashed);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "slantdashdot")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::slantdashdot);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "thick")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::thick);
|
|
||||||
}
|
|
||||||
else if(border_style_string == "thin")
|
|
||||||
{
|
|
||||||
side.set_border_style(border_style::thin);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::runtime_error("unknown border style");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto color_node = side_node.child("color");
|
|
||||||
|
|
||||||
if(color_node != nullptr)
|
|
||||||
{
|
|
||||||
if(color_node.attribute("indexed") != nullptr)
|
|
||||||
{
|
|
||||||
side.set_color(side::color_type::indexed, color_node.attribute("indexed").as_int());
|
|
||||||
}
|
|
||||||
else if(color_node.attribute("theme") != nullptr)
|
|
||||||
{
|
|
||||||
side.set_color(side::color_type::theme, color_node.attribute("theme").as_int());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::runtime_error("invalid color type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_borders(pugi::xml_node borders_node)
|
|
||||||
{
|
|
||||||
for(auto border_node : borders_node)
|
|
||||||
{
|
|
||||||
border new_border;
|
|
||||||
|
|
||||||
std::vector<std::tuple<std::string, side *, bool *>> sides;
|
|
||||||
sides.push_back(std::make_tuple("start", &new_border.start, &new_border.start_assigned));
|
|
||||||
sides.push_back(std::make_tuple("end", &new_border.end, &new_border.end_assigned));
|
|
||||||
sides.push_back(std::make_tuple("left", &new_border.left, &new_border.left_assigned));
|
|
||||||
sides.push_back(std::make_tuple("right", &new_border.right, &new_border.right_assigned));
|
|
||||||
sides.push_back(std::make_tuple("top", &new_border.top, &new_border.top_assigned));
|
|
||||||
sides.push_back(std::make_tuple("bottom", &new_border.bottom, &new_border.bottom_assigned));
|
|
||||||
sides.push_back(std::make_tuple("diagonal", &new_border.diagonal, &new_border.diagonal_assigned));
|
|
||||||
sides.push_back(std::make_tuple("vertical", &new_border.vertical, &new_border.vertical_assigned));
|
|
||||||
sides.push_back(std::make_tuple("horizontal", &new_border.horizontal, &new_border.horizontal_assigned));
|
|
||||||
|
|
||||||
for(const auto &side : sides)
|
|
||||||
{
|
|
||||||
read_side(border_node.child(std::get<0>(side).c_str()), *std::get<1>(side), *std::get<2>(side));
|
|
||||||
}
|
|
||||||
|
|
||||||
borders_.push_back(new_border);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_named_styles(pugi::xml_node named_styles_node)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_style_names()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_cell_styles()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_xfs()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void style_reader::read_style_table()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,240 +0,0 @@
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <xlnt/common/datetime.hpp>
|
|
||||||
#include <xlnt/common/exceptions.hpp>
|
|
||||||
#include <xlnt/common/zip_file.hpp>
|
|
||||||
#include <xlnt/reader/workbook_reader.hpp>
|
|
||||||
#include <xlnt/workbook/document_properties.hpp>
|
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
|
||||||
|
|
||||||
#include "detail/include_pugixml.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
xlnt::datetime w3cdtf_to_datetime(const std::string &string)
|
|
||||||
{
|
|
||||||
xlnt::datetime result(1900, 1, 1);
|
|
||||||
auto separator_index = string.find('-');
|
|
||||||
result.year = std::stoi(string.substr(0, separator_index));
|
|
||||||
result.month = std::stoi(string.substr(separator_index + 1, string.find('-', separator_index + 1)));
|
|
||||||
separator_index = string.find('-', separator_index + 1);
|
|
||||||
result.day = std::stoi(string.substr(separator_index + 1, string.find('T', separator_index + 1)));
|
|
||||||
separator_index = string.find('T', separator_index + 1);
|
|
||||||
result.hour = std::stoi(string.substr(separator_index + 1, string.find(':', separator_index + 1)));
|
|
||||||
separator_index = string.find(':', separator_index + 1);
|
|
||||||
result.minute = std::stoi(string.substr(separator_index + 1, string.find(':', separator_index + 1)));
|
|
||||||
separator_index = string.find(':', separator_index + 1);
|
|
||||||
result.second = std::stoi(string.substr(separator_index + 1, string.find('Z', separator_index + 1)));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> read_sheets(zip_file &archive)
|
|
||||||
{
|
|
||||||
auto xml_source = archive.read("xl/workbook.xml");
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.load(xml_source.c_str());
|
|
||||||
|
|
||||||
std::string ns;
|
|
||||||
|
|
||||||
for(auto child : doc.children())
|
|
||||||
{
|
|
||||||
std::string name = child.name();
|
|
||||||
|
|
||||||
if(name.find(':') != std::string::npos)
|
|
||||||
{
|
|
||||||
auto colon_index = name.find(':');
|
|
||||||
ns = name.substr(0, colon_index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto with_ns = [&](const std::string &base) { return ns.empty() ? base : ns + ":" + base; };
|
|
||||||
|
|
||||||
auto root_node = doc.child(with_ns("workbook").c_str());
|
|
||||||
auto sheets_node = root_node.child(with_ns("sheets").c_str());
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> sheets;
|
|
||||||
|
|
||||||
// store temp because pugixml iteration uses the internal char array multiple times
|
|
||||||
auto sheet_element_name = with_ns("sheet");
|
|
||||||
|
|
||||||
for(auto sheet_node : sheets_node.children(sheet_element_name.c_str()))
|
|
||||||
{
|
|
||||||
std::string id = sheet_node.attribute("r:id").as_string();
|
|
||||||
std::string name = sheet_node.attribute("name").as_string();
|
|
||||||
sheets.push_back(std::make_pair(id, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sheets;
|
|
||||||
}
|
|
||||||
|
|
||||||
document_properties read_properties_core(const std::string &xml_string)
|
|
||||||
{
|
|
||||||
document_properties props;
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.load(xml_string.c_str());
|
|
||||||
auto root_node = doc.child("cp:coreProperties");
|
|
||||||
|
|
||||||
props.excel_base_date = calendar::windows_1900;
|
|
||||||
|
|
||||||
if(root_node.child("dc:creator") != nullptr)
|
|
||||||
{
|
|
||||||
props.creator = root_node.child("dc:creator").text().as_string();
|
|
||||||
}
|
|
||||||
if(root_node.child("cp:lastModifiedBy") != nullptr)
|
|
||||||
{
|
|
||||||
props.last_modified_by = root_node.child("cp:lastModifiedBy").text().as_string();
|
|
||||||
}
|
|
||||||
if(root_node.child("dcterms:created") != nullptr)
|
|
||||||
{
|
|
||||||
std::string created_string = root_node.child("dcterms:created").text().as_string();
|
|
||||||
props.created = w3cdtf_to_datetime(created_string);
|
|
||||||
}
|
|
||||||
if(root_node.child("dcterms:modified") != nullptr)
|
|
||||||
{
|
|
||||||
std::string modified_string = root_node.child("dcterms:modified").text().as_string();
|
|
||||||
props.modified = w3cdtf_to_datetime(modified_string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string read_dimension(const std::string &xml_string)
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
doc.load(xml_string.c_str());
|
|
||||||
auto root_node = doc.child("worksheet");
|
|
||||||
auto dimension_node = root_node.child("dimension");
|
|
||||||
std::string dimension = dimension_node.attribute("ref").as_string();
|
|
||||||
return dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<relationship> read_relationships(zip_file &archive, const std::string &filename)
|
|
||||||
{
|
|
||||||
auto filename_separator_index = filename.find_last_of('/');
|
|
||||||
auto basename = filename.substr(filename_separator_index + 1);
|
|
||||||
auto dirname = filename.substr(0, filename_separator_index);
|
|
||||||
auto rels_filename = dirname + "/_rels/" + basename + ".rels";
|
|
||||||
|
|
||||||
pugi::xml_document doc;
|
|
||||||
auto content = archive.read(rels_filename);
|
|
||||||
doc.load(content.c_str());
|
|
||||||
|
|
||||||
auto root_node = doc.child("Relationships");
|
|
||||||
|
|
||||||
std::vector<relationship> relationships;
|
|
||||||
|
|
||||||
for(auto relationship : root_node.children("Relationship"))
|
|
||||||
{
|
|
||||||
std::string id = relationship.attribute("Id").as_string();
|
|
||||||
std::string type = relationship.attribute("Type").as_string();
|
|
||||||
std::string target = relationship.attribute("Target").as_string();
|
|
||||||
|
|
||||||
if(target[0] != '/' && target.substr(0, 2) != "..")
|
|
||||||
{
|
|
||||||
target = dirname + "/" + target;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(target[0] == '/')
|
|
||||||
{
|
|
||||||
target = target.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
relationships.push_back(xlnt::relationship(type, id, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
return relationships;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> read_content_types(zip_file &archive)
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto content_types_string = archive.read("[Content_Types].xml");
|
|
||||||
doc.load(content_types_string.c_str());
|
|
||||||
}
|
|
||||||
catch(std::exception e)
|
|
||||||
{
|
|
||||||
throw invalid_file_exception(archive.get_filename());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto root_node = doc.child("Types");
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> override_types;
|
|
||||||
|
|
||||||
for(auto child : root_node.children("Override"))
|
|
||||||
{
|
|
||||||
std::string part_name = child.attribute("PartName").as_string();
|
|
||||||
std::string content_type = child.attribute("ContentType").as_string();
|
|
||||||
override_types.push_back({part_name, content_type});
|
|
||||||
}
|
|
||||||
|
|
||||||
return override_types;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string determine_document_type(const std::vector<std::pair<std::string, std::string>> &override_types)
|
|
||||||
{
|
|
||||||
auto match = std::find_if(override_types.begin(), override_types.end(), [](const std::pair<std::string, std::string> &p) { return p.first == "/xl/workbook.xml"; });
|
|
||||||
|
|
||||||
if(match == override_types.end())
|
|
||||||
{
|
|
||||||
return "unsupported";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string type = match->second;
|
|
||||||
|
|
||||||
if(type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml")
|
|
||||||
{
|
|
||||||
return "excel";
|
|
||||||
}
|
|
||||||
else if(type == "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml")
|
|
||||||
{
|
|
||||||
return "powerpoint";
|
|
||||||
}
|
|
||||||
else if(type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")
|
|
||||||
{
|
|
||||||
return "word";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unsupported";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> detect_worksheets(zip_file &archive)
|
|
||||||
{
|
|
||||||
static const std::string ValidWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
|
|
||||||
|
|
||||||
auto content_types = read_content_types(archive);
|
|
||||||
std::vector<std::string> valid_sheets;
|
|
||||||
|
|
||||||
for(const auto &content_type : content_types)
|
|
||||||
{
|
|
||||||
if(content_type.second == ValidWorksheet)
|
|
||||||
{
|
|
||||||
valid_sheets.push_back(content_type.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto workbook_relationships = read_relationships(archive, "xl/workbook.xml");
|
|
||||||
std::vector<std::pair<std::string, std::string>> result;
|
|
||||||
|
|
||||||
for(const auto &ws : read_sheets(archive))
|
|
||||||
{
|
|
||||||
auto rel = *std::find_if(workbook_relationships.begin(), workbook_relationships.end(), [&](const relationship &r) { return r.get_id() == ws.first; });
|
|
||||||
auto target = rel.get_target_uri();
|
|
||||||
|
|
||||||
if(std::find(valid_sheets.begin(), valid_sheets.end(), "/" + target) != valid_sheets.end())
|
|
||||||
{
|
|
||||||
result.push_back({target, ws.second});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
5
source/s11n/comment_serializer.cpp
Normal file
5
source/s11n/comment_serializer.cpp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#include <xlnt/s11n/comment_serializer.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -1,17 +1,7 @@
|
||||||
#include <xlnt/common/datetime.hpp>
|
#include <xlnt/s11n/excel_serializer.hpp>
|
||||||
#include <xlnt/common/exceptions.hpp>
|
#include <xlnt/s11n/manifest_serializer.hpp>
|
||||||
#include <xlnt/common/zip_file.hpp>
|
#include <xlnt/workbook/manifest.hpp>
|
||||||
#include <xlnt/styles/style.hpp>
|
|
||||||
#include <xlnt/reader/excel_reader.hpp>
|
|
||||||
#include <xlnt/reader/shared_strings_reader.hpp>
|
|
||||||
#include <xlnt/reader/style_reader.hpp>
|
|
||||||
#include <xlnt/reader/workbook_reader.hpp>
|
|
||||||
#include <xlnt/reader/worksheet_reader.hpp>
|
|
||||||
#include <xlnt/workbook/document_properties.hpp>
|
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
|
||||||
|
|
||||||
#include "detail/include_pugixml.hpp"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -166,4 +156,112 @@ xlnt::workbook excel_reader::load_workbook(const std::vector<std::uint8_t> &byte
|
||||||
return ::load_workbook(archive, guess_types, data_only);
|
return ::load_workbook(archive, guess_types, data_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
excel_writer::excel_writer(workbook &wb) : wb_(wb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::save(const std::string &filename, bool as_template)
|
||||||
|
{
|
||||||
|
zip_file archive;
|
||||||
|
write_data(archive, as_template);
|
||||||
|
archive.save(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_data(zip_file &archive, bool as_template)
|
||||||
|
{
|
||||||
|
archive.writestr(constants::ArcRootRels, write_root_rels(wb_));
|
||||||
|
archive.writestr(constants::ArcWorkbookRels, write_workbook_rels(wb_));
|
||||||
|
archive.writestr(constants::ArcApp, write_properties_app(wb_));
|
||||||
|
archive.writestr(constants::ArcCore, write_properties_core(wb_.get_properties()));
|
||||||
|
|
||||||
|
if(wb_.has_loaded_theme())
|
||||||
|
{
|
||||||
|
archive.writestr(constants::ArcTheme, wb_.get_loaded_theme());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
archive.writestr(constants::ArcTheme, write_theme());
|
||||||
|
}
|
||||||
|
|
||||||
|
archive.writestr(constants::ArcWorkbook, write_workbook(wb_));
|
||||||
|
|
||||||
|
auto shared_strings = extract_all_strings(wb_);
|
||||||
|
|
||||||
|
write_charts(archive);
|
||||||
|
write_images(archive);
|
||||||
|
write_shared_strings(archive, shared_strings);
|
||||||
|
write_worksheets(archive, shared_strings);
|
||||||
|
write_chartsheets(archive);
|
||||||
|
write_external_links(archive);
|
||||||
|
|
||||||
|
style_writer style_writer_(wb_);
|
||||||
|
archive.writestr(constants::ArcStyles, style_writer_.write_table());
|
||||||
|
|
||||||
|
auto manifest = write_content_types(wb_, as_template);
|
||||||
|
archive.writestr(constants::ArcContentTypes, manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_shared_strings(xlnt::zip_file &archive, const std::vector<std::string> &shared_strings)
|
||||||
|
{
|
||||||
|
archive.writestr(constants::ArcSharedString, ::xlnt::write_shared_strings(shared_strings));
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_images(zip_file &/*archive*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_charts(zip_file &/*archive*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_chartsheets(zip_file &/*archive*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_worksheets(zip_file &archive, const std::vector<std::string> &shared_strings)
|
||||||
|
{
|
||||||
|
std::size_t index = 0;
|
||||||
|
|
||||||
|
for(auto ws : wb_)
|
||||||
|
{
|
||||||
|
for(auto relationship : wb_.get_relationships())
|
||||||
|
{
|
||||||
|
if(relationship.get_type() == relationship::type::worksheet &&
|
||||||
|
workbook::index_from_ws_filename(relationship.get_target_uri()) == index)
|
||||||
|
{
|
||||||
|
archive.writestr(relationship.get_target_uri(), write_worksheet(ws, shared_strings));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void excel_writer::write_external_links(zip_file &/*archive*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool save_workbook(workbook &wb, const std::string &filename, bool as_template)
|
||||||
|
{
|
||||||
|
excel_writer writer(wb);
|
||||||
|
writer.save(filename, as_template);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template)
|
||||||
|
{
|
||||||
|
zip_file archive;
|
||||||
|
excel_writer writer(wb);
|
||||||
|
writer.write_data(archive, as_template);
|
||||||
|
std::vector<std::uint8_t> buffer;
|
||||||
|
archive.save(buffer);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
33
source/s11n/manifest_serializer.cpp
Normal file
33
source/s11n/manifest_serializer.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include <xlnt/s11n/manifest_serializer.hpp>
|
||||||
|
#include <xlnt/s11n/xml_document.hpp>
|
||||||
|
#include <xlnt/workbook/manifest.hpp>
|
||||||
|
|
||||||
|
#include "detail/constants.hpp"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
bool manifest_serializer::write_manifest(xml_document &xml)
|
||||||
|
{
|
||||||
|
xml.add_namespace("", constants::Namespaces.at("content-types"));
|
||||||
|
|
||||||
|
auto root_node = xml.root();
|
||||||
|
root_node.set_name("Types");
|
||||||
|
|
||||||
|
for(const auto &default_type : manifest_.get_default_types())
|
||||||
|
{
|
||||||
|
auto type_node = root_node.add_child("Default");
|
||||||
|
type_node.add_attribute("Extension", default_type.get_extension());
|
||||||
|
type_node.add_attribute("ContentType", default_type.get_extension());
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const auto &override_type : manifest_.get_override_types())
|
||||||
|
{
|
||||||
|
auto type_node = root_node.add_child("Override");
|
||||||
|
type_node.add_attribute("PartName", override_type.get_part_name());
|
||||||
|
type_node.add_attribute("ContentType", override_type.get_content_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
47
source/s11n/relationship_serializer.cpp
Normal file
47
source/s11n/relationship_serializer.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include <xlnt/s11n/relationship_serializer.hpp>
|
||||||
|
|
||||||
|
#include <xlnt/common/relationship.hpp>
|
||||||
|
#include <xlnt/s11n/xml_document.hpp>
|
||||||
|
#include <xlnt/s11n/xml_node.hpp>
|
||||||
|
|
||||||
|
#include "detail/constants.hpp"
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
bool relationship_serializer::read_relationships(const xml_document &xml, const std::string &dir, std::vector<relationship> &relationships)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool relationship_serializer::write_relationships(const std::vector<relationship> &relationships, const std::string &dir, xml_document &xml)
|
||||||
|
{
|
||||||
|
xml.add_namespace("", constants::Namespaces.at("relationships"));
|
||||||
|
|
||||||
|
auto root_node = xml.root();
|
||||||
|
root_node.set_name("Relationships");
|
||||||
|
|
||||||
|
for(const auto &relationship : relationships)
|
||||||
|
{
|
||||||
|
auto target = relationship.get_target_uri();
|
||||||
|
|
||||||
|
if (dir != "" && target.substr(0, dir.size()) == dir)
|
||||||
|
{
|
||||||
|
target = target.substr(dir.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto app_props_node = root_node.add_child("Relationship");
|
||||||
|
|
||||||
|
app_props_node.add_attribute("Id", relationship.get_id());
|
||||||
|
app_props_node.add_attribute("Target", target);
|
||||||
|
app_props_node.add_attribute("Type", relationship.get_type_string());
|
||||||
|
|
||||||
|
if(relationship.get_target_mode() == target_mode::external)
|
||||||
|
{
|
||||||
|
app_props_node.add_attribute("TargetMode", "External");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
29
source/s11n/shared_strings_serializer.cpp
Normal file
29
source/s11n/shared_strings_serializer.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include <xlnt/s11n/shared_strings_serializer.hpp>
|
||||||
|
#include <xlnt/s11n/xml_document.hpp>
|
||||||
|
#include <xlnt/s11n/xml_node.hpp>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
bool shared_strings_serializer::read_strings(const xml_document &xml, std::vector<std::string> &strings)
|
||||||
|
{
|
||||||
|
strings.clear();
|
||||||
|
|
||||||
|
auto root_node = xml.root();
|
||||||
|
root_node.set_name("sst");
|
||||||
|
|
||||||
|
auto unique_count = std::stoull(root_node.get_attribute("uniqueCount"));
|
||||||
|
|
||||||
|
for(const auto &si_node : root_node.get_children())
|
||||||
|
{
|
||||||
|
strings.push_back(si_node.get_child("t").get_text());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(unique_count != strings.size())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("counts don't match");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
900
source/s11n/style_serializer.cpp
Normal file
900
source/s11n/style_serializer.cpp
Normal file
|
@ -0,0 +1,900 @@
|
||||||
|
#include <xlnt/s11n/style_serializer.hpp>
|
||||||
|
#include <xlnt/s11n/xml_document.hpp>
|
||||||
|
#include <xlnt/s11n/xml_node.hpp>
|
||||||
|
#include <xlnt/styles/alignment.hpp>
|
||||||
|
#include <xlnt/styles/border.hpp>
|
||||||
|
#include <xlnt/styles/fill.hpp>
|
||||||
|
#include <xlnt/styles/font.hpp>
|
||||||
|
#include <xlnt/styles/number_format.hpp>
|
||||||
|
#include <xlnt/styles/protection.hpp>
|
||||||
|
#include <xlnt/styles/style.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool is_true(const std::string &bool_string)
|
||||||
|
{
|
||||||
|
return bool_string == "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::protection::type protection_type_from_string(const std::string &type_string)
|
||||||
|
{
|
||||||
|
if(type_string == "true")
|
||||||
|
{
|
||||||
|
return xlnt::protection::type::protected_;
|
||||||
|
}
|
||||||
|
else if(type_string == "inherit")
|
||||||
|
{
|
||||||
|
return xlnt::protection::type::inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xlnt::protection::type::unprotected;
|
||||||
|
};
|
||||||
|
|
||||||
|
xlnt::font::underline_style underline_style_from_string(const std::string &underline_string)
|
||||||
|
{
|
||||||
|
if(underline_string == "none")
|
||||||
|
{
|
||||||
|
return xlnt::font::underline_style::none;
|
||||||
|
}
|
||||||
|
else if(underline_string == "single")
|
||||||
|
{
|
||||||
|
return xlnt::font::underline_style::single;
|
||||||
|
}
|
||||||
|
else if(underline_string == "single-accounting")
|
||||||
|
{
|
||||||
|
return xlnt::font::underline_style::single_accounting;
|
||||||
|
}
|
||||||
|
else if(underline_string == "double")
|
||||||
|
{
|
||||||
|
return xlnt::font::underline_style::double_;
|
||||||
|
}
|
||||||
|
else if(underline_string == "double-accounting")
|
||||||
|
{
|
||||||
|
return xlnt::font::underline_style::double_accounting;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xlnt::font::underline_style::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::fill::pattern_type pattern_fill_type_from_string(const std::string &fill_type)
|
||||||
|
{
|
||||||
|
if(fill_type == "none") return xlnt::fill::pattern_type::none;
|
||||||
|
if(fill_type == "solid") return xlnt::fill::pattern_type::solid;
|
||||||
|
if(fill_type == "gray125") return xlnt::fill::pattern_type::gray125;
|
||||||
|
return xlnt::fill::pattern_type::none;
|
||||||
|
};
|
||||||
|
|
||||||
|
xlnt::border_style border_style_from_string(const std::string &border_style_string)
|
||||||
|
{
|
||||||
|
if(border_style_string == "none")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::none;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "dashdot")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::dashdot;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "dashdotdot")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::dashdotdot;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "dashed")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::dashed;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "dotted")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::dotted;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "double")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::double_;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "hair")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::hair;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "medium")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::medium;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "mediumdashdot")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::mediumdashdot;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "mediumdashdotdot")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::mediumdashdotdot;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "mediumdashed")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::mediumdashed;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "slantdashdot")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::slantdashdot;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "thick")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::thick;
|
||||||
|
}
|
||||||
|
else if(border_style_string == "thin")
|
||||||
|
{
|
||||||
|
return xlnt::border_style::thin;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("unknown border style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
style_serializer::style_serializer(workbook &wb) : wb_(wb)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protection style_serializer::read_protection(const xml_node &protection_node) const
|
||||||
|
{
|
||||||
|
protection prot;
|
||||||
|
|
||||||
|
prot.set_locked(protection_type_from_string(protection_node.get_attribute("locked")));
|
||||||
|
prot.set_hidden(protection_type_from_string(protection_node.get_attribute("hidden")));
|
||||||
|
|
||||||
|
return prot;
|
||||||
|
}
|
||||||
|
|
||||||
|
alignment style_serializer::read_alignment(const xml_node &alignment_node) const
|
||||||
|
{
|
||||||
|
alignment align;
|
||||||
|
|
||||||
|
align.set_wrap_text(is_true(alignment_node.get_attribute("wrapText")));
|
||||||
|
|
||||||
|
bool has_vertical = alignment_node.has_attribute("vertical");
|
||||||
|
|
||||||
|
if(has_vertical)
|
||||||
|
{
|
||||||
|
std::string vertical = alignment_node.get_attribute("vertical");
|
||||||
|
|
||||||
|
if(vertical == "bottom")
|
||||||
|
{
|
||||||
|
align.set_vertical(alignment::vertical_alignment::bottom);
|
||||||
|
}
|
||||||
|
else if(vertical =="center")
|
||||||
|
{
|
||||||
|
align.set_vertical(alignment::vertical_alignment::center);
|
||||||
|
}
|
||||||
|
else if(vertical =="justify")
|
||||||
|
{
|
||||||
|
align.set_vertical(alignment::vertical_alignment::justify);
|
||||||
|
}
|
||||||
|
else if(vertical =="top")
|
||||||
|
{
|
||||||
|
align.set_vertical(alignment::vertical_alignment::top);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw "unknown alignment";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_horizontal = alignment_node.has_attribute("horizontal");
|
||||||
|
|
||||||
|
if(has_horizontal)
|
||||||
|
{
|
||||||
|
std::string horizontal = alignment_node.get_attribute("horizontal");
|
||||||
|
|
||||||
|
if(horizontal == "left")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::left);
|
||||||
|
}
|
||||||
|
else if(horizontal == "center")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::center);
|
||||||
|
}
|
||||||
|
else if(horizontal == "center-continuous")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::center_continuous);
|
||||||
|
}
|
||||||
|
else if(horizontal == "right")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::right);
|
||||||
|
}
|
||||||
|
else if(horizontal == "justify")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::justify);
|
||||||
|
}
|
||||||
|
else if(horizontal == "general")
|
||||||
|
{
|
||||||
|
align.set_horizontal(alignment::horizontal_alignment::general);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw "unknown alignment";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return align;
|
||||||
|
}
|
||||||
|
|
||||||
|
style style_serializer::read_style(const xml_node &style_node) const
|
||||||
|
{
|
||||||
|
style s;
|
||||||
|
|
||||||
|
s.apply_number_format(is_true(style_node.get_attribute("applyNumberFormat")));
|
||||||
|
s.number_format_id_ = std::stoull(style_node.get_attribute("numFmtId"));
|
||||||
|
|
||||||
|
bool builtin_format = true;
|
||||||
|
|
||||||
|
for(auto num_fmt : wb_.get_number_formats())
|
||||||
|
{
|
||||||
|
if(num_fmt.get_id() == s.get_number_format_id())
|
||||||
|
{
|
||||||
|
s.number_format_ = num_fmt;
|
||||||
|
builtin_format = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(builtin_format)
|
||||||
|
{
|
||||||
|
s.number_format_ = number_format::from_builtin_id(s.get_number_format_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
s.apply_font(is_true(style_node.get_attribute("applyFont")));
|
||||||
|
s.font_id_ = style_node.has_attribute("fontId") ? std::stoull(style_node.get_attribute("fontId")) : 0;
|
||||||
|
s.font_ = wb_.get_font(s.font_id_);
|
||||||
|
|
||||||
|
s.apply_fill(is_true(style_node.get_attribute("applyFill")));
|
||||||
|
s.fill_id_ = style_node.has_attribute("fillId") ? std::stoull(style_node.get_attribute("fillId")) : 0;
|
||||||
|
s.fill_ = wb_.get_fill(s.fill_id_);
|
||||||
|
|
||||||
|
s.apply_border(is_true(style_node.get_attribute("applyBorder")));
|
||||||
|
s.border_id_ = style_node.has_attribute("borderId") ? std::stoull(style_node.get_attribute("borderId")) : 0;
|
||||||
|
s.border_ = wb_.get_border(s.border_id_);
|
||||||
|
|
||||||
|
s.apply_protection(style_node.has_attribute("protection"));
|
||||||
|
|
||||||
|
if(s.protection_apply_)
|
||||||
|
{
|
||||||
|
auto inline_protection = read_protection(style_node.get_child("protection"));
|
||||||
|
s.protection_ = inline_protection;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.apply_alignment(style_node.has_child("alignment"));
|
||||||
|
|
||||||
|
if(s.alignment_apply_)
|
||||||
|
{
|
||||||
|
auto inline_alignment = read_alignment(style_node.get_child("alignment"));
|
||||||
|
s.alignment_ = inline_alignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_serializer::read_stylesheet(const xml_document &xml)
|
||||||
|
{
|
||||||
|
auto stylesheet_node = xml.root();
|
||||||
|
|
||||||
|
read_borders(stylesheet_node.get_child("borders"));
|
||||||
|
read_fills(stylesheet_node.get_child("fills"));
|
||||||
|
read_fonts(stylesheet_node.get_child("fonts"));
|
||||||
|
read_number_formats(stylesheet_node.get_child("numFmts"));
|
||||||
|
read_colors(stylesheet_node.get_child("colors"));
|
||||||
|
|
||||||
|
auto cell_xfs_node = stylesheet_node.get_child("cellXfs");
|
||||||
|
|
||||||
|
for(auto xf_node : cell_xfs_node.get_children())
|
||||||
|
{
|
||||||
|
if(xf_node.get_name() != "xf")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wb_.add_style(read_style(xf_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_serializer::read_number_formats(const xml_node &number_formats_node)
|
||||||
|
{
|
||||||
|
for(auto num_fmt_node : number_formats_node.get_children())
|
||||||
|
{
|
||||||
|
if(num_fmt_node.get_name() != "numFmt")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format_string = num_fmt_node.get_attribute("formatCode");
|
||||||
|
|
||||||
|
if(format_string == "GENERAL")
|
||||||
|
{
|
||||||
|
format_string = "General";
|
||||||
|
}
|
||||||
|
|
||||||
|
number_format nf;
|
||||||
|
|
||||||
|
nf.set_format_string(format_string);
|
||||||
|
nf.set_id(std::stoull(num_fmt_node.get_attribute("numFmtId")));
|
||||||
|
|
||||||
|
wb_.add_number_format(nf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_serializer::read_fonts(const xml_node &fonts_node)
|
||||||
|
{
|
||||||
|
for(auto font_node : fonts_node.get_children())
|
||||||
|
{
|
||||||
|
wb_.add_font(read_font(font_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
font style_serializer::read_font(const xlnt::xml_node &font_node) const
|
||||||
|
{
|
||||||
|
font new_font;
|
||||||
|
|
||||||
|
new_font.set_size(std::stoi(font_node.get_child("sz").get_attribute("val")));
|
||||||
|
new_font.set_name(font_node.get_child("name").get_attribute("val"));
|
||||||
|
|
||||||
|
if(font_node.has_child("color"))
|
||||||
|
{
|
||||||
|
new_font.set_color(read_color(font_node.get_child("color")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.has_child("family"))
|
||||||
|
{
|
||||||
|
new_font.set_family(std::stoull(font_node.get_child("family").get_attribute("val")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.has_child("scheme"))
|
||||||
|
{
|
||||||
|
new_font.set_scheme(font_node.get_child("scheme").get_attribute("val"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.has_child("b"))
|
||||||
|
{
|
||||||
|
new_font.set_bold(is_true(font_node.get_child("b").get_attribute("val")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.has_child("strike"))
|
||||||
|
{
|
||||||
|
new_font.set_strikethrough(is_true(font_node.get_child("strike").get_attribute("val")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.has_child("i"))
|
||||||
|
{
|
||||||
|
new_font.set_italic(is_true(font_node.get_child("i").get_attribute("val")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(font_node.has_child("u"))
|
||||||
|
{
|
||||||
|
std::string underline_string = font_node.get_child("u").get_attribute("val");
|
||||||
|
new_font.set_underline(underline_style_from_string(underline_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_serializer::read_colors(const xml_node &colors_node)
|
||||||
|
{
|
||||||
|
if(colors_node.has_child("indexedColors"))
|
||||||
|
{
|
||||||
|
auto indexed_colors = read_indexed_colors(colors_node.get_child("indexedColors"));
|
||||||
|
|
||||||
|
for(const auto &indexed_color : indexed_colors)
|
||||||
|
{
|
||||||
|
wb_.add_color(indexed_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_serializer::read_fills(const xml_node &fills_node)
|
||||||
|
{
|
||||||
|
for(auto fill_node : fills_node.get_children())
|
||||||
|
{
|
||||||
|
wb_.add_fill(read_fill(fill_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fill style_serializer::read_fill(const xml_node &fill_node) const
|
||||||
|
{
|
||||||
|
fill new_fill;
|
||||||
|
|
||||||
|
if(fill_node.has_child("patternFill"))
|
||||||
|
{
|
||||||
|
new_fill.set_type(fill::type::pattern);
|
||||||
|
|
||||||
|
auto pattern_fill_node = fill_node.get_child("patternFill");
|
||||||
|
new_fill.set_pattern_type(pattern_fill_type_from_string(pattern_fill_node.get_attribute("patternType")));
|
||||||
|
|
||||||
|
if(pattern_fill_node.has_child("bgColor"))
|
||||||
|
{
|
||||||
|
new_fill.set_background_color(read_color(pattern_fill_node.get_child("bgColor")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pattern_fill_node.has_child("fgColor"))
|
||||||
|
{
|
||||||
|
new_fill.set_foreground_color(read_color(pattern_fill_node.get_child("fgColor")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
side style_serializer::read_side(const xml_node &side_node) const
|
||||||
|
{
|
||||||
|
side new_side;
|
||||||
|
|
||||||
|
if(side_node.has_attribute("style"))
|
||||||
|
{
|
||||||
|
new_side.set_border_style(border_style_from_string(side_node.get_attribute("style")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(side_node.has_child("color"))
|
||||||
|
{
|
||||||
|
new_side.set_color(read_color(side_node.get_child("color")));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_side;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_serializer::read_borders(const xml_node &borders_node)
|
||||||
|
{
|
||||||
|
for(auto border_node : borders_node.get_children())
|
||||||
|
{
|
||||||
|
wb_.add_border(read_border(border_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
border style_serializer::read_border(const xml_node &border_node) const
|
||||||
|
{
|
||||||
|
border new_border;
|
||||||
|
|
||||||
|
if(border_node.has_child("start"))
|
||||||
|
{
|
||||||
|
new_border.start_assigned = true;
|
||||||
|
new_border.start = read_side(border_node.get_child("start"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_node.has_child("end"))
|
||||||
|
{
|
||||||
|
new_border.end_assigned = true;
|
||||||
|
new_border.end = read_side(border_node.get_child("end"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_node.has_child("left"))
|
||||||
|
{
|
||||||
|
new_border.left_assigned = true;
|
||||||
|
new_border.left = read_side(border_node.get_child("left"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_node.has_child("right"))
|
||||||
|
{
|
||||||
|
new_border.right_assigned = true;
|
||||||
|
new_border.right = read_side(border_node.get_child("right"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_node.has_child("top"))
|
||||||
|
{
|
||||||
|
new_border.top_assigned = true;
|
||||||
|
new_border.top = read_side(border_node.get_child("top"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_node.has_child("bottom"))
|
||||||
|
{
|
||||||
|
new_border.bottom_assigned = true;
|
||||||
|
new_border.bottom = read_side(border_node.get_child("bottom"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_node.has_child("diagonal"))
|
||||||
|
{
|
||||||
|
new_border.diagonal_assigned = true;
|
||||||
|
new_border.diagonal = read_side(border_node.get_child("diagonal"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_node.has_child("vertical"))
|
||||||
|
{
|
||||||
|
new_border.vertical_assigned = true;
|
||||||
|
new_border.vertical = read_side(border_node.get_child("vertical"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(border_node.has_child("horizontal"))
|
||||||
|
{
|
||||||
|
new_border.horizontal_assigned = true;
|
||||||
|
new_border.horizontal = read_side(border_node.get_child("horizontal"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_border;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_serializer::write_stylesheet(xlnt::xml_document &xml) const
|
||||||
|
{
|
||||||
|
xml.add_namespace("", "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
||||||
|
xml.add_namespace("mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
|
||||||
|
xml.add_namespace("x14ac", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
|
||||||
|
|
||||||
|
auto &style_sheet_node = doc.add_child("styleSheet");
|
||||||
|
xml.add_attribute("mc:Ignorable", "x14ac");
|
||||||
|
|
||||||
|
auto num_fmts_node = style_sheet_node.add_child("numFmts");
|
||||||
|
auto num_fmts = wb_.get_number_formats();
|
||||||
|
num_fmts_node.add_attribute("count", static_cast<int>(num_fmts.size()));
|
||||||
|
|
||||||
|
for(auto &num_fmt : num_fmts)
|
||||||
|
{
|
||||||
|
auto num_fmt_node = num_fmts_node.add_child("numFmt");
|
||||||
|
num_fmt_node.add_attribute("numFmtId", num_fmt.get_id());
|
||||||
|
num_fmt_node.add_attribute("formatCode", num_fmt.get_format_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fonts_node = style_sheet_node.add_child("fonts");
|
||||||
|
auto fonts = wb_.get_fonts();
|
||||||
|
if(fonts.empty())
|
||||||
|
{
|
||||||
|
fonts.push_back(font());
|
||||||
|
}
|
||||||
|
fonts_node.add_attribute("count", static_cast<int>(fonts.size()));
|
||||||
|
fonts_node.add_attribute("x14ac:knownFonts", 1);
|
||||||
|
|
||||||
|
for(auto &f : fonts)
|
||||||
|
{
|
||||||
|
auto font_node = fonts_node.add_child("font");
|
||||||
|
|
||||||
|
if(f.is_bold())
|
||||||
|
{
|
||||||
|
auto bold_node = font_node.add_child("b");
|
||||||
|
bold_node.add_attribute("val", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f.is_italic())
|
||||||
|
{
|
||||||
|
auto bold_node = font_node.add_child("i");
|
||||||
|
bold_node.add_attribute("val", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f.is_underline())
|
||||||
|
{
|
||||||
|
auto bold_node = font_node.add_child("u");
|
||||||
|
|
||||||
|
switch(f.get_underline())
|
||||||
|
{
|
||||||
|
case font::underline_style::single:
|
||||||
|
bold_node.add_attribute("val", "single");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f.is_strikethrough())
|
||||||
|
{
|
||||||
|
auto bold_node = font_node.add_child("strike");
|
||||||
|
bold_node.add_attribute("val", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto size_node = font_node.add_child("sz");
|
||||||
|
size_node.add_attribute("val", f.get_size());
|
||||||
|
|
||||||
|
auto color_node = font_node.add_child("color");
|
||||||
|
|
||||||
|
if(f.get_color().get_type() == color::type::indexed)
|
||||||
|
{
|
||||||
|
color_node.add_attribute("indexed", static_cast<unsigned int>(f.get_color().get_index()));
|
||||||
|
}
|
||||||
|
else if(f.get_color().get_type() == color::type::theme)
|
||||||
|
{
|
||||||
|
color_node.add_attribute("theme", static_cast<unsigned int>(f.get_color().get_theme()));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto name_node = font_node.add_child("name");
|
||||||
|
name_node.add_attribute("val", f.get_name());
|
||||||
|
|
||||||
|
if(f.has_family())
|
||||||
|
{
|
||||||
|
auto family_node = font_node.add_child("family");
|
||||||
|
family_node.add_attribute("val", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f.has_scheme())
|
||||||
|
{
|
||||||
|
auto scheme_node = font_node.add_child("scheme");
|
||||||
|
scheme_node.add_attribute("val", "minor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fills_node = style_sheet_node.add_child("fills");
|
||||||
|
const auto &fills = wb_.get_fills();
|
||||||
|
fills_node.add_attribute("count", static_cast<unsigned int>(fills.size()));
|
||||||
|
|
||||||
|
for(auto &fill_ : fills)
|
||||||
|
{
|
||||||
|
auto fill_node = fills_node.add_child("fill");
|
||||||
|
|
||||||
|
if(fill_.get_type() == fill::type::pattern)
|
||||||
|
{
|
||||||
|
auto pattern_fill_node = fill_node.add_child("patternFill");
|
||||||
|
auto type_string = fill_.get_pattern_type_string();
|
||||||
|
pattern_fill_node.add_attribute("patternType", type_string);
|
||||||
|
|
||||||
|
if(fill_.has_foreground_color())
|
||||||
|
{
|
||||||
|
auto fg_color_node = pattern_fill_node.add_child("fgColor");
|
||||||
|
|
||||||
|
switch(fill_.get_foreground_color().get_type())
|
||||||
|
{
|
||||||
|
case color::type::auto_: fg_color_node.add_attribute("auto", fill_.get_foreground_color().get_auto()); break;
|
||||||
|
case color::type::theme: fg_color_node.add_attribute("theme", fill_.get_foreground_color().get_theme()); break;
|
||||||
|
case color::type::indexed: fg_color_node.add_attribute("indexed", fill_.get_foreground_color().get_index()); break;
|
||||||
|
default: throw std::runtime_error("bad type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fill_.has_background_color())
|
||||||
|
{
|
||||||
|
auto bg_color_node = pattern_fill_node.add_child("bgColor");
|
||||||
|
|
||||||
|
switch(fill_.get_background_color().get_type())
|
||||||
|
{
|
||||||
|
case color::type::auto_: bg_color_node.add_attribute("auto", fill_.get_background_color().get_auto()); break;
|
||||||
|
case color::type::theme: bg_color_node.add_attribute("theme", fill_.get_background_color().get_theme()); break;
|
||||||
|
case color::type::indexed: bg_color_node.add_attribute("indexed", fill_.get_background_color().get_index()); break;
|
||||||
|
default: throw std::runtime_error("bad type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(fill_.get_type() == fill::type::solid)
|
||||||
|
{
|
||||||
|
auto solid_fill_node = fill_node.add_child("solidFill");
|
||||||
|
solid_fill_node.add_child("color");
|
||||||
|
}
|
||||||
|
else if(fill_.get_type() == fill::type::gradient)
|
||||||
|
{
|
||||||
|
auto gradient_fill_node = fill_node.add_child("gradientFill");
|
||||||
|
|
||||||
|
if(fill_.get_gradient_type_string() == "linear")
|
||||||
|
{
|
||||||
|
gradient_fill_node.add_attribute("degree", fill_.get_rotation());
|
||||||
|
}
|
||||||
|
else if(fill_.get_gradient_type_string() == "path")
|
||||||
|
{
|
||||||
|
gradient_fill_node.add_attribute("left", fill_.get_gradient_left());
|
||||||
|
gradient_fill_node.add_attribute("right", fill_.get_gradient_right());
|
||||||
|
gradient_fill_node.add_attribute("top", fill_.get_gradient_top());
|
||||||
|
gradient_fill_node.add_attribute("bottom", fill_.get_gradient_bottom());
|
||||||
|
|
||||||
|
auto start_node = gradient_fill_node.add_child("stop");
|
||||||
|
start_node.add_attribute("position", 0);
|
||||||
|
|
||||||
|
auto end_node = gradient_fill_node.add_child("stop");
|
||||||
|
end_node.add_attribute("position", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto borders_node = style_sheet_node.add_child("borders");
|
||||||
|
const auto &borders = wb_.get_borders();
|
||||||
|
borders_node.add_attribute("count", static_cast<unsigned int>(borders.size()));
|
||||||
|
|
||||||
|
for(const auto &border_ : borders)
|
||||||
|
{
|
||||||
|
auto border_node = borders_node.add_child("border");
|
||||||
|
|
||||||
|
std::vector<std::tuple<std::string, const side, bool>> sides;
|
||||||
|
sides.push_back(std::make_tuple("start", border_.start, border_.start_assigned));
|
||||||
|
sides.push_back(std::make_tuple("end", border_.end, border_.end_assigned));
|
||||||
|
sides.push_back(std::make_tuple("left", border_.left, border_.left_assigned));
|
||||||
|
sides.push_back(std::make_tuple("right", border_.right, border_.right_assigned));
|
||||||
|
sides.push_back(std::make_tuple("top", border_.top, border_.top_assigned));
|
||||||
|
sides.push_back(std::make_tuple("bottom", border_.bottom, border_.bottom_assigned));
|
||||||
|
sides.push_back(std::make_tuple("diagonal", border_.diagonal, border_.diagonal_assigned));
|
||||||
|
sides.push_back(std::make_tuple("vertical", border_.vertical, border_.vertical_assigned));
|
||||||
|
sides.push_back(std::make_tuple("horizontal", border_.horizontal, border_.horizontal_assigned));
|
||||||
|
|
||||||
|
for(const auto &side_tuple : sides)
|
||||||
|
{
|
||||||
|
std::string name = std::get<0>(side_tuple);
|
||||||
|
const side side_ = std::get<1>(side_tuple);
|
||||||
|
bool assigned = std::get<2>(side_tuple);
|
||||||
|
|
||||||
|
if(assigned)
|
||||||
|
{
|
||||||
|
auto side_node = border_node.add_child(name);
|
||||||
|
|
||||||
|
if(side_.is_style_assigned())
|
||||||
|
{
|
||||||
|
auto style_attribute = side_node.add_attribute("style");
|
||||||
|
|
||||||
|
switch(side_.get_style())
|
||||||
|
{
|
||||||
|
case border_style::none: style_attribute.set_value("none"); break;
|
||||||
|
case border_style::dashdot : style_attribute.set_value("dashdot"); break;
|
||||||
|
case border_style::dashdotdot : style_attribute.set_value("dashdotdot"); break;
|
||||||
|
case border_style::dashed : style_attribute.set_value("dashed"); break;
|
||||||
|
case border_style::dotted : style_attribute.set_value("dotted"); break;
|
||||||
|
case border_style::double_ : style_attribute.set_value("double"); break;
|
||||||
|
case border_style::hair : style_attribute.set_value("hair"); break;
|
||||||
|
case border_style::medium : style_attribute.set_value("thin"); break;
|
||||||
|
case border_style::mediumdashdot: style_attribute.set_value("mediumdashdot"); break;
|
||||||
|
case border_style::mediumdashdotdot: style_attribute.set_value("mediumdashdotdot"); break;
|
||||||
|
case border_style::mediumdashed: style_attribute.set_value("mediumdashed"); break;
|
||||||
|
case border_style::slantdashdot: style_attribute.set_value("slantdashdot"); break;
|
||||||
|
case border_style::thick: style_attribute.set_value("thick"); break;
|
||||||
|
case border_style::thin: style_attribute.set_value("thin"); break;
|
||||||
|
default: throw std::runtime_error("invalid style");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(side_.is_color_assigned())
|
||||||
|
{
|
||||||
|
auto color_node = side_node.add_child("color");
|
||||||
|
|
||||||
|
if(side_.get_color_type() == side::color_type::indexed)
|
||||||
|
{
|
||||||
|
color_node.add_attribute("indexed", (int)side_.get_color());
|
||||||
|
}
|
||||||
|
else if(side_.get_color_type() == side::color_type::theme)
|
||||||
|
{
|
||||||
|
color_node.add_attribute("indexed", (int)side_.get_color());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("invalid color type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cell_style_xfs_node = style_sheet_node.add_child("cellStyleXfs");
|
||||||
|
cell_style_xfs_node.add_attribute("count", 1);
|
||||||
|
auto style_xf_node = cell_style_xfs_node.add_child("xf");
|
||||||
|
style_xf_node.add_attribute("numFmtId", 0);
|
||||||
|
style_xf_node.add_attribute("fontId", 0);
|
||||||
|
style_xf_node.add_attribute("fillId", 0);
|
||||||
|
style_xf_node.add_attribute("borderId", 0);
|
||||||
|
|
||||||
|
auto cell_xfs_node = style_sheet_node.add_child("cellXfs");
|
||||||
|
const auto &styles = wb_.get_styles();
|
||||||
|
cell_xfs_node.add_attribute("count", static_cast<int>(styles.size()));
|
||||||
|
|
||||||
|
for(auto &style : styles)
|
||||||
|
{
|
||||||
|
auto xf_node = cell_xfs_node.add_child("xf");
|
||||||
|
xf_node.add_attribute("numFmtId", style.get_number_format().get_id());
|
||||||
|
xf_node.add_attribute("fontId", (int)style.get_font_id());
|
||||||
|
|
||||||
|
if(style.fill_apply_)
|
||||||
|
{
|
||||||
|
xf_node.add_attribute("fillId", (int)style.get_fill_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(style.border_apply_)
|
||||||
|
{
|
||||||
|
xf_node.add_attribute("borderId", (int)style.get_border_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
xf_node.add_attribute("applyNumberFormat", style.number_format_apply_ ? 1 : 0);
|
||||||
|
xf_node.add_attribute("applyFont", style.font_apply_ ? 1 : 0);
|
||||||
|
xf_node.add_attribute("applyFill", style.fill_apply_ ? 1 : 0);
|
||||||
|
xf_node.add_attribute("applyBorder", style.border_apply_ ? 1 : 0);
|
||||||
|
xf_node.add_attribute("applyAlignment", style.alignment_apply_ ? 1 : 0);
|
||||||
|
xf_node.add_attribute("applyProtection", style.protection_apply_ ? 1 : 0);
|
||||||
|
|
||||||
|
if(style.alignment_apply_)
|
||||||
|
{
|
||||||
|
auto alignment_node = xf_node.add_child("alignment");
|
||||||
|
|
||||||
|
if(style.alignment_.has_vertical())
|
||||||
|
{
|
||||||
|
switch(style.alignment_.get_vertical())
|
||||||
|
{
|
||||||
|
case alignment::vertical_alignment::bottom:
|
||||||
|
alignment_node.add_attribute("vertical", "bottom");
|
||||||
|
break;
|
||||||
|
case alignment::vertical_alignment::center:
|
||||||
|
alignment_node.add_attribute("vertical", "center");
|
||||||
|
break;
|
||||||
|
case alignment::vertical_alignment::justify:
|
||||||
|
alignment_node.add_attribute("vertical", "justify");
|
||||||
|
break;
|
||||||
|
case alignment::vertical_alignment::top:
|
||||||
|
alignment_node.add_attribute("vertical", "top");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("invalid alignment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(style.alignment_.has_horizontal())
|
||||||
|
{
|
||||||
|
switch(style.alignment_.get_horizontal())
|
||||||
|
{
|
||||||
|
case alignment::horizontal_alignment::center:
|
||||||
|
alignment_node.add_attribute("horizontal", "center");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::center_continuous:
|
||||||
|
alignment_node.add_attribute("horizontal", "center_continuous");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::general:
|
||||||
|
alignment_node.add_attribute("horizontal", "general");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::justify:
|
||||||
|
alignment_node.add_attribute("horizontal", "justify");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::left:
|
||||||
|
alignment_node.add_attribute("horizontal", "left");
|
||||||
|
break;
|
||||||
|
case alignment::horizontal_alignment::right:
|
||||||
|
alignment_node.add_attribute("horizontal", "right");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error("invalid alignment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(style.alignment_.get_wrap_text())
|
||||||
|
{
|
||||||
|
alignment_node.add_attribute("wrapText", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cell_styles_node = style_sheet_node.add_child("cellStyles");
|
||||||
|
cell_styles_node.add_attribute("count", 1);
|
||||||
|
auto cell_style_node = cell_styles_node.add_child("cellStyle");
|
||||||
|
cell_style_node.add_attribute("name", "Normal");
|
||||||
|
cell_style_node.add_attribute("xfId", 0);
|
||||||
|
cell_style_node.add_attribute("builtinId", 0);
|
||||||
|
|
||||||
|
style_sheet_node.add_child("dxfs").add_attribute("count", 0);
|
||||||
|
|
||||||
|
auto table_styles_node = style_sheet_node.add_child("tableStyles");
|
||||||
|
table_styles_node.add_attribute("count", 0);
|
||||||
|
table_styles_node.add_attribute("defaultTableStyle", "TableStyleMedium2");
|
||||||
|
table_styles_node.add_attribute("defaultPivotStyle", "PivotStyleMedium9");
|
||||||
|
|
||||||
|
auto colors_node = style_sheet_node.add_child("colors");
|
||||||
|
auto indexed_colors_node = colors_node.add_child("indexedColors");
|
||||||
|
|
||||||
|
for(auto &c : wb_.get_colors())
|
||||||
|
{
|
||||||
|
indexed_colors_node.add_child("rgbColor").add_attribute("rgb", c.get_rgb_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ext_list_node = style_sheet_node.add_child("extLst");
|
||||||
|
auto ext_node = ext_list_node.add_child("ext");
|
||||||
|
ext_node.add_attribute("uri", "{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}");
|
||||||
|
ext_node.add_attribute("xmlns:x14", "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main");
|
||||||
|
ext_node.add_child("x14:slicerStyles").add_attribute("defaultSlicerStyle", "SlicerStyleLight1");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool style_serializer::write_number_formats(xml_node &number_formats_node) const
|
||||||
|
{
|
||||||
|
number_formats_node.add_attribute("count", std::to_string(wb_.get_number_formats().size()));
|
||||||
|
|
||||||
|
for(const auto &num_fmt : wb_.get_number_formats())
|
||||||
|
{
|
||||||
|
auto &num_fmt_node = number_formats_node.add_child("numFmt");
|
||||||
|
num_fmt_node.add_attribute("numFmtId", std::to_string(num_fmt.get_id()));
|
||||||
|
num_fmt_node.add_attribute("formatCode", num_fmt.get_format_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -1,27 +1,33 @@
|
||||||
#include <set>
|
#include <xlnt/s11n/workbook_serializer.hpp>
|
||||||
#include <sstream>
|
#include <xlnt/common/datetime.hpp>
|
||||||
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
|
||||||
#include <xlnt/common/exceptions.hpp>
|
|
||||||
#include <xlnt/common/relationship.hpp>
|
#include <xlnt/common/relationship.hpp>
|
||||||
#include <xlnt/common/zip_file.hpp>
|
#include <xlnt/s11n/xml_document.hpp>
|
||||||
|
#include <xlnt/s11n/xml_node.hpp>
|
||||||
#include <xlnt/workbook/document_properties.hpp>
|
#include <xlnt/workbook/document_properties.hpp>
|
||||||
#include <xlnt/workbook/named_range.hpp>
|
#include <xlnt/workbook/manifest.hpp>
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
#include <xlnt/workbook/workbook.hpp>
|
||||||
#include <xlnt/worksheet/range.hpp>
|
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
|
||||||
#include <xlnt/writer/manifest_writer.hpp>
|
|
||||||
#include <xlnt/writer/relationship_writer.hpp>
|
|
||||||
#include <xlnt/writer/theme_writer.hpp>
|
|
||||||
#include <xlnt/writer/worksheet_writer.hpp>
|
|
||||||
#include <xlnt/writer/workbook_writer.hpp>
|
|
||||||
|
|
||||||
#include "detail/constants.hpp"
|
#include "detail/constants.hpp"
|
||||||
#include "detail/include_pugixml.hpp"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
xlnt::datetime w3cdtf_to_datetime(const std::string &string)
|
||||||
|
{
|
||||||
|
xlnt::datetime result(1900, 1, 1);
|
||||||
|
auto separator_index = string.find('-');
|
||||||
|
result.year = std::stoi(string.substr(0, separator_index));
|
||||||
|
result.month = std::stoi(string.substr(separator_index + 1, string.find('-', separator_index + 1)));
|
||||||
|
separator_index = string.find('-', separator_index + 1);
|
||||||
|
result.day = std::stoi(string.substr(separator_index + 1, string.find('T', separator_index + 1)));
|
||||||
|
separator_index = string.find('T', separator_index + 1);
|
||||||
|
result.hour = std::stoi(string.substr(separator_index + 1, string.find(':', separator_index + 1)));
|
||||||
|
separator_index = string.find(':', separator_index + 1);
|
||||||
|
result.minute = std::stoi(string.substr(separator_index + 1, string.find(':', separator_index + 1)));
|
||||||
|
separator_index = string.find(':', separator_index + 1);
|
||||||
|
result.second = std::stoi(string.substr(separator_index + 1, string.find('Z', separator_index + 1)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::string fill(const std::string &string, std::size_t length = 2)
|
std::string fill(const std::string &string, std::size_t length = 2)
|
||||||
{
|
{
|
||||||
if(string.size() >= length)
|
if(string.size() >= length)
|
||||||
|
@ -41,7 +47,176 @@ std::string datetime_to_w3cdtf(const xlnt::datetime &dt)
|
||||||
|
|
||||||
namespace xlnt {
|
namespace xlnt {
|
||||||
|
|
||||||
std::string write_shared_strings(const std::vector<std::string> &string_table)
|
/*
|
||||||
|
std::vector<std::pair<std::string, std::string>> workbook_serializer::read_sheets(zip_file &archive)
|
||||||
|
{
|
||||||
|
std::string ns;
|
||||||
|
|
||||||
|
for(auto child : doc.children())
|
||||||
|
{
|
||||||
|
std::string name = child.name();
|
||||||
|
|
||||||
|
if(name.find(':') != std::string::npos)
|
||||||
|
{
|
||||||
|
auto colon_index = name.find(':');
|
||||||
|
ns = name.substr(0, colon_index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto with_ns = [&](const std::string &base) { return ns.empty() ? base : ns + ":" + base; };
|
||||||
|
|
||||||
|
auto root_node = doc.child(with_ns("workbook").c_str());
|
||||||
|
auto sheets_node = root_node.child(with_ns("sheets").c_str());
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> sheets;
|
||||||
|
|
||||||
|
// store temp because pugixml iteration uses the internal char array multiple times
|
||||||
|
auto sheet_element_name = with_ns("sheet");
|
||||||
|
|
||||||
|
for(auto sheet_node : sheets_node.children(sheet_element_name.c_str()))
|
||||||
|
{
|
||||||
|
std::string id = sheet_node.attribute("r:id").as_string();
|
||||||
|
std::string name = sheet_node.attribute("name").as_string();
|
||||||
|
sheets.push_back(std::make_pair(id, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sheets;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void workbook_serializer::read_properties_core(const xml_document &xml)
|
||||||
|
{
|
||||||
|
auto &props = wb_.get_properties();
|
||||||
|
auto root_node = xml.root();
|
||||||
|
|
||||||
|
props.excel_base_date = calendar::windows_1900;
|
||||||
|
|
||||||
|
if(root_node.has_child("dc:creator"))
|
||||||
|
{
|
||||||
|
props.creator = root_node.get_child("dc:creator").get_text();
|
||||||
|
}
|
||||||
|
if(root_node.has_child("cp:lastModifiedBy"))
|
||||||
|
{
|
||||||
|
props.last_modified_by = root_node.get_child("cp:lastModifiedBy").get_text();
|
||||||
|
}
|
||||||
|
if(root_node.has_child("dcterms:created"))
|
||||||
|
{
|
||||||
|
std::string created_string = root_node.get_child("dcterms:created").get_text();
|
||||||
|
props.created = w3cdtf_to_datetime(created_string);
|
||||||
|
}
|
||||||
|
if(root_node.has_child("dcterms:modified"))
|
||||||
|
{
|
||||||
|
std::string modified_string = root_node.get_child("dcterms:modified").get_text();
|
||||||
|
props.modified = w3cdtf_to_datetime(modified_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string workbook_serializer::read_dimension(const std::string &xml_string)
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(xml_string.c_str());
|
||||||
|
auto root_node = doc.child("worksheet");
|
||||||
|
auto dimension_node = root_node.child("dimension");
|
||||||
|
std::string dimension = dimension_node.attribute("ref").as_string();
|
||||||
|
return dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<relationship> workbook_serializer::read_relationships(zip_file &archive, const std::string &filename)
|
||||||
|
{
|
||||||
|
auto filename_separator_index = filename.find_last_of('/');
|
||||||
|
auto basename = filename.substr(filename_separator_index + 1);
|
||||||
|
auto dirname = filename.substr(0, filename_separator_index);
|
||||||
|
auto rels_filename = dirname + "/_rels/" + basename + ".rels";
|
||||||
|
|
||||||
|
pugi::xml_document doc;
|
||||||
|
auto content = archive.read(rels_filename);
|
||||||
|
doc.load(content.c_str());
|
||||||
|
|
||||||
|
auto root_node = doc.child("Relationships");
|
||||||
|
|
||||||
|
std::vector<relationship> relationships;
|
||||||
|
|
||||||
|
for(auto relationship : root_node.children("Relationship"))
|
||||||
|
{
|
||||||
|
std::string id = relationship.attribute("Id").as_string();
|
||||||
|
std::string type = relationship.attribute("Type").as_string();
|
||||||
|
std::string target = relationship.attribute("Target").as_string();
|
||||||
|
|
||||||
|
if(target[0] != '/' && target.substr(0, 2) != "..")
|
||||||
|
{
|
||||||
|
target = dirname + "/" + target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(target[0] == '/')
|
||||||
|
{
|
||||||
|
target = target.substr(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
relationships.push_back(xlnt::relationship(type, id, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
return relationships;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string workbook_serializer::determine_document_type(const manifest &manifest)
|
||||||
|
{
|
||||||
|
if(!manifest.has_override_type(constants::ArcWorkbook))
|
||||||
|
{
|
||||||
|
return "unsupported";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string type = manifest.get_override_type(constants::ArcWorkbook);
|
||||||
|
|
||||||
|
if(type == "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml")
|
||||||
|
{
|
||||||
|
return "excel";
|
||||||
|
}
|
||||||
|
else if(type == "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml")
|
||||||
|
{
|
||||||
|
return "powerpoint";
|
||||||
|
}
|
||||||
|
else if(type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")
|
||||||
|
{
|
||||||
|
return "word";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "unsupported";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, std::string>> workbook_serializer::detect_worksheets(zip_file &archive)
|
||||||
|
{
|
||||||
|
static const std::string ValidWorksheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
|
||||||
|
|
||||||
|
auto content_types = read_content_types(archive);
|
||||||
|
std::vector<std::string> valid_sheets;
|
||||||
|
|
||||||
|
for(const auto &content_type : content_types)
|
||||||
|
{
|
||||||
|
if(content_type.second == ValidWorksheet)
|
||||||
|
{
|
||||||
|
valid_sheets.push_back(content_type.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto workbook_relationships = read_relationships(archive, "xl/workbook.xml");
|
||||||
|
std::vector<std::pair<std::string, std::string>> result;
|
||||||
|
|
||||||
|
for(const auto &ws : read_sheets(archive))
|
||||||
|
{
|
||||||
|
auto rel = *std::find_if(workbook_relationships.begin(), workbook_relationships.end(), [&](const relationship &r) { return r.get_id() == ws.first; });
|
||||||
|
auto target = rel.get_target_uri();
|
||||||
|
|
||||||
|
if(std::find(valid_sheets.begin(), valid_sheets.end(), "/" + target) != valid_sheets.end())
|
||||||
|
{
|
||||||
|
result.push_back({target, ws.second});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string workbook_serializer::write_shared_strings(const std::vector<std::string> &string_table)
|
||||||
{
|
{
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
auto root_node = doc.append_child("sst");
|
auto root_node = doc.append_child("sst");
|
||||||
|
@ -59,7 +234,7 @@ std::string write_shared_strings(const std::vector<std::string> &string_table)
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string write_properties_core(const document_properties &prop)
|
std::string workbook_serializer::write_properties_core(const document_properties &prop)
|
||||||
{
|
{
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
auto root_node = doc.append_child("cp:coreProperties");
|
auto root_node = doc.append_child("cp:coreProperties");
|
||||||
|
@ -87,12 +262,12 @@ std::string write_properties_core(const document_properties &prop)
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string write_worksheet_rels(worksheet ws)
|
std::string workbook_serializer::write_worksheet_rels(worksheet ws)
|
||||||
{
|
{
|
||||||
return write_relationships(ws.get_relationships(), "");
|
return write_relationships(ws.get_relationships(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string write_theme()
|
std::string workbook_serializer::write_theme()
|
||||||
{
|
{
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
auto theme_node = doc.append_child("a:theme");
|
auto theme_node = doc.append_child("a:theme");
|
||||||
|
@ -578,12 +753,12 @@ std::string write_workbook(const workbook &wb)
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string write_workbook_rels(const workbook &wb)
|
std::string workbook_serializer::write_workbook_rels(const workbook &wb)
|
||||||
{
|
{
|
||||||
return write_relationships(wb.get_relationships(), "xl/");
|
return write_relationships(wb.get_relationships(), "xl/");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string write_defined_names(const xlnt::workbook &wb)
|
std::string workbook_serializer::write_defined_names(const xlnt::workbook &wb)
|
||||||
{
|
{
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
auto names = doc.root().append_child("names");
|
auto names = doc.root().append_child("names");
|
368
source/s11n/worksheet_serializer.cpp
Normal file
368
source/s11n/worksheet_serializer.cpp
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
#include <xlnt/s11n/worksheet_serializer.hpp>
|
||||||
|
#include <xlnt/cell/cell.hpp>
|
||||||
|
#include <xlnt/cell/cell_reference.hpp>
|
||||||
|
#include <xlnt/s11n/xml_document.hpp>
|
||||||
|
#include <xlnt/s11n/xml_node.hpp>
|
||||||
|
#include <xlnt/worksheet/range.hpp>
|
||||||
|
#include <xlnt/worksheet/range_reference.hpp>
|
||||||
|
|
||||||
|
#include "detail/constants.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool is_integral(long double d)
|
||||||
|
{
|
||||||
|
return d == static_cast<long long int>(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namepsace
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
bool worksheet_serializer::write_worksheet(const worksheet ws, const std::vector<std::string> &string_table, xml_document &xml)
|
||||||
|
{
|
||||||
|
ws.get_cell("A1");
|
||||||
|
|
||||||
|
xml.add_namespace("", constants::Namespaces.at("spreadsheetml"));
|
||||||
|
xml.add_namespace("r", constants::Namespaces.at("r"));
|
||||||
|
|
||||||
|
auto &root_node = xml.root();
|
||||||
|
root_node.set_name("worksheet");
|
||||||
|
|
||||||
|
auto &sheet_pr_node = root_node.add_child("sheetPr");
|
||||||
|
|
||||||
|
if(!ws.get_page_setup().is_default())
|
||||||
|
{
|
||||||
|
auto &page_set_up_pr_node = sheet_pr_node.add_child("pageSetUpPr");
|
||||||
|
page_set_up_pr_node.add_attribute("fitToPage", ws.get_page_setup().fit_to_page() ? "1" : "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &outline_pr_node = sheet_pr_node.add_child("outlinePr");
|
||||||
|
|
||||||
|
outline_pr_node.add_attribute("summaryBelow", "1");
|
||||||
|
outline_pr_node.add_attribute("summaryRight", "1");
|
||||||
|
|
||||||
|
auto &dimension_node = root_node.add_child("dimension");
|
||||||
|
dimension_node.add_attribute("ref", ws.calculate_dimension().to_string());
|
||||||
|
|
||||||
|
auto &sheet_views_node = root_node.add_child("sheetViews");
|
||||||
|
auto &sheet_view_node = sheet_views_node.add_child("sheetView");
|
||||||
|
sheet_view_node.add_attribute("workbookViewId", "0");
|
||||||
|
|
||||||
|
std::string active_pane = "bottomRight";
|
||||||
|
|
||||||
|
if(ws.has_frozen_panes())
|
||||||
|
{
|
||||||
|
auto pane_node = sheet_view_node.add_child("pane");
|
||||||
|
|
||||||
|
if(ws.get_frozen_panes().get_column_index() > 1)
|
||||||
|
{
|
||||||
|
pane_node.add_attribute("xSplit", std::to_string(ws.get_frozen_panes().get_column_index() - 1));
|
||||||
|
active_pane = "topRight";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ws.get_frozen_panes().get_row() > 1)
|
||||||
|
{
|
||||||
|
pane_node.add_attribute("ySplit", std::to_string(ws.get_frozen_panes().get_row() - 1));
|
||||||
|
active_pane = "bottomLeft";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
|
||||||
|
{
|
||||||
|
auto top_right_node = sheet_view_node.add_child("selection");
|
||||||
|
top_right_node.add_attribute("pane", "topRight");
|
||||||
|
auto bottom_left_node = sheet_view_node.add_child("selection");
|
||||||
|
bottom_left_node.add_attribute("pane", "bottomLeft");
|
||||||
|
active_pane = "bottomRight";
|
||||||
|
}
|
||||||
|
|
||||||
|
pane_node.add_attribute("topLeftCell", ws.get_frozen_panes().to_string());
|
||||||
|
pane_node.add_attribute("activePane", active_pane);
|
||||||
|
pane_node.add_attribute("state", "frozen");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto selection_node = sheet_view_node.add_child("selection");
|
||||||
|
|
||||||
|
if(ws.has_frozen_panes())
|
||||||
|
{
|
||||||
|
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
|
||||||
|
{
|
||||||
|
selection_node.add_attribute("pane", "bottomRight");
|
||||||
|
}
|
||||||
|
else if(ws.get_frozen_panes().get_row() > 1)
|
||||||
|
{
|
||||||
|
selection_node.add_attribute("pane", "bottomLeft");
|
||||||
|
}
|
||||||
|
else if(ws.get_frozen_panes().get_column_index() > 1)
|
||||||
|
{
|
||||||
|
selection_node.add_attribute("pane", "topRight");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string active_cell = "A1";
|
||||||
|
selection_node.add_attribute("activeCell", active_cell);
|
||||||
|
selection_node.add_attribute("sqref", active_cell);
|
||||||
|
|
||||||
|
auto sheet_format_pr_node = root_node.add_child("sheetFormatPr");
|
||||||
|
sheet_format_pr_node.add_attribute("baseColWidth", "10");
|
||||||
|
sheet_format_pr_node.add_attribute("defaultRowHeight", "15");
|
||||||
|
|
||||||
|
bool has_column_properties = false;
|
||||||
|
|
||||||
|
for(auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++)
|
||||||
|
{
|
||||||
|
if(ws.has_column_properties(column))
|
||||||
|
{
|
||||||
|
has_column_properties = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(has_column_properties)
|
||||||
|
{
|
||||||
|
auto cols_node = root_node.add_child("cols");
|
||||||
|
|
||||||
|
for(auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++)
|
||||||
|
{
|
||||||
|
const auto &props = ws.get_column_properties(column);
|
||||||
|
|
||||||
|
auto col_node = cols_node.add_child("col");
|
||||||
|
|
||||||
|
col_node.add_attribute("min", std::to_string(column));
|
||||||
|
col_node.add_attribute("max", std::to_string(column));
|
||||||
|
col_node.add_attribute("width", std::to_string(props.width));
|
||||||
|
col_node.add_attribute("style", std::to_string(props.style));
|
||||||
|
col_node.add_attribute("customWidth", props.custom ? "1" : "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> hyperlink_references;
|
||||||
|
|
||||||
|
auto sheet_data_node = root_node.add_child("sheetData");
|
||||||
|
|
||||||
|
for(auto row : ws.rows())
|
||||||
|
{
|
||||||
|
row_t min = static_cast<row_t>(row.num_cells());
|
||||||
|
row_t max = 0;
|
||||||
|
bool any_non_null = false;
|
||||||
|
|
||||||
|
for(auto cell : row)
|
||||||
|
{
|
||||||
|
min = std::min(min, cell_reference::column_index_from_string(cell.get_column()));
|
||||||
|
max = std::max(max, cell_reference::column_index_from_string(cell.get_column()));
|
||||||
|
|
||||||
|
if(!cell.garbage_collectible())
|
||||||
|
{
|
||||||
|
any_non_null = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!any_non_null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto row_node = sheet_data_node.add_child("row");
|
||||||
|
|
||||||
|
row_node.add_attribute("r", std::to_string(row.front().get_row()));
|
||||||
|
row_node.add_attribute("spans", (std::to_string(min) + ":" + std::to_string(max)));
|
||||||
|
|
||||||
|
if(ws.has_row_properties(row.front().get_row()))
|
||||||
|
{
|
||||||
|
row_node.add_attribute("customHeight", "1");
|
||||||
|
auto height = ws.get_row_properties(row.front().get_row()).height;
|
||||||
|
|
||||||
|
if(height == std::floor(height))
|
||||||
|
{
|
||||||
|
row_node.add_attribute("ht", std::to_string(static_cast<long long int>(height)) + ".0");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row_node.add_attribute("ht", std::to_string(height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//row_node.add_attribute("x14ac:dyDescent", 0.25);
|
||||||
|
|
||||||
|
for(auto cell : row)
|
||||||
|
{
|
||||||
|
if(!cell.garbage_collectible())
|
||||||
|
{
|
||||||
|
if(cell.has_hyperlink())
|
||||||
|
{
|
||||||
|
hyperlink_references[cell.get_hyperlink().get_id()] = cell.get_reference().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cell_node = row_node.add_child("c");
|
||||||
|
cell_node.add_attribute("r", cell.get_reference().to_string());
|
||||||
|
|
||||||
|
if(cell.get_data_type() == cell::type::string)
|
||||||
|
{
|
||||||
|
if(cell.has_formula())
|
||||||
|
{
|
||||||
|
cell_node.add_attribute("t", "str");
|
||||||
|
cell_node.add_child("f").set_text(cell.get_formula());
|
||||||
|
cell_node.add_child("v").set_text(cell.to_string());
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int match_index = -1;
|
||||||
|
|
||||||
|
for(std::size_t i = 0; i < string_table.size(); i++)
|
||||||
|
{
|
||||||
|
if(string_table[i] == cell.get_value<std::string>())
|
||||||
|
{
|
||||||
|
match_index = static_cast<int>(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(match_index == -1)
|
||||||
|
{
|
||||||
|
if(cell.get_value<std::string>().empty())
|
||||||
|
{
|
||||||
|
cell_node.add_attribute("t", "s");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cell_node.add_attribute("t", "inlineStr");
|
||||||
|
auto inline_string_node = cell_node.add_child("is");
|
||||||
|
inline_string_node.add_child("t").text().set(cell.get_value<std::string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cell_node.add_attribute("t", "s");
|
||||||
|
auto value_node = cell_node.add_child("v");
|
||||||
|
value_node.text().set(match_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(cell.get_data_type() != cell::type::null)
|
||||||
|
{
|
||||||
|
if(cell.get_data_type() == cell::type::boolean)
|
||||||
|
{
|
||||||
|
cell_node.add_attribute("t", "b");
|
||||||
|
auto value_node = cell_node.add_child("v");
|
||||||
|
value_node.text().set(cell.get_value<bool>() ? 1 : 0);
|
||||||
|
}
|
||||||
|
else if(cell.get_data_type() == cell::type::numeric)
|
||||||
|
{
|
||||||
|
if(cell.has_formula())
|
||||||
|
{
|
||||||
|
cell_node.add_child("f").text().set(cell.get_formula());
|
||||||
|
cell_node.add_child("v").text().set(cell.to_string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell_node.add_attribute("t", "n");
|
||||||
|
auto value_node = cell_node.add_child("v");
|
||||||
|
if(is_integral(cell.get_value<long double>()))
|
||||||
|
{
|
||||||
|
value_node.text().set(cell.get_value<long long>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss.precision(20);
|
||||||
|
ss << cell.get_value<long double>();
|
||||||
|
ss.str();
|
||||||
|
value_node.text().set(ss.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(cell.has_formula())
|
||||||
|
{
|
||||||
|
cell_node.add_child("f").text().set(cell.get_formula());
|
||||||
|
cell_node.add_child("v");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if(cell.has_style())
|
||||||
|
{
|
||||||
|
auto style_id = cell.get_style_id();
|
||||||
|
cell_node.add_attribute("s", (int)style_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ws.has_auto_filter())
|
||||||
|
{
|
||||||
|
auto auto_filter_node = root_node.add_child("autoFilter");
|
||||||
|
auto_filter_node.add_attribute("ref", ws.get_auto_filter().to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ws.get_merged_ranges().empty())
|
||||||
|
{
|
||||||
|
auto merge_cells_node = root_node.add_child("mergeCells");
|
||||||
|
merge_cells_node.add_attribute("count", (unsigned int)ws.get_merged_ranges().size());
|
||||||
|
|
||||||
|
for(auto merged_range : ws.get_merged_ranges())
|
||||||
|
{
|
||||||
|
auto merge_cell_node = merge_cells_node.add_child("mergeCell");
|
||||||
|
merge_cell_node.add_attribute("ref", merged_range.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ws.get_relationships().empty())
|
||||||
|
{
|
||||||
|
auto hyperlinks_node = root_node.add_child("hyperlinks");
|
||||||
|
|
||||||
|
for(auto relationship : ws.get_relationships())
|
||||||
|
{
|
||||||
|
auto hyperlink_node = hyperlinks_node.add_child("hyperlink");
|
||||||
|
hyperlink_node.add_attribute("display", relationship.get_target_uri());
|
||||||
|
hyperlink_node.add_attribute("ref", hyperlink_references.at(relationship.get_id()));
|
||||||
|
hyperlink_node.add_attribute("r:id", relationship.get_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ws.get_page_setup().is_default())
|
||||||
|
{
|
||||||
|
auto print_options_node = root_node.add_child("printOptions");
|
||||||
|
print_options_node.add_attribute("horizontalCentered", ws.get_page_setup().get_horizontal_centered() ? 1 : 0);
|
||||||
|
print_options_node.add_attribute("verticalCentered", ws.get_page_setup().get_vertical_centered() ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto page_margins_node = root_node.add_child("pageMargins");
|
||||||
|
|
||||||
|
page_margins_node.add_attribute("left", ws.get_page_margins().get_left());
|
||||||
|
page_margins_node.add_attribute("right", ws.get_page_margins().get_right());
|
||||||
|
page_margins_node.add_attribute("top", ws.get_page_margins().get_top());
|
||||||
|
page_margins_node.add_attribute("bottom", ws.get_page_margins().get_bottom());
|
||||||
|
page_margins_node.add_attribute("header", ws.get_page_margins().get_header());
|
||||||
|
page_margins_node.add_attribute("footer", ws.get_page_margins().get_footer());
|
||||||
|
|
||||||
|
if(!ws.get_page_setup().is_default())
|
||||||
|
{
|
||||||
|
auto page_setup_node = root_node.add_child("pageSetup");
|
||||||
|
|
||||||
|
std::string orientation_string = ws.get_page_setup().get_orientation() == page_setup::orientation::landscape ? "landscape" : "portrait";
|
||||||
|
page_setup_node.add_attribute("orientation", orientation_string);
|
||||||
|
page_setup_node.add_attribute("paperSize", (int)ws.get_page_setup().get_paper_size());
|
||||||
|
page_setup_node.add_attribute("fitToHeight", ws.get_page_setup().fit_to_height() ? 1 : 0);
|
||||||
|
page_setup_node.add_attribute("fitToWidth", ws.get_page_setup().fit_to_width() ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ws.get_header_footer().is_default())
|
||||||
|
{
|
||||||
|
auto header_footer_node = root_node.add_child("headerFooter");
|
||||||
|
auto odd_header_node = header_footer_node.add_child("oddHeader");
|
||||||
|
std::string header_text = "&L&\"Calibri,Regular\"&K000000Left Header Text&C&\"Arial,Regular\"&6&K445566Center Header Text&R&\"Arial,Bold\"&8&K112233Right Header Text";
|
||||||
|
odd_header_node.text().set(header_text);
|
||||||
|
auto odd_footer_node = header_footer_node.add_child("oddFooter");
|
||||||
|
std::string footer_text = "&L&\"Times New Roman,Regular\"&10&K445566Left Footer Text_x000D_And &D and &T&C&\"Times New Roman,Bold\"&12&K778899Center Footer Text &Z&F on &A&R&\"Times New Roman,Italic\"&14&KAABBCCRight Footer Text &P of &N";
|
||||||
|
odd_footer_node.text().set(footer_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
doc.save(ss);
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
25
source/s11n/xml_document.cpp
Normal file
25
source/s11n/xml_document.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include <xlnt/s11n/xml_document.hpp>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
void xml_document::set_encoding(const std::string &encoding)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_document::add_namespace(const std::string &id, const std::string &uri)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_node &xml_document::root()
|
||||||
|
{
|
||||||
|
return root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const xml_node &xml_document::root() const
|
||||||
|
{
|
||||||
|
return root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
107
source/s11n/xml_node.cpp
Normal file
107
source/s11n/xml_node.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#include <xlnt/s11n/xml_node.hpp>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
xml_node::xml_node()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_node::xml_node(const std::string &name)
|
||||||
|
{
|
||||||
|
set_name(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string xml_node::get_name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_node::set_name(const std::string &name)
|
||||||
|
{
|
||||||
|
name_ = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xml_node::has_text() const
|
||||||
|
{
|
||||||
|
return has_text_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string xml_node::get_text() const
|
||||||
|
{
|
||||||
|
return text_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_node::set_text(const std::string &text)
|
||||||
|
{
|
||||||
|
text_ = text;
|
||||||
|
has_text_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<xml_node> &xml_node::get_children() const
|
||||||
|
{
|
||||||
|
return children_;
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_node &xml_node::add_child(const xml_node &child)
|
||||||
|
{
|
||||||
|
has_text_ = false;
|
||||||
|
text_.clear();
|
||||||
|
|
||||||
|
children_.push_back(child);
|
||||||
|
return children_.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_node &xml_node::add_child(const std::string &child_name)
|
||||||
|
{
|
||||||
|
return add_child(xml_node(child_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<string_pair> &xml_node::get_attributes() const
|
||||||
|
{
|
||||||
|
return attributes_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void xml_node::add_attribute(const std::string &name, const std::string &value)
|
||||||
|
{
|
||||||
|
attributes_.push_back(std::make_pair(name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xml_node::has_attribute(const std::string &attribute_name) const
|
||||||
|
{
|
||||||
|
return std::find(attributes_.begin(), attributes_.end(),
|
||||||
|
[&](const string_pair &p) { return p.first == attribute_name; }) != attributes_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string xml_node::get_attribute(const std::string &attribute_name) const
|
||||||
|
{
|
||||||
|
auto match = std::find(attributes_.begin(), attributes_.end(),
|
||||||
|
[&](const string_pair &p) { return p.first == attribute_name; });
|
||||||
|
|
||||||
|
if(match == attributes_.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("attribute doesn't exist: " + attribute_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return match->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xml_node::has_child(const std::string &child_name) const
|
||||||
|
{
|
||||||
|
return std::find(children_.begin(), children_.end(),
|
||||||
|
[&](const xml_node &n) { return n.get_name() == child_name; }) != children_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const xml_node &xml_node::get_child(const std::string &child_name) const
|
||||||
|
{
|
||||||
|
auto match = std::find(children_.begin(), children_.end(),
|
||||||
|
[&](const xml_node &n) { return n.get_name() == child_name; });
|
||||||
|
|
||||||
|
if(match == attributes_.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("child doesn't exist: " + child_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *match;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
85
source/s11n/xml_serializer.cpp
Normal file
85
source/s11n/xml_serializer.cpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <xlnt/s11n/xml_serializer.hpp>
|
||||||
|
#include <xlnt/s11n/xml_document.hpp>
|
||||||
|
#include <xlnt/s11n/xml_node.hpp>
|
||||||
|
|
||||||
|
#include "detail/include_pugixml.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void serialize_node(const xlnt::xml_node &source, pugi::xml_node node)
|
||||||
|
{
|
||||||
|
for(const auto &attribute : source.get_attributes())
|
||||||
|
{
|
||||||
|
node.append_attribute(attribute.first.c_str()).set_value(attribute.second.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(source.has_text())
|
||||||
|
{
|
||||||
|
node.text().set(source.get_text().c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(const auto &child : source.get_children())
|
||||||
|
{
|
||||||
|
pugi::xml_node child_node = node.append_child(child.get_name().c_str());
|
||||||
|
serialize_node(child, child_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xlnt::xml_node deserialize_node(const pugi::xml_node source)
|
||||||
|
{
|
||||||
|
xlnt::xml_node node(source.name());
|
||||||
|
|
||||||
|
for(const auto attribute : source.attributes())
|
||||||
|
{
|
||||||
|
node.add_attribute(attribute.name(), attribute.as_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(source.text() != nullptr)
|
||||||
|
{
|
||||||
|
node.set_text(source.text().as_string());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(const auto child : source.children())
|
||||||
|
{
|
||||||
|
node.add_child(deserialize_node(child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
std::string xml_serializer::serialize(const xml_document &xml)
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
|
||||||
|
auto root = doc.root();
|
||||||
|
root.set_name(xml.root().get_name().c_str());
|
||||||
|
serialize_node(xml.root(), root);
|
||||||
|
|
||||||
|
std::ostringstream ss;
|
||||||
|
doc.save(ss);
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
xml_document xml_serializer::deserialize(const std::string &xml_string)
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
doc.load(xml_string.c_str());
|
||||||
|
|
||||||
|
xml_document result;
|
||||||
|
result.root() = deserialize_node(doc.root());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
43
source/workbook/manifest.cpp
Normal file
43
source/workbook/manifest.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include <xlnt/workbook/manifest.hpp>
|
||||||
|
|
||||||
|
namespace xlnt {
|
||||||
|
|
||||||
|
bool manifest::has_default_type(const std::string &extension) const
|
||||||
|
{
|
||||||
|
return std::find_if(default_types_.begin(), default_types_.end(),
|
||||||
|
[&](const default_type &d) { return d.get_extension() == extension; }) != default_types_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool manifest::has_override_type(const std::string &part_name) const
|
||||||
|
{
|
||||||
|
return std::find_if(override_types_.begin(), override_types_.end(),
|
||||||
|
[&](const override_type &d) { return d.get_part_name() == part_name; }) != override_types_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string manifest::get_default_type(const std::string &extension) const
|
||||||
|
{
|
||||||
|
auto match = std::find_if(default_types_.begin(), default_types_.end(),
|
||||||
|
[&](const default_type &d) { return d.get_extension() == extension; });
|
||||||
|
|
||||||
|
if(match == default_types_.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("no default type found for extension: " + extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
return match->get_content_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string manifest::get_override_type(const std::string &part_name) const
|
||||||
|
{
|
||||||
|
auto match = std::find_if(override_types_.begin(), override_types_.end(),
|
||||||
|
[&](const override_type &d) { return d.get_part_name() == part_name; });
|
||||||
|
|
||||||
|
if(match == override_types_.end())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("no default type found for part name: " + part_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return match->get_content_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xlnt
|
|
@ -837,4 +837,14 @@ std::vector<color> workbook::get_colors() const
|
||||||
return d_->colors_;
|
return d_->colors_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
manifest &workbook::get_manifest()
|
||||||
|
{
|
||||||
|
return d_->manifest_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const manifest &workbook::get_manifest() const
|
||||||
|
{
|
||||||
|
return d_->manifest_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xlnt
|
} // namespace xlnt
|
||||||
|
|
|
@ -73,7 +73,7 @@ std::vector<range_reference> worksheet::get_merged_ranges() const
|
||||||
return d_->merged_cells_;
|
return d_->merged_cells_;
|
||||||
}
|
}
|
||||||
|
|
||||||
margins &worksheet::get_page_margins()
|
const margins &worksheet::get_page_margins() const
|
||||||
{
|
{
|
||||||
return d_->page_margins_;
|
return d_->page_margins_;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ void worksheet::unset_auto_filter()
|
||||||
d_->auto_filter_ = range_reference(1, 1, 1, 1);
|
d_->auto_filter_ = range_reference(1, 1, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
page_setup &worksheet::get_page_setup()
|
const page_setup &worksheet::get_page_setup() const
|
||||||
{
|
{
|
||||||
return d_->page_setup_;
|
return d_->page_setup_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,152 +0,0 @@
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
|
||||||
#include <xlnt/cell/cell_reference.hpp>
|
|
||||||
#include <xlnt/common/zip_file.hpp>
|
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
|
||||||
#include <xlnt/worksheet/range.hpp>
|
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
|
||||||
#include <xlnt/writer/excel_writer.hpp>
|
|
||||||
#include <xlnt/writer/manifest_writer.hpp>
|
|
||||||
#include <xlnt/writer/workbook_writer.hpp>
|
|
||||||
#include <xlnt/writer/worksheet_writer.hpp>
|
|
||||||
|
|
||||||
#include "detail/constants.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::vector<std::string> extract_all_strings(xlnt::workbook &wb)
|
|
||||||
{
|
|
||||||
std::unordered_set<std::string> strings;
|
|
||||||
|
|
||||||
for(auto ws : wb)
|
|
||||||
{
|
|
||||||
for(auto row : ws.rows())
|
|
||||||
{
|
|
||||||
for(auto cell : row)
|
|
||||||
{
|
|
||||||
if(cell.get_data_type() == xlnt::cell::type::string)
|
|
||||||
{
|
|
||||||
strings.insert(cell.get_value<std::string>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::vector<std::string>(strings.begin(), strings.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
excel_writer::excel_writer(workbook &wb) : wb_(wb)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::save(const std::string &filename, bool as_template)
|
|
||||||
{
|
|
||||||
zip_file archive;
|
|
||||||
write_data(archive, as_template);
|
|
||||||
archive.save(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_data(zip_file &archive, bool as_template)
|
|
||||||
{
|
|
||||||
archive.writestr(constants::ArcRootRels, write_root_rels(wb_));
|
|
||||||
archive.writestr(constants::ArcWorkbookRels, write_workbook_rels(wb_));
|
|
||||||
archive.writestr(constants::ArcApp, write_properties_app(wb_));
|
|
||||||
archive.writestr(constants::ArcCore, write_properties_core(wb_.get_properties()));
|
|
||||||
|
|
||||||
if(wb_.has_loaded_theme())
|
|
||||||
{
|
|
||||||
archive.writestr(constants::ArcTheme, wb_.get_loaded_theme());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
archive.writestr(constants::ArcTheme, write_theme());
|
|
||||||
}
|
|
||||||
|
|
||||||
archive.writestr(constants::ArcWorkbook, write_workbook(wb_));
|
|
||||||
|
|
||||||
auto shared_strings = extract_all_strings(wb_);
|
|
||||||
|
|
||||||
write_charts(archive);
|
|
||||||
write_images(archive);
|
|
||||||
write_shared_strings(archive, shared_strings);
|
|
||||||
write_worksheets(archive, shared_strings);
|
|
||||||
write_chartsheets(archive);
|
|
||||||
write_external_links(archive);
|
|
||||||
|
|
||||||
style_writer style_writer_(wb_);
|
|
||||||
archive.writestr(constants::ArcStyles, style_writer_.write_table());
|
|
||||||
|
|
||||||
auto manifest = write_content_types(wb_, as_template);
|
|
||||||
archive.writestr(constants::ArcContentTypes, manifest);
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_shared_strings(xlnt::zip_file &archive, const std::vector<std::string> &shared_strings)
|
|
||||||
{
|
|
||||||
archive.writestr(constants::ArcSharedString, ::xlnt::write_shared_strings(shared_strings));
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_images(zip_file &/*archive*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_charts(zip_file &/*archive*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_chartsheets(zip_file &/*archive*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_worksheets(zip_file &archive, const std::vector<std::string> &shared_strings)
|
|
||||||
{
|
|
||||||
std::size_t index = 0;
|
|
||||||
|
|
||||||
for(auto ws : wb_)
|
|
||||||
{
|
|
||||||
for(auto relationship : wb_.get_relationships())
|
|
||||||
{
|
|
||||||
if(relationship.get_type() == relationship::type::worksheet &&
|
|
||||||
workbook::index_from_ws_filename(relationship.get_target_uri()) == index)
|
|
||||||
{
|
|
||||||
archive.writestr(relationship.get_target_uri(), write_worksheet(ws, shared_strings));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void excel_writer::write_external_links(zip_file &/*archive*/)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool save_workbook(workbook &wb, const std::string &filename, bool as_template)
|
|
||||||
{
|
|
||||||
excel_writer writer(wb);
|
|
||||||
writer.save(filename, as_template);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> save_virtual_workbook(xlnt::workbook &wb, bool as_template)
|
|
||||||
{
|
|
||||||
zip_file archive;
|
|
||||||
excel_writer writer(wb);
|
|
||||||
writer.write_data(archive, as_template);
|
|
||||||
std::vector<std::uint8_t> buffer;
|
|
||||||
archive.save(buffer);
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,40 +0,0 @@
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
|
||||||
#include <xlnt/writer/manifest_writer.hpp>
|
|
||||||
|
|
||||||
#include "detail/constants.hpp"
|
|
||||||
#include "detail/include_pugixml.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
std::string write_content_types(const workbook &wb, bool /*as_template*/)
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
auto root_node = doc.append_child("Types");
|
|
||||||
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("content-types").c_str());
|
|
||||||
|
|
||||||
for(auto type : wb.get_content_types())
|
|
||||||
{
|
|
||||||
pugi::xml_node type_node;
|
|
||||||
|
|
||||||
if (type.is_default)
|
|
||||||
{
|
|
||||||
type_node = root_node.append_child("Default");
|
|
||||||
type_node.append_attribute("Extension").set_value(type.extension.c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
type_node = root_node.append_child("Override");
|
|
||||||
type_node.append_attribute("PartName").set_value(type.part_name.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
type_node.append_attribute("ContentType").set_value(type.type.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
doc.save(ss);
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -1,45 +0,0 @@
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <xlnt/common/relationship.hpp>
|
|
||||||
#include <xlnt/writer/relationship_writer.hpp>
|
|
||||||
|
|
||||||
#include "detail/constants.hpp"
|
|
||||||
#include "detail/include_pugixml.hpp"
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
std::string write_relationships(const std::vector<relationship> &relationships, const std::string &dir)
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
|
|
||||||
auto root_node = doc.append_child("Relationships");
|
|
||||||
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("relationships").c_str());
|
|
||||||
|
|
||||||
for(auto relationship : relationships)
|
|
||||||
{
|
|
||||||
auto target = relationship.get_target_uri();
|
|
||||||
|
|
||||||
if (dir != "" && target.substr(0, dir.size()) == dir)
|
|
||||||
{
|
|
||||||
target = target.substr(dir.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto app_props_node = root_node.append_child("Relationship");
|
|
||||||
|
|
||||||
app_props_node.append_attribute("Id").set_value(relationship.get_id().c_str());
|
|
||||||
app_props_node.append_attribute("Target").set_value(target.c_str());
|
|
||||||
app_props_node.append_attribute("Type").set_value(relationship.get_type_string().c_str());
|
|
||||||
|
|
||||||
if(relationship.get_target_mode() == target_mode::external)
|
|
||||||
{
|
|
||||||
app_props_node.append_attribute("TargetMode").set_value("External");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
doc.save(ss);
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,409 +0,0 @@
|
||||||
#include <sstream>
|
|
||||||
#include <pugixml.hpp>
|
|
||||||
|
|
||||||
#include <xlnt/styles/alignment.hpp>
|
|
||||||
#include <xlnt/styles/border.hpp>
|
|
||||||
#include <xlnt/styles/fill.hpp>
|
|
||||||
#include <xlnt/styles/font.hpp>
|
|
||||||
#include <xlnt/styles/number_format.hpp>
|
|
||||||
#include <xlnt/styles/protection.hpp>
|
|
||||||
#include <xlnt/writer/style_writer.hpp>
|
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
|
||||||
#include <xlnt/worksheet/range.hpp>
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
style_writer::style_writer(xlnt::workbook &wb) : wb_(wb)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string style_writer::write_table() const
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
auto style_sheet_node = doc.append_child("styleSheet");
|
|
||||||
style_sheet_node.append_attribute("xmlns").set_value("http://schemas.openxmlformats.org/spreadsheetml/2006/main");
|
|
||||||
style_sheet_node.append_attribute("xmlns:mc").set_value("http://schemas.openxmlformats.org/markup-compatibility/2006");
|
|
||||||
style_sheet_node.append_attribute("mc:Ignorable").set_value("x14ac");
|
|
||||||
style_sheet_node.append_attribute("xmlns:x14ac").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac");
|
|
||||||
|
|
||||||
auto num_fmts_node = style_sheet_node.append_child("numFmts");
|
|
||||||
auto num_fmts = wb_.get_number_formats();
|
|
||||||
num_fmts_node.append_attribute("count").set_value(static_cast<int>(num_fmts.size()));
|
|
||||||
|
|
||||||
for(auto &num_fmt : num_fmts)
|
|
||||||
{
|
|
||||||
auto num_fmt_node = num_fmts_node.append_child("numFmt");
|
|
||||||
num_fmt_node.append_attribute("numFmtId").set_value(num_fmt.get_id());
|
|
||||||
num_fmt_node.append_attribute("formatCode").set_value(num_fmt.get_format_string().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fonts_node = style_sheet_node.append_child("fonts");
|
|
||||||
auto fonts = wb_.get_fonts();
|
|
||||||
if(fonts.empty())
|
|
||||||
{
|
|
||||||
fonts.push_back(font());
|
|
||||||
}
|
|
||||||
fonts_node.append_attribute("count").set_value(static_cast<int>(fonts.size()));
|
|
||||||
fonts_node.append_attribute("x14ac:knownFonts").set_value(1);
|
|
||||||
|
|
||||||
for(auto &f : fonts)
|
|
||||||
{
|
|
||||||
auto font_node = fonts_node.append_child("font");
|
|
||||||
|
|
||||||
if(f.is_bold())
|
|
||||||
{
|
|
||||||
auto bold_node = font_node.append_child("b");
|
|
||||||
bold_node.append_attribute("val").set_value(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(f.is_italic())
|
|
||||||
{
|
|
||||||
auto bold_node = font_node.append_child("i");
|
|
||||||
bold_node.append_attribute("val").set_value(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(f.is_underline())
|
|
||||||
{
|
|
||||||
auto bold_node = font_node.append_child("u");
|
|
||||||
|
|
||||||
switch(f.get_underline())
|
|
||||||
{
|
|
||||||
case font::underline_style::single:
|
|
||||||
bold_node.append_attribute("val").set_value("single");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(f.is_strikethrough())
|
|
||||||
{
|
|
||||||
auto bold_node = font_node.append_child("strike");
|
|
||||||
bold_node.append_attribute("val").set_value(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto size_node = font_node.append_child("sz");
|
|
||||||
size_node.append_attribute("val").set_value(f.get_size());
|
|
||||||
|
|
||||||
auto color_node = font_node.append_child("color");
|
|
||||||
|
|
||||||
if(f.get_color().get_type() == color::type::indexed)
|
|
||||||
{
|
|
||||||
color_node.append_attribute("indexed").set_value(static_cast<unsigned int>(f.get_color().get_index()));
|
|
||||||
}
|
|
||||||
else if(f.get_color().get_type() == color::type::theme)
|
|
||||||
{
|
|
||||||
color_node.append_attribute("theme").set_value(static_cast<unsigned int>(f.get_color().get_theme()));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto name_node = font_node.append_child("name");
|
|
||||||
name_node.append_attribute("val").set_value(f.get_name().c_str());
|
|
||||||
|
|
||||||
if(f.has_family())
|
|
||||||
{
|
|
||||||
auto family_node = font_node.append_child("family");
|
|
||||||
family_node.append_attribute("val").set_value(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(f.has_scheme())
|
|
||||||
{
|
|
||||||
auto scheme_node = font_node.append_child("scheme");
|
|
||||||
scheme_node.append_attribute("val").set_value("minor");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto fills_node = style_sheet_node.append_child("fills");
|
|
||||||
const auto &fills = wb_.get_fills();
|
|
||||||
fills_node.append_attribute("count").set_value(static_cast<unsigned int>(fills.size()));
|
|
||||||
|
|
||||||
for(auto &fill_ : fills)
|
|
||||||
{
|
|
||||||
auto fill_node = fills_node.append_child("fill");
|
|
||||||
|
|
||||||
if(fill_.get_type() == fill::type::pattern)
|
|
||||||
{
|
|
||||||
auto pattern_fill_node = fill_node.append_child("patternFill");
|
|
||||||
auto type_string = fill_.get_pattern_type_string();
|
|
||||||
pattern_fill_node.append_attribute("patternType").set_value(type_string.c_str());
|
|
||||||
|
|
||||||
if(fill_.has_foreground_color())
|
|
||||||
{
|
|
||||||
auto fg_color_node = pattern_fill_node.append_child("fgColor");
|
|
||||||
|
|
||||||
switch(fill_.get_foreground_color().get_type())
|
|
||||||
{
|
|
||||||
case color::type::auto_: fg_color_node.append_attribute("auto").set_value(fill_.get_foreground_color().get_auto()); break;
|
|
||||||
case color::type::theme: fg_color_node.append_attribute("theme").set_value(fill_.get_foreground_color().get_theme()); break;
|
|
||||||
case color::type::indexed: fg_color_node.append_attribute("indexed").set_value(fill_.get_foreground_color().get_index()); break;
|
|
||||||
default: throw std::runtime_error("bad type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fill_.has_background_color())
|
|
||||||
{
|
|
||||||
auto bg_color_node = pattern_fill_node.append_child("bgColor");
|
|
||||||
|
|
||||||
switch(fill_.get_background_color().get_type())
|
|
||||||
{
|
|
||||||
case color::type::auto_: bg_color_node.append_attribute("auto").set_value(fill_.get_background_color().get_auto()); break;
|
|
||||||
case color::type::theme: bg_color_node.append_attribute("theme").set_value(fill_.get_background_color().get_theme()); break;
|
|
||||||
case color::type::indexed: bg_color_node.append_attribute("indexed").set_value(fill_.get_background_color().get_index()); break;
|
|
||||||
default: throw std::runtime_error("bad type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(fill_.get_type() == fill::type::solid)
|
|
||||||
{
|
|
||||||
auto solid_fill_node = fill_node.append_child("solidFill");
|
|
||||||
solid_fill_node.append_child("color");
|
|
||||||
}
|
|
||||||
else if(fill_.get_type() == fill::type::gradient)
|
|
||||||
{
|
|
||||||
auto gradient_fill_node = fill_node.append_child("gradientFill");
|
|
||||||
|
|
||||||
if(fill_.get_gradient_type_string() == "linear")
|
|
||||||
{
|
|
||||||
gradient_fill_node.append_attribute("degree").set_value(fill_.get_rotation());
|
|
||||||
}
|
|
||||||
else if(fill_.get_gradient_type_string() == "path")
|
|
||||||
{
|
|
||||||
gradient_fill_node.append_attribute("left").set_value(fill_.get_gradient_left());
|
|
||||||
gradient_fill_node.append_attribute("right").set_value(fill_.get_gradient_right());
|
|
||||||
gradient_fill_node.append_attribute("top").set_value(fill_.get_gradient_top());
|
|
||||||
gradient_fill_node.append_attribute("bottom").set_value(fill_.get_gradient_bottom());
|
|
||||||
|
|
||||||
auto start_node = gradient_fill_node.append_child("stop");
|
|
||||||
start_node.append_attribute("position").set_value(0);
|
|
||||||
|
|
||||||
auto end_node = gradient_fill_node.append_child("stop");
|
|
||||||
end_node.append_attribute("position").set_value(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto borders_node = style_sheet_node.append_child("borders");
|
|
||||||
const auto &borders = wb_.get_borders();
|
|
||||||
borders_node.append_attribute("count").set_value(static_cast<unsigned int>(borders.size()));
|
|
||||||
|
|
||||||
for(const auto &border_ : borders)
|
|
||||||
{
|
|
||||||
auto border_node = borders_node.append_child("border");
|
|
||||||
|
|
||||||
std::vector<std::tuple<std::string, const side, bool>> sides;
|
|
||||||
sides.push_back(std::make_tuple("start", border_.start, border_.start_assigned));
|
|
||||||
sides.push_back(std::make_tuple("end", border_.end, border_.end_assigned));
|
|
||||||
sides.push_back(std::make_tuple("left", border_.left, border_.left_assigned));
|
|
||||||
sides.push_back(std::make_tuple("right", border_.right, border_.right_assigned));
|
|
||||||
sides.push_back(std::make_tuple("top", border_.top, border_.top_assigned));
|
|
||||||
sides.push_back(std::make_tuple("bottom", border_.bottom, border_.bottom_assigned));
|
|
||||||
sides.push_back(std::make_tuple("diagonal", border_.diagonal, border_.diagonal_assigned));
|
|
||||||
sides.push_back(std::make_tuple("vertical", border_.vertical, border_.vertical_assigned));
|
|
||||||
sides.push_back(std::make_tuple("horizontal", border_.horizontal, border_.horizontal_assigned));
|
|
||||||
|
|
||||||
for(const auto &side_tuple : sides)
|
|
||||||
{
|
|
||||||
std::string name = std::get<0>(side_tuple);
|
|
||||||
const side side_ = std::get<1>(side_tuple);
|
|
||||||
bool assigned = std::get<2>(side_tuple);
|
|
||||||
|
|
||||||
if(assigned)
|
|
||||||
{
|
|
||||||
auto side_node = border_node.append_child(name.c_str());
|
|
||||||
|
|
||||||
if(side_.is_style_assigned())
|
|
||||||
{
|
|
||||||
auto style_attribute = side_node.append_attribute("style");
|
|
||||||
|
|
||||||
switch(side_.get_style())
|
|
||||||
{
|
|
||||||
case border_style::none: style_attribute.set_value("none"); break;
|
|
||||||
case border_style::dashdot : style_attribute.set_value("dashdot"); break;
|
|
||||||
case border_style::dashdotdot : style_attribute.set_value("dashdotdot"); break;
|
|
||||||
case border_style::dashed : style_attribute.set_value("dashed"); break;
|
|
||||||
case border_style::dotted : style_attribute.set_value("dotted"); break;
|
|
||||||
case border_style::double_ : style_attribute.set_value("double"); break;
|
|
||||||
case border_style::hair : style_attribute.set_value("hair"); break;
|
|
||||||
case border_style::medium : style_attribute.set_value("thin"); break;
|
|
||||||
case border_style::mediumdashdot: style_attribute.set_value("mediumdashdot"); break;
|
|
||||||
case border_style::mediumdashdotdot: style_attribute.set_value("mediumdashdotdot"); break;
|
|
||||||
case border_style::mediumdashed: style_attribute.set_value("mediumdashed"); break;
|
|
||||||
case border_style::slantdashdot: style_attribute.set_value("slantdashdot"); break;
|
|
||||||
case border_style::thick: style_attribute.set_value("thick"); break;
|
|
||||||
case border_style::thin: style_attribute.set_value("thin"); break;
|
|
||||||
default: throw std::runtime_error("invalid style");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(side_.is_color_assigned())
|
|
||||||
{
|
|
||||||
auto color_node = side_node.append_child("color");
|
|
||||||
|
|
||||||
if(side_.get_color_type() == side::color_type::indexed)
|
|
||||||
{
|
|
||||||
color_node.append_attribute("indexed").set_value((int)side_.get_color());
|
|
||||||
}
|
|
||||||
else if(side_.get_color_type() == side::color_type::theme)
|
|
||||||
{
|
|
||||||
color_node.append_attribute("indexed").set_value((int)side_.get_color());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw std::runtime_error("invalid color type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cell_style_xfs_node = style_sheet_node.append_child("cellStyleXfs");
|
|
||||||
cell_style_xfs_node.append_attribute("count").set_value(1);
|
|
||||||
auto style_xf_node = cell_style_xfs_node.append_child("xf");
|
|
||||||
style_xf_node.append_attribute("numFmtId").set_value(0);
|
|
||||||
style_xf_node.append_attribute("fontId").set_value(0);
|
|
||||||
style_xf_node.append_attribute("fillId").set_value(0);
|
|
||||||
style_xf_node.append_attribute("borderId").set_value(0);
|
|
||||||
|
|
||||||
auto cell_xfs_node = style_sheet_node.append_child("cellXfs");
|
|
||||||
const auto &styles = wb_.get_styles();
|
|
||||||
cell_xfs_node.append_attribute("count").set_value(static_cast<int>(styles.size()));
|
|
||||||
|
|
||||||
for(auto &style : styles)
|
|
||||||
{
|
|
||||||
auto xf_node = cell_xfs_node.append_child("xf");
|
|
||||||
xf_node.append_attribute("numFmtId").set_value(style.get_number_format().get_id());
|
|
||||||
xf_node.append_attribute("fontId").set_value((int)style.get_font_id());
|
|
||||||
|
|
||||||
if(style.fill_apply_)
|
|
||||||
{
|
|
||||||
xf_node.append_attribute("fillId").set_value((int)style.get_fill_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(style.border_apply_)
|
|
||||||
{
|
|
||||||
xf_node.append_attribute("borderId").set_value((int)style.get_border_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
xf_node.append_attribute("applyNumberFormat").set_value(style.number_format_apply_ ? 1 : 0);
|
|
||||||
xf_node.append_attribute("applyFont").set_value(style.font_apply_ ? 1 : 0);
|
|
||||||
xf_node.append_attribute("applyFill").set_value(style.fill_apply_ ? 1 : 0);
|
|
||||||
xf_node.append_attribute("applyBorder").set_value(style.border_apply_ ? 1 : 0);
|
|
||||||
xf_node.append_attribute("applyAlignment").set_value(style.alignment_apply_ ? 1 : 0);
|
|
||||||
xf_node.append_attribute("applyProtection").set_value(style.protection_apply_ ? 1 : 0);
|
|
||||||
|
|
||||||
if(style.alignment_apply_)
|
|
||||||
{
|
|
||||||
auto alignment_node = xf_node.append_child("alignment");
|
|
||||||
|
|
||||||
if(style.alignment_.has_vertical())
|
|
||||||
{
|
|
||||||
switch(style.alignment_.get_vertical())
|
|
||||||
{
|
|
||||||
case alignment::vertical_alignment::bottom:
|
|
||||||
alignment_node.append_attribute("vertical").set_value("bottom");
|
|
||||||
break;
|
|
||||||
case alignment::vertical_alignment::center:
|
|
||||||
alignment_node.append_attribute("vertical").set_value("center");
|
|
||||||
break;
|
|
||||||
case alignment::vertical_alignment::justify:
|
|
||||||
alignment_node.append_attribute("vertical").set_value("justify");
|
|
||||||
break;
|
|
||||||
case alignment::vertical_alignment::top:
|
|
||||||
alignment_node.append_attribute("vertical").set_value("top");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("invalid alignment");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(style.alignment_.has_horizontal())
|
|
||||||
{
|
|
||||||
switch(style.alignment_.get_horizontal())
|
|
||||||
{
|
|
||||||
case alignment::horizontal_alignment::center:
|
|
||||||
alignment_node.append_attribute("horizontal").set_value("center");
|
|
||||||
break;
|
|
||||||
case alignment::horizontal_alignment::center_continuous:
|
|
||||||
alignment_node.append_attribute("horizontal").set_value("center_continuous");
|
|
||||||
break;
|
|
||||||
case alignment::horizontal_alignment::general:
|
|
||||||
alignment_node.append_attribute("horizontal").set_value("general");
|
|
||||||
break;
|
|
||||||
case alignment::horizontal_alignment::justify:
|
|
||||||
alignment_node.append_attribute("horizontal").set_value("justify");
|
|
||||||
break;
|
|
||||||
case alignment::horizontal_alignment::left:
|
|
||||||
alignment_node.append_attribute("horizontal").set_value("left");
|
|
||||||
break;
|
|
||||||
case alignment::horizontal_alignment::right:
|
|
||||||
alignment_node.append_attribute("horizontal").set_value("right");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("invalid alignment");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(style.alignment_.get_wrap_text())
|
|
||||||
{
|
|
||||||
alignment_node.append_attribute("wrapText").set_value(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cell_styles_node = style_sheet_node.append_child("cellStyles");
|
|
||||||
cell_styles_node.append_attribute("count").set_value(1);
|
|
||||||
auto cell_style_node = cell_styles_node.append_child("cellStyle");
|
|
||||||
cell_style_node.append_attribute("name").set_value("Normal");
|
|
||||||
cell_style_node.append_attribute("xfId").set_value(0);
|
|
||||||
cell_style_node.append_attribute("builtinId").set_value(0);
|
|
||||||
|
|
||||||
style_sheet_node.append_child("dxfs").append_attribute("count").set_value(0);
|
|
||||||
|
|
||||||
auto table_styles_node = style_sheet_node.append_child("tableStyles");
|
|
||||||
table_styles_node.append_attribute("count").set_value(0);
|
|
||||||
table_styles_node.append_attribute("defaultTableStyle").set_value("TableStyleMedium2");
|
|
||||||
table_styles_node.append_attribute("defaultPivotStyle").set_value("PivotStyleMedium9");
|
|
||||||
|
|
||||||
auto colors_node = style_sheet_node.append_child("colors");
|
|
||||||
auto indexed_colors_node = colors_node.append_child("indexedColors");
|
|
||||||
|
|
||||||
for(auto &c : wb_.get_colors())
|
|
||||||
{
|
|
||||||
indexed_colors_node.append_child("rgbColor").append_attribute("rgb").set_value(c.get_rgb_string().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ext_list_node = style_sheet_node.append_child("extLst");
|
|
||||||
auto ext_node = ext_list_node.append_child("ext");
|
|
||||||
ext_node.append_attribute("uri").set_value("{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}");
|
|
||||||
ext_node.append_attribute("xmlns:x14").set_value("http://schemas.microsoft.com/office/spreadsheetml/2009/9/main");
|
|
||||||
ext_node.append_child("x14:slicerStyles").append_attribute("defaultSlicerStyle").set_value("SlicerStyleLight1");
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
doc.save(ss);
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,369 +0,0 @@
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <xlnt/cell/cell.hpp>
|
|
||||||
#include <xlnt/cell/cell_reference.hpp>
|
|
||||||
#include <xlnt/styles/border.hpp>
|
|
||||||
#include <xlnt/styles/fill.hpp>
|
|
||||||
#include <xlnt/styles/font.hpp>
|
|
||||||
#include <xlnt/styles/number_format.hpp>
|
|
||||||
#include <xlnt/workbook/workbook.hpp>
|
|
||||||
#include <xlnt/worksheet/range.hpp>
|
|
||||||
#include <xlnt/worksheet/range_reference.hpp>
|
|
||||||
#include <xlnt/worksheet/worksheet.hpp>
|
|
||||||
#include <xlnt/writer/worksheet_writer.hpp>
|
|
||||||
|
|
||||||
#include "detail/constants.hpp"
|
|
||||||
#include "detail/include_pugixml.hpp"
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
bool is_integral(long double d)
|
|
||||||
{
|
|
||||||
return d == static_cast<long long int>(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namepsace
|
|
||||||
|
|
||||||
namespace xlnt {
|
|
||||||
|
|
||||||
std::string write_worksheet(worksheet ws, const std::vector<std::string> &string_table)
|
|
||||||
{
|
|
||||||
ws.get_cell("A1");
|
|
||||||
|
|
||||||
pugi::xml_document doc;
|
|
||||||
auto root_node = doc.append_child("worksheet");
|
|
||||||
root_node.append_attribute("xmlns").set_value(constants::Namespaces.at("spreadsheetml").c_str());
|
|
||||||
root_node.append_attribute("xmlns:r").set_value(constants::Namespaces.at("r").c_str());
|
|
||||||
auto sheet_pr_node = root_node.append_child("sheetPr");
|
|
||||||
auto outline_pr_node = sheet_pr_node.append_child("outlinePr");
|
|
||||||
if(!ws.get_page_setup().is_default())
|
|
||||||
{
|
|
||||||
auto page_set_up_pr_node = sheet_pr_node.append_child("pageSetUpPr");
|
|
||||||
page_set_up_pr_node.append_attribute("fitToPage").set_value(ws.get_page_setup().fit_to_page() ? 1 : 0);
|
|
||||||
}
|
|
||||||
outline_pr_node.append_attribute("summaryBelow").set_value(1);
|
|
||||||
outline_pr_node.append_attribute("summaryRight").set_value(1);
|
|
||||||
auto dimension_node = root_node.append_child("dimension");
|
|
||||||
dimension_node.append_attribute("ref").set_value(ws.calculate_dimension().to_string().c_str());
|
|
||||||
auto sheet_views_node = root_node.append_child("sheetViews");
|
|
||||||
auto sheet_view_node = sheet_views_node.append_child("sheetView");
|
|
||||||
sheet_view_node.append_attribute("workbookViewId").set_value(0);
|
|
||||||
|
|
||||||
std::string active_pane = "bottomRight";
|
|
||||||
|
|
||||||
if(ws.has_frozen_panes())
|
|
||||||
{
|
|
||||||
auto pane_node = sheet_view_node.append_child("pane");
|
|
||||||
|
|
||||||
if(ws.get_frozen_panes().get_column_index() > 1)
|
|
||||||
{
|
|
||||||
pane_node.append_attribute("xSplit").set_value(ws.get_frozen_panes().get_column_index() - 1);
|
|
||||||
active_pane = "topRight";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ws.get_frozen_panes().get_row() > 1)
|
|
||||||
{
|
|
||||||
pane_node.append_attribute("ySplit").set_value(ws.get_frozen_panes().get_row() - 1);
|
|
||||||
active_pane = "bottomLeft";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
|
|
||||||
{
|
|
||||||
auto top_right_node = sheet_view_node.append_child("selection");
|
|
||||||
top_right_node.append_attribute("pane").set_value("topRight");
|
|
||||||
auto bottom_left_node = sheet_view_node.append_child("selection");
|
|
||||||
bottom_left_node.append_attribute("pane").set_value("bottomLeft");
|
|
||||||
active_pane = "bottomRight";
|
|
||||||
}
|
|
||||||
|
|
||||||
pane_node.append_attribute("topLeftCell").set_value(ws.get_frozen_panes().to_string().c_str());
|
|
||||||
pane_node.append_attribute("activePane").set_value(active_pane.c_str());
|
|
||||||
pane_node.append_attribute("state").set_value("frozen");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto selection_node = sheet_view_node.append_child("selection");
|
|
||||||
|
|
||||||
if(ws.has_frozen_panes())
|
|
||||||
{
|
|
||||||
if(ws.get_frozen_panes().get_row() > 1 && ws.get_frozen_panes().get_column_index() > 1)
|
|
||||||
{
|
|
||||||
selection_node.append_attribute("pane").set_value("bottomRight");
|
|
||||||
}
|
|
||||||
else if(ws.get_frozen_panes().get_row() > 1)
|
|
||||||
{
|
|
||||||
selection_node.append_attribute("pane").set_value("bottomLeft");
|
|
||||||
}
|
|
||||||
else if(ws.get_frozen_panes().get_column_index() > 1)
|
|
||||||
{
|
|
||||||
selection_node.append_attribute("pane").set_value("topRight");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string active_cell = "A1";
|
|
||||||
selection_node.append_attribute("activeCell").set_value(active_cell.c_str());
|
|
||||||
selection_node.append_attribute("sqref").set_value(active_cell.c_str());
|
|
||||||
|
|
||||||
auto sheet_format_pr_node = root_node.append_child("sheetFormatPr");
|
|
||||||
sheet_format_pr_node.append_attribute("baseColWidth").set_value(10);
|
|
||||||
sheet_format_pr_node.append_attribute("defaultRowHeight").set_value(15);
|
|
||||||
|
|
||||||
bool has_column_properties = false;
|
|
||||||
|
|
||||||
for(auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++)
|
|
||||||
{
|
|
||||||
if(ws.has_column_properties(column))
|
|
||||||
{
|
|
||||||
has_column_properties = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(has_column_properties)
|
|
||||||
{
|
|
||||||
auto cols_node = root_node.append_child("cols");
|
|
||||||
|
|
||||||
for(auto column = ws.get_lowest_column(); column <= ws.get_highest_column(); column++)
|
|
||||||
{
|
|
||||||
const auto &props = ws.get_column_properties(column);
|
|
||||||
|
|
||||||
auto col_node = cols_node.append_child("col");
|
|
||||||
|
|
||||||
col_node.append_attribute("min").set_value(column);
|
|
||||||
col_node.append_attribute("max").set_value(column);
|
|
||||||
col_node.append_attribute("width").set_value(props.width);
|
|
||||||
col_node.append_attribute("style").set_value(static_cast<unsigned long long>(props.style));
|
|
||||||
col_node.append_attribute("customWidth").set_value(props.custom ? 1 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string> hyperlink_references;
|
|
||||||
|
|
||||||
auto sheet_data_node = root_node.append_child("sheetData");
|
|
||||||
|
|
||||||
for(auto row : ws.rows())
|
|
||||||
{
|
|
||||||
row_t min = static_cast<row_t>(row.num_cells());
|
|
||||||
row_t max = 0;
|
|
||||||
bool any_non_null = false;
|
|
||||||
|
|
||||||
for(auto cell : row)
|
|
||||||
{
|
|
||||||
min = std::min(min, cell_reference::column_index_from_string(cell.get_column()));
|
|
||||||
max = std::max(max, cell_reference::column_index_from_string(cell.get_column()));
|
|
||||||
|
|
||||||
if(!cell.garbage_collectible())
|
|
||||||
{
|
|
||||||
any_non_null = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!any_non_null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto row_node = sheet_data_node.append_child("row");
|
|
||||||
|
|
||||||
row_node.append_attribute("r").set_value(row.front().get_row());
|
|
||||||
row_node.append_attribute("spans").set_value((std::to_string(min) + ":" + std::to_string(max)).c_str());
|
|
||||||
|
|
||||||
if(ws.has_row_properties(row.front().get_row()))
|
|
||||||
{
|
|
||||||
row_node.append_attribute("customHeight").set_value(1);
|
|
||||||
auto height = ws.get_row_properties(row.front().get_row()).height;
|
|
||||||
|
|
||||||
if(height == std::floor(height))
|
|
||||||
{
|
|
||||||
row_node.append_attribute("ht").set_value((std::to_string((int)height) + ".0").c_str());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
row_node.append_attribute("ht").set_value(height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//row_node.append_attribute("x14ac:dyDescent").set_value(0.25);
|
|
||||||
|
|
||||||
for(auto cell : row)
|
|
||||||
{
|
|
||||||
if(!cell.garbage_collectible())
|
|
||||||
{
|
|
||||||
if(cell.has_hyperlink())
|
|
||||||
{
|
|
||||||
hyperlink_references[cell.get_hyperlink().get_id()] = cell.get_reference().to_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cell_node = row_node.append_child("c");
|
|
||||||
cell_node.append_attribute("r").set_value(cell.get_reference().to_string().c_str());
|
|
||||||
|
|
||||||
if(cell.get_data_type() == cell::type::string)
|
|
||||||
{
|
|
||||||
if(cell.has_formula())
|
|
||||||
{
|
|
||||||
cell_node.append_attribute("t").set_value("str");
|
|
||||||
cell_node.append_child("f").text().set(cell.get_formula().c_str());
|
|
||||||
cell_node.append_child("v").text().set(cell.to_string().c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int match_index = -1;
|
|
||||||
|
|
||||||
for(std::size_t i = 0; i < string_table.size(); i++)
|
|
||||||
{
|
|
||||||
if(string_table[i] == cell.get_value<std::string>())
|
|
||||||
{
|
|
||||||
match_index = static_cast<int>(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(match_index == -1)
|
|
||||||
{
|
|
||||||
if(cell.get_value<std::string>().empty())
|
|
||||||
{
|
|
||||||
cell_node.append_attribute("t").set_value("s");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cell_node.append_attribute("t").set_value("inlineStr");
|
|
||||||
auto inline_string_node = cell_node.append_child("is");
|
|
||||||
inline_string_node.append_child("t").text().set(cell.get_value<std::string>().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cell_node.append_attribute("t").set_value("s");
|
|
||||||
auto value_node = cell_node.append_child("v");
|
|
||||||
value_node.text().set(match_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(cell.get_data_type() != cell::type::null)
|
|
||||||
{
|
|
||||||
if(cell.get_data_type() == cell::type::boolean)
|
|
||||||
{
|
|
||||||
cell_node.append_attribute("t").set_value("b");
|
|
||||||
auto value_node = cell_node.append_child("v");
|
|
||||||
value_node.text().set(cell.get_value<bool>() ? 1 : 0);
|
|
||||||
}
|
|
||||||
else if(cell.get_data_type() == cell::type::numeric)
|
|
||||||
{
|
|
||||||
if(cell.has_formula())
|
|
||||||
{
|
|
||||||
cell_node.append_child("f").text().set(cell.get_formula().c_str());
|
|
||||||
cell_node.append_child("v").text().set(cell.to_string().c_str());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell_node.append_attribute("t").set_value("n");
|
|
||||||
auto value_node = cell_node.append_child("v");
|
|
||||||
if(is_integral(cell.get_value<long double>()))
|
|
||||||
{
|
|
||||||
value_node.text().set(cell.get_value<long long>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::stringstream ss;
|
|
||||||
ss.precision(20);
|
|
||||||
ss << cell.get_value<long double>();
|
|
||||||
ss.str();
|
|
||||||
value_node.text().set(ss.str().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(cell.has_formula())
|
|
||||||
{
|
|
||||||
cell_node.append_child("f").text().set(cell.get_formula().c_str());
|
|
||||||
cell_node.append_child("v");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if(cell.has_style())
|
|
||||||
{
|
|
||||||
auto style_id = cell.get_style_id();
|
|
||||||
cell_node.append_attribute("s").set_value((int)style_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ws.has_auto_filter())
|
|
||||||
{
|
|
||||||
auto auto_filter_node = root_node.append_child("autoFilter");
|
|
||||||
auto_filter_node.append_attribute("ref").set_value(ws.get_auto_filter().to_string().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ws.get_merged_ranges().empty())
|
|
||||||
{
|
|
||||||
auto merge_cells_node = root_node.append_child("mergeCells");
|
|
||||||
merge_cells_node.append_attribute("count").set_value((unsigned int)ws.get_merged_ranges().size());
|
|
||||||
|
|
||||||
for(auto merged_range : ws.get_merged_ranges())
|
|
||||||
{
|
|
||||||
auto merge_cell_node = merge_cells_node.append_child("mergeCell");
|
|
||||||
merge_cell_node.append_attribute("ref").set_value(merged_range.to_string().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ws.get_relationships().empty())
|
|
||||||
{
|
|
||||||
auto hyperlinks_node = root_node.append_child("hyperlinks");
|
|
||||||
|
|
||||||
for(auto relationship : ws.get_relationships())
|
|
||||||
{
|
|
||||||
auto hyperlink_node = hyperlinks_node.append_child("hyperlink");
|
|
||||||
hyperlink_node.append_attribute("display").set_value(relationship.get_target_uri().c_str());
|
|
||||||
hyperlink_node.append_attribute("ref").set_value(hyperlink_references.at(relationship.get_id()).c_str());
|
|
||||||
hyperlink_node.append_attribute("r:id").set_value(relationship.get_id().c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ws.get_page_setup().is_default())
|
|
||||||
{
|
|
||||||
auto print_options_node = root_node.append_child("printOptions");
|
|
||||||
print_options_node.append_attribute("horizontalCentered").set_value(ws.get_page_setup().get_horizontal_centered() ? 1 : 0);
|
|
||||||
print_options_node.append_attribute("verticalCentered").set_value(ws.get_page_setup().get_vertical_centered() ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto page_margins_node = root_node.append_child("pageMargins");
|
|
||||||
|
|
||||||
page_margins_node.append_attribute("left").set_value(ws.get_page_margins().get_left());
|
|
||||||
page_margins_node.append_attribute("right").set_value(ws.get_page_margins().get_right());
|
|
||||||
page_margins_node.append_attribute("top").set_value(ws.get_page_margins().get_top());
|
|
||||||
page_margins_node.append_attribute("bottom").set_value(ws.get_page_margins().get_bottom());
|
|
||||||
page_margins_node.append_attribute("header").set_value(ws.get_page_margins().get_header());
|
|
||||||
page_margins_node.append_attribute("footer").set_value(ws.get_page_margins().get_footer());
|
|
||||||
|
|
||||||
if(!ws.get_page_setup().is_default())
|
|
||||||
{
|
|
||||||
auto page_setup_node = root_node.append_child("pageSetup");
|
|
||||||
|
|
||||||
std::string orientation_string = ws.get_page_setup().get_orientation() == page_setup::orientation::landscape ? "landscape" : "portrait";
|
|
||||||
page_setup_node.append_attribute("orientation").set_value(orientation_string.c_str());
|
|
||||||
page_setup_node.append_attribute("paperSize").set_value((int)ws.get_page_setup().get_paper_size());
|
|
||||||
page_setup_node.append_attribute("fitToHeight").set_value(ws.get_page_setup().fit_to_height() ? 1 : 0);
|
|
||||||
page_setup_node.append_attribute("fitToWidth").set_value(ws.get_page_setup().fit_to_width() ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ws.get_header_footer().is_default())
|
|
||||||
{
|
|
||||||
auto header_footer_node = root_node.append_child("headerFooter");
|
|
||||||
auto odd_header_node = header_footer_node.append_child("oddHeader");
|
|
||||||
std::string header_text = "&L&\"Calibri,Regular\"&K000000Left Header Text&C&\"Arial,Regular\"&6&K445566Center Header Text&R&\"Arial,Bold\"&8&K112233Right Header Text";
|
|
||||||
odd_header_node.text().set(header_text.c_str());
|
|
||||||
auto odd_footer_node = header_footer_node.append_child("oddFooter");
|
|
||||||
std::string footer_text = "&L&\"Times New Roman,Regular\"&10&K445566Left Footer Text_x000D_And &D and &T&C&\"Times New Roman,Bold\"&12&K778899Center Footer Text &Z&F on &A&R&\"Times New Roman,Italic\"&14&KAABBCCRight Footer Text &P of &N";
|
|
||||||
odd_footer_node.text().set(footer_text.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stringstream ss;
|
|
||||||
doc.save(ss);
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace xlnt
|
|
|
@ -22,6 +22,8 @@
|
||||||
#include <xlnt/writer/excel_writer.hpp>
|
#include <xlnt/writer/excel_writer.hpp>
|
||||||
#include <xlnt/reader/excel_reader.hpp>
|
#include <xlnt/reader/excel_reader.hpp>
|
||||||
|
|
||||||
|
#include <xlnt/common/xml_tree.hpp>
|
||||||
|
|
||||||
class test_cell : public CxxTest::TestSuite
|
class test_cell : public CxxTest::TestSuite
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -33,6 +35,13 @@ public:
|
||||||
wb_guess_types.set_guess_types(true);
|
wb_guess_types.set_guess_types(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_debug()
|
||||||
|
{
|
||||||
|
auto wb = xlnt::excel_reader::load_workbook("/Users/thomas/Development/xlnt/samples/formatting.xlsx");
|
||||||
|
wb.save("/Users/thomas/Development/xlnt/samples/formatting-rt.xlsx");
|
||||||
|
wb.save("/Users/thomas/Development/xlnt/samples/formatting-rt.zip");
|
||||||
|
}
|
||||||
|
|
||||||
void test_infer_numeric()
|
void test_infer_numeric()
|
||||||
{
|
{
|
||||||
auto ws = wb_guess_types.create_sheet();
|
auto ws = wb_guess_types.create_sheet();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user