-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Expand file tree
/
Copy pathxlsxtomd.cpp
More file actions
170 lines (142 loc) · 5 KB
/
Copy pathxlsxtomd.cpp
File metadata and controls
170 lines (142 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include "xlsxtomd.h"
#include <xlsxabstractsheet.h>
#include <xlsxcell.h>
#include <xlsxcellrange.h>
#include <xlsxdocument.h>
#include <xlsxformat.h>
#include <xlsxworksheet.h>
#include <QChar>
#include <QDateTime>
#include <QDebug>
#include <QLatin1StringView>
#include <QList>
#include <QRegularExpression>
#include <QString>
#include <QStringList> // IWYU pragma: keep
#include <QStringView>
#include <QVariant>
#include <QtLogging>
#include <memory>
using namespace Qt::Literals::StringLiterals;
static QString formatCellText(const QXlsx::Cell *cell)
{
if (!cell) return QString();
QVariant value = cell->value();
QXlsx::Format format = cell->format();
QString cellText;
// Determine the cell type based on format
if (cell->isDateTime()) {
// Handle DateTime
QDateTime dateTime = cell->dateTime().toDateTime();
cellText = dateTime.isValid() ? dateTime.toString(QStringView(u"yyyy-MM-dd")) : value.toString();
} else {
cellText = value.toString();
}
if (cellText.isEmpty())
return QString();
// Escape special characters
static QRegularExpression special(
QStringLiteral(
R"(()([\\`*_[\]<>()!|])|)" // special characters
R"(^(\s*)(#+(?:\s|$))|)" // headings
R"(^(\s*[0-9])(\.(?:\s|$))|)" // ordered lists ("1. a")
R"(^(\s*)([+-](?:\s|$)))" // unordered lists ("- a")
),
QRegularExpression::MultilineOption
);
cellText.replace(special, uR"(\1\\2)"_s);
cellText.replace(u'&', "&"_L1);
cellText.replace(u'<', "<"_L1);
cellText.replace(u'>', ">"_L1);
// Apply Markdown formatting based on font styles
if (format.fontUnderline())
cellText = u"_%1_"_s.arg(cellText);
if (format.fontBold())
cellText = u"**%1**"_s.arg(cellText);
if (format.fontItalic())
cellText = u"*%1*"_s.arg(cellText);
if (format.fontStrikeOut())
cellText = u"~~%1~~"_s.arg(cellText);
return cellText;
}
static QString getCellValue(QXlsx::Worksheet *sheet, int row, int col)
{
if (!sheet)
return QString();
// Attempt to retrieve the cell directly
std::shared_ptr<QXlsx::Cell> cell = sheet->cellAt(row, col);
// If the cell is part of a merged range and not directly available
if (!cell) {
for (const QXlsx::CellRange &range : sheet->mergedCells()) {
if (row >= range.firstRow() && row <= range.lastRow() &&
col >= range.firstColumn() && col <= range.lastColumn()) {
cell = sheet->cellAt(range.firstRow(), range.firstColumn());
break;
}
}
}
// Format and return the cell text if available
if (cell)
return formatCellText(cell.get());
// Return empty string if cell is not found
return QString();
}
QString XLSXToMD::toMarkdown(QIODevice *xlsxDevice)
{
// Load the Excel document
QXlsx::Document xlsx(xlsxDevice);
if (!xlsx.load()) {
qCritical() << "Failed to load the Excel from device";
return QString();
}
QString markdown;
// Retrieve all sheet names
QStringList sheetNames = xlsx.sheetNames();
if (sheetNames.isEmpty()) {
qWarning() << "No sheets found in the Excel document.";
return QString();
}
// Iterate through each worksheet by name
for (const QString &sheetName : sheetNames) {
QXlsx::Worksheet *sheet = dynamic_cast<QXlsx::Worksheet *>(xlsx.sheet(sheetName));
if (!sheet) {
qWarning() << "Failed to load sheet:" << sheetName;
continue;
}
markdown += u"### %1\n\n"_s.arg(sheetName);
// Determine the used range
QXlsx::CellRange range = sheet->dimension();
int firstRow = range.firstRow();
int lastRow = range.lastRow();
int firstCol = range.firstColumn();
int lastCol = range.lastColumn();
if (firstRow > lastRow || firstCol > lastCol) {
qWarning() << "Sheet" << sheetName << "is empty.";
markdown += QStringView(u"*No data available.*\n\n");
continue;
}
auto appendRow = [&markdown](auto &list) { markdown += u"|%1|\n"_s.arg(list.join(u'|')); };
// Empty header
static QString header(u' ');
static QString separator(u'-');
QStringList headers;
QStringList separators;
for (int col = firstCol; col <= lastCol; ++col) {
headers << header;
separators << separator;
}
appendRow(headers);
appendRow(separators);
// Iterate through data rows
for (int row = firstRow; row <= lastRow; ++row) {
QStringList rowData;
for (int col = firstCol; col <= lastCol; ++col) {
QString cellText = getCellValue(sheet, row, col);
rowData << (cellText.isEmpty() ? u" "_s : cellText);
}
appendRow(rowData);
}
markdown += u'\n'; // Add an empty line between sheets
}
return markdown;
}