Skip to content

Commit 5778fac

Browse files
committed
fix XLSX
1 parent 2107877 commit 5778fac

5 files changed

Lines changed: 191 additions & 571 deletions

File tree

src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp

Lines changed: 117 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#include <odr/internal/abstract/document_element.hpp>
88
#include <odr/internal/abstract/filesystem.hpp>
99
#include <odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.hpp>
10-
#include <odr/internal/util/string_util.hpp>
1110
#include <odr/internal/util/xml_util.hpp>
1211

1312
#include <utility>
@@ -16,7 +15,8 @@ namespace odr::internal::ooxml::spreadsheet {
1615

1716
namespace {
1817
std::unique_ptr<abstract::ElementAdapter>
19-
create_element_adapter(const Document &document, ElementRegistry &registry);
18+
create_element_adapter(const Document &document, ElementRegistry &registry,
19+
StyleRegistry &style_registry);
2020
}
2121

2222
Document::Document(std::shared_ptr<abstract::ReadableFilesystem> files)
@@ -56,7 +56,8 @@ Document::Document(std::shared_ptr<abstract::ReadableFilesystem> files)
5656
m_root_element = parse_tree(m_element_registry, parse_context,
5757
workbook_xml.document_element());
5858

59-
m_element_adapter = create_element_adapter(*this, m_element_registry);
59+
m_element_adapter =
60+
create_element_adapter(*this, m_element_registry, m_style_registry);
6061
}
6162

