diff --git a/include/xlnt/workbook/streaming_workbook_reader.hpp b/include/xlnt/workbook/streaming_workbook_reader.hpp
index 1e98f1ac..7bd56e54 100644
--- a/include/xlnt/workbook/streaming_workbook_reader.hpp
+++ b/include/xlnt/workbook/streaming_workbook_reader.hpp
@@ -58,12 +58,16 @@ public:
///
void close();
+ bool has_cell();
+
///
/// Reads the next cell in the current worksheet and optionally returns it if
/// the last cell in the sheet has not yet been read.
///
cell read_cell();
+ bool has_worksheet();
+
///
/// Beings reading of the next worksheet in the workbook and optionally
/// returns its title if the last worksheet has not yet been read.
diff --git a/source/detail/serialization/xlsx_consumer.cpp b/source/detail/serialization/xlsx_consumer.cpp
index 89161fd7..933e28e2 100644
--- a/source/detail/serialization/xlsx_consumer.cpp
+++ b/source/detail/serialization/xlsx_consumer.cpp
@@ -129,7 +129,8 @@ namespace detail {
xlsx_consumer::xlsx_consumer(workbook &target)
: target_(target),
- parser_(nullptr)
+ parser_(nullptr),
+ stream_cell_(nullptr)
{
}
@@ -150,9 +151,252 @@ cell xlsx_consumer::read_cell()
return cell(nullptr);
}
-std::string xlsx_consumer::begin_worksheet()
+std::string xlsx_consumer::read_worksheet_begin()
{
- return "";
+ if (worksheet_queue_.empty())
+ {
+ return "";
+ }
+
+ const auto back = worksheet_queue_.back();
+ const auto rel_id = back.id();
+ worksheet_queue_.pop_back();
+
+ auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
+ target_.d_->sheet_title_rel_id_map_.end(),
+ [&](const std::pair &p) {
+ return p.second == rel_id;
+ })->first;
+
+ auto id = sheet_title_id_map_[title];
+ auto index = sheet_title_index_map_[title];
+
+ auto insertion_iter = target_.d_->worksheets_.begin();
+ while (insertion_iter != target_.d_->worksheets_.end() && sheet_title_index_map_[insertion_iter->title_] < index)
+ {
+ ++insertion_iter;
+ }
+
+ target_.d_->worksheets_.emplace(insertion_iter, &target_, id, title);
+
+ auto ws = target_.sheet_by_id(id);
+
+ expect_start_element(qn("spreadsheetml", "worksheet"), xml::content::complex); // CT_Worksheet
+ skip_attributes({ qn("mc", "Ignorable") });
+ read_namespaces();
+
+ xlnt::range_reference full_range;
+ auto &manifest = target_.manifest();
+
+ const auto workbook_rel = manifest.relationship(path("/"), relationship_type::office_document);
+ const auto sheet_rel = manifest.relationship(workbook_rel.target().path(), rel_id);
+ path sheet_path(sheet_rel.source().path().parent().append(sheet_rel.target().path()));
+ auto hyperlinks = manifest.relationships(sheet_path, xlnt::relationship_type::hyperlink);
+
+ while (in_element(qn("spreadsheetml", "worksheet")))
+ {
+ auto current_worksheet_element = expect_start_element(xml::content::complex);
+
+ if (current_worksheet_element == qn("spreadsheetml", "sheetPr")) // CT_SheetPr 0-1
+ {
+ while (in_element(current_worksheet_element))
+ {
+ auto sheet_pr_child_element = expect_start_element(xml::content::simple);
+
+ if (sheet_pr_child_element == qn("spreadsheetml", "tabColor")) // CT_Color 0-1
+ {
+ read_color();
+ }
+ else if (sheet_pr_child_element == qn("spreadsheetml", "outlinePr")) // CT_OutlinePr 0-1
+ {
+ skip_attribute("applyStyles"); // optional, boolean, false
+ skip_attribute("summaryBelow"); // optional, boolean, true
+ skip_attribute("summaryRight"); // optional, boolean, true
+ skip_attribute("showOutlineSymbols"); // optional, boolean, true
+ }
+ else if (sheet_pr_child_element == qn("spreadsheetml", "pageSetUpPr")) // CT_PageSetUpPr 0-1
+ {
+ skip_attribute("autoPageBreaks"); // optional, boolean, true
+ skip_attribute("fitToPage"); // optional, boolean, false
+ }
+ else
+ {
+ unexpected_element(sheet_pr_child_element);
+ }
+
+ expect_end_element(sheet_pr_child_element);
+ }
+
+ skip_attribute("syncHorizontal"); // optional, boolean, false
+ skip_attribute("syncVertical"); // optional, boolean, false
+ skip_attribute("syncRef"); // optional, ST_Ref, false
+ skip_attribute("transitionEvaluation"); // optional, boolean, false
+ skip_attribute("transitionEntry"); // optional, boolean, false
+ skip_attribute("published"); // optional, boolean, true
+ skip_attribute("codeName"); // optional, string
+ skip_attribute("filterMode"); // optional, boolean, false
+ skip_attribute("enableFormatConditionsCalculation"); // optional, boolean, true
+ }
+ else if (current_worksheet_element == qn("spreadsheetml", "dimension")) // CT_SheetDimension 0-1
+ {
+ full_range = xlnt::range_reference(parser().attribute("ref"));
+ }
+ else if (current_worksheet_element == qn("spreadsheetml", "sheetViews")) // CT_SheetViews 0-1
+ {
+ while (in_element(current_worksheet_element))
+ {
+ expect_start_element(qn("spreadsheetml", "sheetView"), xml::content::complex); // CT_SheetView 1+
+
+ sheet_view new_view;
+ new_view.id(parser().attribute("workbookViewId"));
+
+ if (parser().attribute_present("showGridLines")) // default="true"
+ {
+ new_view.show_grid_lines(is_true(parser().attribute("showGridLines")));
+ }
+
+ if (parser().attribute_present("defaultGridColor")) // default="true"
+ {
+ new_view.default_grid_color(is_true(parser().attribute("defaultGridColor")));
+ }
+
+ if (parser().attribute_present("view") && parser().attribute("view") != "normal")
+ {
+ new_view.type(parser().attribute("view") == "pageBreakPreview" ? sheet_view_type::page_break_preview
+ : sheet_view_type::page_layout);
+ }
+
+ skip_attributes({ "windowProtection", "showFormulas", "showRowColHeaders", "showZeros", "rightToLeft",
+ "tabSelected", "showRuler", "showOutlineSymbols", "showWhiteSpace", "view", "topLeftCell",
+ "colorId", "zoomScale", "zoomScaleNormal", "zoomScaleSheetLayoutView", "zoomScalePageLayoutView" });
+
+ while (in_element(qn("spreadsheetml", "sheetView")))
+ {
+ auto sheet_view_child_element = expect_start_element(xml::content::simple);
+
+ if (sheet_view_child_element == qn("spreadsheetml", "pane")) // CT_Pane 0-1
+ {
+ pane new_pane;
+
+ if (parser().attribute_present("topLeftCell"))
+ {
+ new_pane.top_left_cell = cell_reference(parser().attribute("topLeftCell"));
+ }
+
+ if (parser().attribute_present("xSplit"))
+ {
+ new_pane.x_split = parser().attribute("xSplit");
+ }
+
+ if (parser().attribute_present("ySplit"))
+ {
+ new_pane.y_split = parser().attribute("ySplit");
+ }
+
+ if (parser().attribute_present("activePane"))
+ {
+ new_pane.active_pane = parser().attribute("activePane");
+ }
+
+ if (parser().attribute_present("state"))
+ {
+ new_pane.state = parser().attribute("state");
+ }
+
+ new_view.pane(new_pane);
+ }
+ else if (sheet_view_child_element == qn("spreadsheetml", "selection")) // CT_Selection 0-4
+ {
+ skip_remaining_content(sheet_view_child_element);
+ }
+ else if (sheet_view_child_element == qn("spreadsheetml", "pivotSelection")) // CT_PivotSelection 0-4
+ {
+ skip_remaining_content(sheet_view_child_element);
+ }
+ else if (sheet_view_child_element == qn("spreadsheetml", "extLst")) // CT_ExtensionList 0-1
+ {
+ skip_remaining_content(sheet_view_child_element);
+ }
+ else
+ {
+ unexpected_element(sheet_view_child_element);
+ }
+
+ expect_end_element(sheet_view_child_element);
+ }
+
+ expect_end_element(qn("spreadsheetml", "sheetView"));
+
+ ws.d_->views_.push_back(new_view);
+ }
+ }
+ else if (current_worksheet_element == qn("spreadsheetml", "sheetFormatPr")) // CT_SheetFormatPr 0-1
+ {
+ skip_remaining_content(current_worksheet_element);
+ }
+ else if (current_worksheet_element == qn("spreadsheetml", "cols")) // CT_Cols 0+
+ {
+ while (in_element(qn("spreadsheetml", "cols")))
+ {
+ expect_start_element(qn("spreadsheetml", "col"), xml::content::simple);
+
+ skip_attributes({ "bestFit", "collapsed", "outlineLevel" });
+
+ auto min = static_cast(std::stoull(parser().attribute("min")));
+ auto max = static_cast(std::stoull(parser().attribute("max")));
+
+ optional width;
+
+ if (parser().attribute_present("width"))
+ {
+ width = parser().attribute("width");
+ }
+
+ optional column_style;
+
+ if (parser().attribute_present("style"))
+ {
+ column_style = parser().attribute("style");
+ }
+
+ auto custom =
+ parser().attribute_present("customWidth") ? is_true(parser().attribute("customWidth")) : false;
+ auto hidden = parser().attribute_present("hidden") ? is_true(parser().attribute("hidden")) : false;
+
+ expect_end_element(qn("spreadsheetml", "col"));
+
+ for (auto column = min; column <= max; column++)
+ {
+ column_properties props;
+
+ if (width.is_set())
+ {
+ props.width = width.get();
+ }
+
+ if (column_style.is_set())
+ {
+ props.style = column_style.get();
+ }
+
+ props.hidden = hidden;
+ props.custom_width = custom;
+ ws.add_column_properties(column, props);
+ }
+ }
+ }
+ else if (current_worksheet_element == qn("spreadsheetml", "sheetData")) // CT_SheetData 1
+ {
+ in_sheet_data_ = true;
+ }
+ }
+
+ if (!in_sheet_data_)
+ {
+ read_worksheet_end();
+ }
+
+ return title;
}
worksheet xlsx_consumer::end_worksheet()
@@ -165,6 +409,16 @@ xml::parser &xlsx_consumer::parser()
return *parser_;
}
+bool xlsx_consumer::has_cell()
+{
+ return stream_cell_ != nullptr;
+}
+
+bool xlsx_consumer::has_worksheet()
+{
+ return !worksheet_queue_.empty();
+}
+
std::vector xlsx_consumer::read_relationships(const path &part)
{
const auto part_rels_path = part.parent().append("_rels")
@@ -1434,238 +1688,17 @@ void xlsx_consumer::read_volatile_dependencies()
}
// CT_Worksheet
-void xlsx_consumer::read_worksheet(const std::string &rel_id)
+void xlsx_consumer::read_worksheet_end()
{
-/*
- static const auto &xmlns = constants::namespace_("spreadsheetml");
- static const auto &xmlns_mc = constants::namespace_("mc");
- static const auto &xmlns_x14ac = constants::namespace_("x14ac");
- static const auto &xmlns_r = constants::namespace_("r");
-*/
- auto title = std::find_if(target_.d_->sheet_title_rel_id_map_.begin(),
- target_.d_->sheet_title_rel_id_map_.end(),
- [&](const std::pair &p) {
- return p.second == rel_id;
- })->first;
-
- auto id = sheet_title_id_map_[title];
- auto index = sheet_title_index_map_[title];
-
- auto insertion_iter = target_.d_->worksheets_.begin();
- while (insertion_iter != target_.d_->worksheets_.end() && sheet_title_index_map_[insertion_iter->title_] < index)
- {
- ++insertion_iter;
- }
-
- target_.d_->worksheets_.emplace(insertion_iter, &target_, id, title);
-
- auto ws = target_.sheet_by_id(id);
-
- expect_start_element(qn("spreadsheetml", "worksheet"), xml::content::complex); // CT_Worksheet
- skip_attributes({qn("mc", "Ignorable")});
- read_namespaces();
-
- xlnt::range_reference full_range;
- auto &manifest = target_.manifest();
-
- const auto workbook_rel = manifest.relationship(path("/"), relationship_type::office_document);
- const auto sheet_rel = manifest.relationship(workbook_rel.target().path(), rel_id);
- path sheet_path(sheet_rel.source().path().parent().append(sheet_rel.target().path()));
- auto hyperlinks = manifest.relationships(sheet_path, xlnt::relationship_type::hyperlink);
+ in_sheet_data_ = false;
+ auto ws = worksheet(stream_worksheet_);
+ std::vector hyperlinks;
while (in_element(qn("spreadsheetml", "worksheet")))
{
auto current_worksheet_element = expect_start_element(xml::content::complex);
- if (current_worksheet_element == qn("spreadsheetml", "sheetPr")) // CT_SheetPr 0-1
- {
- while (in_element(current_worksheet_element))
- {
- auto sheet_pr_child_element = expect_start_element(xml::content::simple);
-
- if (sheet_pr_child_element == qn("spreadsheetml", "tabColor")) // CT_Color 0-1
- {
- read_color();
- }
- else if (sheet_pr_child_element == qn("spreadsheetml", "outlinePr")) // CT_OutlinePr 0-1
- {
- skip_attribute("applyStyles"); // optional, boolean, false
- skip_attribute("summaryBelow"); // optional, boolean, true
- skip_attribute("summaryRight"); // optional, boolean, true
- skip_attribute("showOutlineSymbols"); // optional, boolean, true
- }
- else if (sheet_pr_child_element == qn("spreadsheetml", "pageSetUpPr")) // CT_PageSetUpPr 0-1
- {
- skip_attribute("autoPageBreaks"); // optional, boolean, true
- skip_attribute("fitToPage"); // optional, boolean, false
- }
- else
- {
- unexpected_element(sheet_pr_child_element);
- }
-
- expect_end_element(sheet_pr_child_element);
- }
-
- skip_attribute("syncHorizontal"); // optional, boolean, false
- skip_attribute("syncVertical"); // optional, boolean, false
- skip_attribute("syncRef"); // optional, ST_Ref, false
- skip_attribute("transitionEvaluation"); // optional, boolean, false
- skip_attribute("transitionEntry"); // optional, boolean, false
- skip_attribute("published"); // optional, boolean, true
- skip_attribute("codeName"); // optional, string
- skip_attribute("filterMode"); // optional, boolean, false
- skip_attribute("enableFormatConditionsCalculation"); // optional, boolean, true
- }
- else if (current_worksheet_element == qn("spreadsheetml", "dimension")) // CT_SheetDimension 0-1
- {
- full_range = xlnt::range_reference(parser().attribute("ref"));
- }
- else if (current_worksheet_element == qn("spreadsheetml", "sheetViews")) // CT_SheetViews 0-1
- {
- while (in_element(current_worksheet_element))
- {
- expect_start_element(qn("spreadsheetml", "sheetView"), xml::content::complex); // CT_SheetView 1+
-
- sheet_view new_view;
- new_view.id(parser().attribute("workbookViewId"));
-
- if (parser().attribute_present("showGridLines")) // default="true"
- {
- new_view.show_grid_lines(is_true(parser().attribute("showGridLines")));
- }
-
- if (parser().attribute_present("defaultGridColor")) // default="true"
- {
- new_view.default_grid_color(is_true(parser().attribute("defaultGridColor")));
- }
-
- if (parser().attribute_present("view") && parser().attribute("view") != "normal")
- {
- new_view.type(parser().attribute("view") == "pageBreakPreview" ? sheet_view_type::page_break_preview
- : sheet_view_type::page_layout);
- }
-
- skip_attributes({"windowProtection", "showFormulas", "showRowColHeaders", "showZeros", "rightToLeft",
- "tabSelected", "showRuler", "showOutlineSymbols", "showWhiteSpace", "view", "topLeftCell",
- "colorId", "zoomScale", "zoomScaleNormal", "zoomScaleSheetLayoutView", "zoomScalePageLayoutView"});
-
- while (in_element(qn("spreadsheetml", "sheetView")))
- {
- auto sheet_view_child_element = expect_start_element(xml::content::simple);
-
- if (sheet_view_child_element == qn("spreadsheetml", "pane")) // CT_Pane 0-1
- {
- pane new_pane;
-
- if (parser().attribute_present("topLeftCell"))
- {
- new_pane.top_left_cell = cell_reference(parser().attribute("topLeftCell"));
- }
-
- if (parser().attribute_present("xSplit"))
- {
- new_pane.x_split = parser().attribute("xSplit");
- }
-
- if (parser().attribute_present("ySplit"))
- {
- new_pane.y_split = parser().attribute("ySplit");
- }
-
- if (parser().attribute_present("activePane"))
- {
- new_pane.active_pane = parser().attribute("activePane");
- }
-
- if (parser().attribute_present("state"))
- {
- new_pane.state = parser().attribute("state");
- }
-
- new_view.pane(new_pane);
- }
- else if (sheet_view_child_element == qn("spreadsheetml", "selection")) // CT_Selection 0-4
- {
- skip_remaining_content(sheet_view_child_element);
- }
- else if (sheet_view_child_element == qn("spreadsheetml", "pivotSelection")) // CT_PivotSelection 0-4
- {
- skip_remaining_content(sheet_view_child_element);
- }
- else if (sheet_view_child_element == qn("spreadsheetml", "extLst")) // CT_ExtensionList 0-1
- {
- skip_remaining_content(sheet_view_child_element);
- }
- else
- {
- unexpected_element(sheet_view_child_element);
- }
-
- expect_end_element(sheet_view_child_element);
- }
-
- expect_end_element(qn("spreadsheetml", "sheetView"));
-
- ws.d_->views_.push_back(new_view);
- }
- }
- else if (current_worksheet_element == qn("spreadsheetml", "sheetFormatPr")) // CT_SheetFormatPr 0-1
- {
- skip_remaining_content(current_worksheet_element);
- }
- else if (current_worksheet_element == qn("spreadsheetml", "cols")) // CT_Cols 0+
- {
- while (in_element(qn("spreadsheetml", "cols")))
- {
- expect_start_element(qn("spreadsheetml", "col"), xml::content::simple);
-
- skip_attributes({"bestFit", "collapsed", "outlineLevel"});
-
- auto min = static_cast(std::stoull(parser().attribute("min")));
- auto max = static_cast(std::stoull(parser().attribute("max")));
-
- optional width;
-
- if (parser().attribute_present("width"))
- {
- width = parser().attribute("width");
- }
-
- optional column_style;
-
- if (parser().attribute_present("style"))
- {
- column_style = parser().attribute("style");
- }
-
- auto custom =
- parser().attribute_present("customWidth") ? is_true(parser().attribute("customWidth")) : false;
- auto hidden = parser().attribute_present("hidden") ? is_true(parser().attribute("hidden")) : false;
-
- expect_end_element(qn("spreadsheetml", "col"));
-
- for (auto column = min; column <= max; column++)
- {
- column_properties props;
-
- if (width.is_set())
- {
- props.width = width.get();
- }
-
- if (column_style.is_set())
- {
- props.style = column_style.get();
- }
-
- props.hidden = hidden;
- props.custom_width = custom;
- ws.add_column_properties(column, props);
- }
- }
- }
- else if (current_worksheet_element == qn("spreadsheetml", "sheetData")) // CT_SheetData 1
+ if (current_worksheet_element == qn("spreadsheetml", "sheetData")) // CT_SheetData 1
{
while (in_element(qn("spreadsheetml", "sheetData")))
{
@@ -2089,10 +2122,15 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
expect_end_element(qn("spreadsheetml", "worksheet"));
+ auto &manifest = target_.manifest();
+
+ xlnt::path sheet_path;
+ relationship workbook_rel, sheet_rel;
+
if (manifest.has_relationship(sheet_path, xlnt::relationship_type::comments))
{
- auto comments_part = manifest.canonicalize(
- {workbook_rel, sheet_rel, manifest.relationship(sheet_path, xlnt::relationship_type::comments)});
+ auto comments_part = manifest.canonicalize({workbook_rel, sheet_rel,
+ manifest.relationship(sheet_path, xlnt::relationship_type::comments)});
auto receive = xml::parser::receive_default;
auto comments_part_streambuf = archive_->open(comments_part);
@@ -2104,8 +2142,8 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
if (manifest.has_relationship(sheet_path, xlnt::relationship_type::vml_drawing))
{
- auto vml_drawings_part = manifest.canonicalize(
- {workbook_rel, sheet_rel, manifest.relationship(sheet_path, xlnt::relationship_type::vml_drawing)});
+ auto vml_drawings_part = manifest.canonicalize({workbook_rel, sheet_rel,
+ manifest.relationship(sheet_path, xlnt::relationship_type::vml_drawing)});
auto vml_drawings_part_streambuf = archive_->open(comments_part);
std::istream vml_drawings_part_stream(comments_part_streambuf.get());
diff --git a/source/detail/serialization/xlsx_consumer.hpp b/source/detail/serialization/xlsx_consumer.hpp
index 225e5f22..c34f048a 100644
--- a/source/detail/serialization/xlsx_consumer.hpp
+++ b/source/detail/serialization/xlsx_consumer.hpp
@@ -45,6 +45,7 @@ template
class optional;
class path;
class relationship;
+class streaming_workbook_reader;
class variant;
class workbook;
class worksheet;
@@ -52,6 +53,8 @@ class worksheet;
namespace detail {
class izstream;
+struct cell_impl;
+struct worksheet_impl;
///
/// Handles writing a workbook into an XLSX file.
@@ -61,8 +64,18 @@ class xlsx_consumer
public:
xlsx_consumer(workbook &destination);
+ void read(std::istream &source);
+
+ void read(std::istream &source, const std::string &password);
+
+private:
+ friend class streaming_workbook_reader;
+
+
void open(std::istream &source);
+ bool has_cell();
+
///
/// Reads the next cell in the current worksheet and optionally returns it if
/// the last cell in the sheet has not yet been read. An exception will be thrown
@@ -70,13 +83,6 @@ public:
///
cell read_cell();
- ///
- /// Beings reading of the next worksheet in the workbook and optionally
- /// returns its title if the last worksheet has not yet been read. An
- /// exception will be thrown if this is not open as a streaming consumer.
- ///
- std::string begin_worksheet();
-
///
/// Ends reading of the current worksheet in the workbook and optionally
/// returns a worksheet object corresponding to the worksheet with the title
@@ -85,11 +91,8 @@ public:
///
worksheet end_worksheet();
- void read(std::istream &source);
+ bool has_worksheet();
- void read(std::istream &source, const std::string &password);
-
-private:
///
/// Read all the files needed from the XLSX archive and initialize all of
/// the data in the workbook to match.
@@ -208,6 +211,16 @@ private:
///
void read_worksheet(const std::string &title);
+ ///
+ /// xl/sheets/*.xml
+ ///
+ std::string read_worksheet_begin();
+
+ ///
+ /// xl/sheets/*.xml
+ ///
+ void read_worksheet_end();
+
// Sheet Relationship Target Parts
///
@@ -398,6 +411,14 @@ private:
std::vector stack_;
bool preserve_space_ = false;
+
+ std::vector worksheet_queue_;
+
+ detail::cell_impl *stream_cell_;
+
+ detail::worksheet_impl *stream_worksheet_;
+
+ bool in_sheet_data_;
};
} // namespace detail
diff --git a/source/workbook/streaming_workbook_reader.cpp b/source/workbook/streaming_workbook_reader.cpp
index 84f3d5f0..462f172d 100644
--- a/source/workbook/streaming_workbook_reader.cpp
+++ b/source/workbook/streaming_workbook_reader.cpp
@@ -32,6 +32,45 @@
#include
#include
+
+namespace {
+
+//TODO: (important) this is duplicated from workbook.cpp, find a common place to keep it
+#ifdef _MSC_VER
+void open_stream(std::ifstream &stream, const std::wstring &path)
+{
+ stream.open(path, std::ios::binary);
+}
+
+void open_stream(std::ofstream &stream, const std::wstring &path)
+{
+ stream.open(path, std::ios::binary);
+}
+
+void open_stream(std::ifstream &stream, const std::string &path)
+{
+ open_stream(stream, xlnt::path(path).wstring());
+}
+
+void open_stream(std::ofstream &stream, const std::string &path)
+{
+ open_stream(stream, xlnt::path(path).wstring());
+}
+#else
+void open_stream(std::ifstream &stream, const std::string &path)
+{
+ stream.open(path, std::ios::binary);
+}
+
+void open_stream(std::ofstream &stream, const std::string &path)
+{
+ stream.open(path, std::ios::binary);
+}
+#endif
+
+} // namespace
+
+
namespace xlnt {
streaming_workbook_reader::~streaming_workbook_reader()
@@ -41,10 +80,15 @@ streaming_workbook_reader::~streaming_workbook_reader()
void streaming_workbook_reader::close()
{
- if (consumer_)
- {
- consumer_.reset(nullptr);
- }
+ if (consumer_)
+ {
+ consumer_.reset(nullptr);
+ }
+}
+
+bool streaming_workbook_reader::has_cell()
+{
+ return consumer_->has_cell();
}
cell streaming_workbook_reader::read_cell()
@@ -52,9 +96,14 @@ cell streaming_workbook_reader::read_cell()
return consumer_->read_cell();
}
+bool streaming_workbook_reader::has_worksheet()
+{
+ return consumer_->has_worksheet();
+}
+
std::string streaming_workbook_reader::begin_worksheet()
{
- return consumer_->begin_worksheet();
+ return consumer_->read_worksheet_begin();
}
worksheet streaming_workbook_reader::end_worksheet()
@@ -71,21 +120,22 @@ void streaming_workbook_reader::open(const std::vector &data)
void streaming_workbook_reader::open(const std::string &filename)
{
- std::ifstream file_stream(filename, std::ios::binary);
- open(file_stream);
+ std::ifstream file_stream;
+ open_stream(file_stream, filename);
}
#ifdef _MSC_VER
void streaming_workbook_reader::open(const std::wstring &filename)
{
- std::ifstream file_stream(filename, std::ios::binary);
- open(file_stream);
+ std::ifstream file_stream;
+ open_stream(file_stream, filename);
}
#endif
void streaming_workbook_reader::open(const xlnt::path &filename)
{
- open(filename.string());
+ std::ifstream file_stream;
+ open_stream(file_stream, filename.string());
}
void streaming_workbook_reader::open(std::istream &stream)
diff --git a/tests/workbook/serialization_test_suite.hpp b/tests/workbook/serialization_test_suite.hpp
index aa2d6def..8449d016 100644
--- a/tests/workbook/serialization_test_suite.hpp
+++ b/tests/workbook/serialization_test_suite.hpp
@@ -31,6 +31,8 @@
#include
#include
#include
+#include
+#include
#include
class serialization_test_suite : public test_suite
@@ -461,4 +463,42 @@ public:
xlnt_assert(round_trip_matches_rw(path, password));
}
}
+
+ void test_streaming_read()
+ {
+ const auto path = path_helper::test_file("4_every_style.xlsx");
+ xlnt::streaming_workbook_reader reader;
+
+ reader.open(path);
+
+ while (reader.has_worksheet())
+ {
+ reader.begin_worksheet();
+
+ while (reader.has_cell())
+ {
+ const auto cell = reader.read_cell();
+ std::cout << cell.reference().to_string() << std::endl;
+ }
+
+ const auto ws = reader.end_worksheet();
+ }
+ }
+
+ void test_streaming_write()
+ {
+ const auto path = std::string("stream-out.xlsx");
+ xlnt::streaming_workbook_writer writer;
+
+ writer.open(path);
+
+ writer.add_sheet("stream");
+
+ auto b2 = writer.add_cell("B2");
+ b2.value("B2!");
+
+ auto c3 = writer.add_cell("C3");
+ b2.value("should not change");
+ c3.value("C3!");
+ }
};