6263
const ElementRegistry &Document::element_registry() const {
@@ -104,8 +105,10 @@ class ElementAdapter final : public abstract::ElementAdapter,
104105
public abstract::FrameAdapter,
105106
public abstract::ImageAdapter {
106107
public:
107-
ElementAdapter(const Document &document, ElementRegistry &registry)
108-
: m_document(&document), m_registry(&registry) {}
108+
ElementAdapter(const Document &document, ElementRegistry &registry,
109+
StyleRegistry &style_registry)
110+
: m_document(&document), m_registry(&registry),
111+
m_style_registry(&style_registry) {}
109112

110113
[[nodiscard]] ElementType
111114
element_type(const ElementIdentifier element_id) const override {
@@ -313,33 +316,45 @@ class ElementAdapter final : public abstract::ElementAdapter,
313316

314317
[[nodiscard]] std::string
315318
sheet_name(const ElementIdentifier element_id) const override {
316-
(void)element_id;
317-
return {}; // TODO
319+
return get_node(element_id).attribute("name").value();
318320
}
319321
[[nodiscard]] TableDimensions
320322
sheet_dimensions(const ElementIdentifier element_id) const override {
321-
(void)element_id;
322-
return {}; // TODO
323+
if (const ElementRegistry::Sheet *element =
324+
m_registry->sheet_element(element_id);
325+
element != nullptr) {
326+
return element->dimensions;
327+
}
328+
return {};
323329
}
324330
[[nodiscard]] TableDimensions
325331
sheet_content(const ElementIdentifier element_id,
326332
const std::optional<TableDimensions> range) const override {
327-
(void)element_id;
328333
(void)range;
329-
return {}; // TODO
334+
return sheet_dimensions(element_id); // TODO
330335
}
331336
[[nodiscard]] ElementIdentifier
332337
sheet_cell(const ElementIdentifier element_id, const std::uint32_t column,
333338
const std::uint32_t row) const override {
334-
(void)element_id;
335-
(void)column;
336-
(void)row;
337-
return {}; // TODO
339+
if (const ElementRegistry::Sheet *sheet_element =
340+
m_registry->sheet_element(element_id);
341+
sheet_element != nullptr) {
342+
if (const ElementRegistry::Sheet::Cell *cell =
343+
sheet_element->cell(column, row);
344+
cell != nullptr) {
345+
return cell->element_id;
346+
}
347+
}
348+
return null_element_id;
338349
}
339350
[[nodiscard]] ElementIdentifier
340351
sheet_first_shape(const ElementIdentifier element_id) const override {
341-
(void)element_id;
342-
return {}; // TODO
352+
if (const ElementRegistry::Sheet *sheet_element =
353+
m_registry->sheet_element(element_id);
354+
sheet_element != nullptr) {
355+
return sheet_element->first_shape_id;
356+
}
357+
return null_element_id;
343358
}
344359
[[nodiscard]] TableStyle
345360
sheet_style(const ElementIdentifier element_id) const override {
@@ -349,46 +364,73 @@ class ElementAdapter final : public abstract::ElementAdapter,
349364
[[nodiscard]] TableColumnStyle
350365
sheet_column_style(const ElementIdentifier element_id,
351366
const std::uint32_t column) const override {
352-
(void)element_id;
353-
(void)column;
354-
return {}; // TODO
367+
TableColumnStyle result;
368+
if (const ElementRegistry::Sheet *sheet_element =
369+
m_registry->sheet_element(element_id);
370+
sheet_element != nullptr) {
371+
const pugi::xml_node column_node = sheet_element->column_node(column);
372+
if (const pugi::xml_attribute width = column_node.attribute("width")) {
373+
result.width = Measure(width.as_float(), DynamicUnit("ch"));
374+
}
375+
}
376+
return result;
355377
}
356378
[[nodiscard]] TableRowStyle
357379
sheet_row_style(const ElementIdentifier element_id,
358380
const std::uint32_t row) const override {
359-
(void)element_id;
360-
(void)row;
361-
return {}; // TODO
381+
TableRowStyle result;
382+
if (const ElementRegistry::Sheet *sheet_element =
383+
m_registry->sheet_element(element_id);
384+
sheet_element != nullptr) {
385+
const pugi::xml_node row_node = sheet_element->row_node(row);
386+
if (const pugi::xml_attribute height = row_node.attribute("ht")) {
387+
result.height = Measure(height.as_float(), DynamicUnit("pt"));
388+
}
389+
}
390+
return result;
362391
}
363392
[[nodiscard]] TableCellStyle
364393
sheet_cell_style(const ElementIdentifier element_id,
365394
const std::uint32_t column,
366395
const std::uint32_t row) const override {
367-
(void)element_id;
368-
(void)column;
369-
(void)row;
370-
return {}; // TODO
396+
TableCellStyle result;
397+
if (const ElementRegistry::Sheet *sheet_element =
398+
m_registry->sheet_element(element_id);
399+
sheet_element != nullptr) {
400+
if (const pugi::xml_attribute style_attr =
401+
sheet_element->cell_node(column, row).attribute("s");
402+
style_attr) {
403+
const std::uint32_t style_id = style_attr.as_uint();
404+
const ResolvedStyle style = m_style_registry->cell_style(style_id);
405+
result.override(style.table_cell_style);
406+
}
407+
}
408+
return result;
371409
}
372410

373411
[[nodiscard]] TablePosition
374412
sheet_cell_position(const ElementIdentifier element_id) const override {
375-
(void)element_id;
376-
return {}; // TODO
413+
if (const ElementRegistry::SheetCell *cell_element =
414+
m_registry->sheet_cell_element(element_id);
415+
cell_element != nullptr) {
416+
return cell_element->position;
417+
}
418+
return {};
377419
}
378420
[[nodiscard]] bool
379421
sheet_cell_is_covered(const ElementIdentifier element_id) const override {
380422
(void)element_id;
381-
return {}; // TODO
423+
return false; // TODO
382424
}
383425
[[nodiscard]] TableDimensions
384426
sheet_cell_span(const ElementIdentifier element_id) const override {
385427
(void)element_id;
386-
return {}; // TODO
428+
return {1, 1}; // TODO
387429
}
388430
[[nodiscard]] ValueType
389431
sheet_cell_value_type(const ElementIdentifier element_id) const override {
390432
(void)element_id;
391-
return {}; // TODO
433+
return ValueType::string; // TODO
392434
}
393435

394436
[[nodiscard]] TextStyle
@@ -430,64 +472,9 @@ class ElementAdapter final : public abstract::ElementAdapter,
430472
}
431473
void text_set_content(const ElementIdentifier element_id,
432474
const std::string &text) const override {
433-
ElementRegistry::Element *element = m_registry->element(element_id);
434-
ElementRegistry::Text *text_element = m_registry->text_element(element_id);
435-
if (element == nullptr || text_element == nullptr) {
436-
return;
437-
}
438-
439-
const pugi::xml_node first = get_node(element_id);
440-
const pugi::xml_node last = text_element->last;
441-
442-
pugi::xml_node parent = first.parent();
443-
const pugi::xml_node old_first = first;
444-
const pugi::xml_node old_last = last;
445-
pugi::xml_node new_first = old_first;
446-
pugi::xml_node new_last = last;
447-
448-
const auto insert_node = [&](const char *node) {
449-
const pugi::xml_node new_node =
450-
parent.insert_child_before(node, old_first);
451-
if (new_first == old_first) {
452-
new_first = new_node;
453-
}
454-
new_last = new_node;
455-
return new_node;
456-
};
457-
458-
for (const util::xml::StringToken &token : util::xml::tokenize_text(text)) {
459-
switch (token.type) {
460-
case util::xml::StringToken::Type::none:
461-
break;
462-
case util::xml::StringToken::Type::string: {
463-
auto text_node = insert_node("w:t");
464-
text_node.append_child(pugi::xml_node_type::node_pcdata)
465-
.text()
466-
.set(token.string.c_str());
467-
} break;
468-
case util::xml::StringToken::Type::spaces: {
469-
auto text_node = insert_node("w:t");
470-
text_node.append_attribute("xml:space").set_value("preserve");
471-
text_node.append_child(pugi::xml_node_type::node_pcdata)
472-
.text()
473-
.set(token.string.c_str());
474-
} break;
475-
case util::xml::StringToken::Type::tabs: {
476-
for (std::size_t i = 0; i < token.string.size(); ++i) {
477-
insert_node("w:tab");
478-
}
479-
} break;
480-
}
481-
}
482-
483-
element->node = new_first;
484-
text_element->last = new_last;
485-
486-
for (pugi::xml_node node = old_first; node != old_last.next_sibling();) {
487-
const pugi::xml_node next = node.next_sibling();
488-
parent.remove_child(node);
489-
node = next;
490-
}
475+
(void)element_id;
476+
(void)text;
477+
// TODO
491478
}
492479
[[nodiscard]] TextStyle
493480
text_style(const ElementIdentifier element_id) const override {
@@ -502,37 +489,56 @@ class ElementAdapter final : public abstract::ElementAdapter,
502489

503490
[[nodiscard]] AnchorType
504491
frame_anchor_type(const ElementIdentifier element_id) const override {
505-
const pugi::xml_node node = get_node(element_id);
506-
507-
if (node.child("wp:inline")) {
508-
return AnchorType::as_char;
509-
}
510-
return AnchorType::as_char; // TODO default?
492+
return AnchorType::at_page;
511493
}
512494
[[nodiscard]] std::optional<std::string>
513495
frame_x(const ElementIdentifier element_id) const override {
514-
(void)element_id;
515-
return std::nullopt;
496+
if (const std::optional<Measure> x =
497+
read_emus_attribute(get_node(element_id)
498+
.child("xdr:pic")
499+
.child("xdr:spPr")
500+
.child("a:xfrm")
501+
.child("a:off")
502+
.attribute("x"))) {
503+
return x->to_string();
504+
}
505+
return {};
516506
}
517507
[[nodiscard]] std::optional<std::string>
518508
frame_y(const ElementIdentifier element_id) const override {
519-
(void)element_id;
520-
return std::nullopt;
509+
if (const std::optional<Measure> y =
510+
read_emus_attribute(get_node(element_id)
511+
.child("xdr:pic")
512+
.child("xdr:spPr")
513+
.child("a:xfrm")
514+
.child("a:off")
515+
.attribute("y"))) {
516+
return y->to_string();
517+
}
518+
return {};
521519
}
522520
[[nodiscard]] std::optional<std::string>
523521
frame_width(const ElementIdentifier element_id) const override {
524-
const pugi::xml_node inner_node = get_frame_inner_node(element_id);
525-
if (const std::optional<Measure> width = read_emus_attribute(
526-
inner_node.child("wp:extent").attribute("cx"))) {
522+
if (const std::optional<Measure> width =
523+
read_emus_attribute(get_node(element_id)
524+
.child("xdr:pic")
525+
.child("xdr:spPr")
526+
.child("a:xfrm")
527+
.child("a:ext")
528+
.attribute("cx"))) {
527529
return width->to_string();
528530
}
529531
return {};
530532
}
531533
[[nodiscard]] std::optional<std::string>
532534
frame_height(const ElementIdentifier element_id) const override {
533-
const pugi::xml_node inner_node = get_frame_inner_node(element_id);
534-
if (const std::optional<Measure> height = read_emus_attribute(
535-
inner_node.child("wp:extent").attribute("cy"))) {
535+
if (const std::optional<Measure> height =
536+
read_emus_attribute(get_node(element_id)
537+
.child("xdr:pic")
538+
.child("xdr:spPr")
539+
.child("a:xfrm")
540+
.child("a:ext")
541+
.attribute("cy"))) {
536542
return height->to_string();
537543
}
538544
return {};
@@ -577,6 +583,7 @@ class ElementAdapter final : public abstract::ElementAdapter,
577583
private:
578584
const Document *m_document{nullptr};
579585
ElementRegistry *m_registry{nullptr};
586+
StyleRegistry *m_style_registry{nullptr};
580587

581588
[[nodiscard]] pugi::xml_node
582589
get_node(const ElementIdentifier element_id) const {
@@ -588,42 +595,14 @@ class ElementAdapter final : public abstract::ElementAdapter,
588595
return {};
589596
}
590597

591-
[[nodiscard]] pugi::xml_node
592-
get_frame_inner_node(const ElementIdentifier element_id) const {
593-
const pugi::xml_node node = get_node(element_id);
594-
if (const pugi::xml_node anchor = node.child("wp:anchor")) {
595-
return anchor;
596-
}
597-
if (const pugi::xml_node inline_node = node.child("wp:inline")) {
598-
return inline_node;
599-
}
600-
return {};
601-
}
602-
603598
[[nodiscard]] static std::string get_text(const pugi::xml_node node) {
604-
const std::string name = node.name();
605-
606-
if (name == "w:t") {
599+
if (const std::string name = node.name(); name == "t" || name == "v") {
607600
return node.text().get();
608601
}
609-
if (name == "w:tab") {
610-
return "\t";
611-
}
612602

613603
return "";
614604
}
615605

616-
[[nodiscard]] const char *
617-
get_style_name(const ElementIdentifier element_id) const {
618-
const pugi::xml_node node = get_node(element_id);
619-
for (pugi::xml_attribute attribute : node.attributes()) {
620-
if (util::string::ends_with(attribute.name(), ":style-name")) {
621-
return attribute.value();
622-
}
623-
}
624-
return {};
625-
}
626-
627606
[[nodiscard]] ResolvedStyle
628607
get_partial_style(const ElementIdentifier element_id) const {
629608
if (const ElementType type = element_type(element_id);
@@ -655,8 +634,9 @@ class ElementAdapter final : public abstract::ElementAdapter,
655634
};
656635

657636
std::unique_ptr<abstract::ElementAdapter>
658-
create_element_adapter(const Document &document, ElementRegistry &registry) {
659-
return std::make_unique<ElementAdapter>(document, registry);
637+
create_element_adapter(const Document &document, ElementRegistry &registry,
638+
StyleRegistry &style_registry) {
639+
return std::make_unique<ElementAdapter>(document, registry, style_registry);
660640
}
661641

662642
} // namespace

0 commit comments

Comments
 (0)