We can read and modify existing simple .xlsx file now
This commit is contained in:
@@ -72,6 +72,7 @@ The library, the header files, and the feature file will be installed to your sy
|
|||||||
## References
|
## References
|
||||||
|
|
||||||
* https://github.com/jmcnamara/XlsxWriter
|
* https://github.com/jmcnamara/XlsxWriter
|
||||||
|
* http://openpyxl.readthedocs.org
|
||||||
* http://officeopenxml.com/anatomyofOOXML-xlsx.php
|
* http://officeopenxml.com/anatomyofOOXML-xlsx.php
|
||||||
* http://www.libxl.com
|
* http://www.libxl.com
|
||||||
* http://closedxml.codeplex.com/
|
* http://closedxml.codeplex.com/
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*!
|
||||||
|
\title Xlsx Readwrite Example
|
||||||
|
\example readwrite
|
||||||
|
\brief Open an existing xlsx file, modify and save it.
|
||||||
|
|
||||||
|
\ingroup qtxlsx
|
||||||
|
|
||||||
|
This example demonstrates how to modify an existing
|
||||||
|
.xlsx file with Qt Xlsx Library.
|
||||||
|
*/
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#include "xlsxdocument.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
//Generate a simple xlsx file at first.
|
||||||
|
QXlsx::Document xlsx;
|
||||||
|
xlsx.write("A1", "Hello Qt!");
|
||||||
|
xlsx.write("A2", 500);
|
||||||
|
xlsx.saveAs("first.xlsx");
|
||||||
|
|
||||||
|
//Read, edit, save
|
||||||
|
QXlsx::Document xlsx2("first.xlsx");
|
||||||
|
xlsx2.addWorksheet("Second");
|
||||||
|
xlsx2.write("A1", "Hello Qt again!");
|
||||||
|
xlsx2.saveAs("second.xlsx");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
TARGET = mergecells
|
||||||
|
|
||||||
|
#include(../../../src/xlsx/qtxlsx.pri)
|
||||||
|
QT += xlsx
|
||||||
|
|
||||||
|
TARGET = readwrite
|
||||||
|
CONFIG += console
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
SOURCES += main.cpp
|
||||||
@@ -4,5 +4,6 @@ SUBDIRS = hello style \
|
|||||||
image \
|
image \
|
||||||
mergecells \
|
mergecells \
|
||||||
rowcolumn \
|
rowcolumn \
|
||||||
numberformat
|
numberformat \
|
||||||
|
readwrite
|
||||||
|
|
||||||
|
|||||||
@@ -110,5 +110,6 @@
|
|||||||
\li \l{Xlsx Hello Example}
|
\li \l{Xlsx Hello Example}
|
||||||
\li \l{Xlsx Style Example}
|
\li \l{Xlsx Style Example}
|
||||||
\li \l{Xlsx DocProperties Example}
|
\li \l{Xlsx DocProperties Example}
|
||||||
|
\li \l{Xlsx Readwrite Example}
|
||||||
\endlist
|
\endlist
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "xlsxglobal.h"
|
#include "xlsxglobal.h"
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QVariant>
|
||||||
class QIODevice;
|
class QIODevice;
|
||||||
class QImage;
|
class QImage;
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
#include "xlsxpackage_p.h"
|
#include "xlsxpackage_p.h"
|
||||||
#include "xlsxworkbook.h"
|
#include "xlsxworkbook.h"
|
||||||
#include "xlsxworksheet.h"
|
#include "xlsxworksheet.h"
|
||||||
|
#include "xlsxworkbook_p.h"
|
||||||
|
#include "xlsxutility_p.h"
|
||||||
#include "xlsxcontenttypes_p.h"
|
#include "xlsxcontenttypes_p.h"
|
||||||
#include "xlsxsharedstrings_p.h"
|
#include "xlsxsharedstrings_p.h"
|
||||||
#include "xlsxdocpropscore_p.h"
|
#include "xlsxdocpropscore_p.h"
|
||||||
@@ -38,6 +40,8 @@
|
|||||||
#include "xlsxdocument.h"
|
#include "xlsxdocument.h"
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
namespace QXlsx {
|
namespace QXlsx {
|
||||||
|
|
||||||
@@ -125,17 +129,59 @@ bool Package::parsePackage(QIODevice *packageDevice)
|
|||||||
m_document->setDocumentProperty(name, props.property(name));
|
m_document->setDocumentProperty(name, props.property(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
//load workbook now
|
//load workbook now, Get the workbook file path from the root rels file
|
||||||
QList<XlsxRelationship> rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument"));
|
|
||||||
if (!rels_xl.isEmpty()) {
|
|
||||||
//Get the app property file name if it exists.
|
|
||||||
//In normal case, this should be "xl/workbook.xml"
|
//In normal case, this should be "xl/workbook.xml"
|
||||||
QString xlworkbook_Name = rels_xl[0].target;
|
QList<XlsxRelationship> rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument"));
|
||||||
|
if (rels_xl.isEmpty())
|
||||||
|
return false;
|
||||||
|
QString xlworkbook_Path = rels_xl[0].target;
|
||||||
|
QStringList xlworkbook_PathList = splitPath(xlworkbook_Path);
|
||||||
|
QString xlworkbook_Dir = xlworkbook_PathList[0];
|
||||||
|
QString xlworkbook_Name = xlworkbook_PathList[1];
|
||||||
|
QSharedPointer<Workbook> book = Workbook::loadFromXmlData(zipReader.fileData(xlworkbook_Path));
|
||||||
|
QList<QPair<QString, QString> > sheetNameIdPairList = book->d_func()->sheetNameIdPairList;
|
||||||
|
Relationships xlworkbook_Rels = Relationships::loadFromXmlData(
|
||||||
|
zipReader.fileData(xlworkbook_Dir+QStringLiteral("/_rels/")+xlworkbook_Name+QStringLiteral(".rels")));
|
||||||
|
|
||||||
//ToDo: Read the workbook here!
|
//load styles
|
||||||
|
QList<XlsxRelationship> rels_styles = xlworkbook_Rels.documentRelationships(QStringLiteral("/styles"));
|
||||||
|
if (!rels_styles.isEmpty()) {
|
||||||
|
//In normal case this should be styles.xml which in xl
|
||||||
|
//:Todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//load sharedStrings
|
||||||
|
QList<XlsxRelationship> rels_sharedStrings = xlworkbook_Rels.documentRelationships(QStringLiteral("/sharedStrings"));
|
||||||
|
if (!rels_sharedStrings.isEmpty()) {
|
||||||
|
//In normal case this should be sharedStrings.xml which in xl
|
||||||
|
QString name = rels_sharedStrings[0].target;
|
||||||
|
QString path = xlworkbook_Dir + QLatin1String("/") + name;
|
||||||
|
QSharedPointer<SharedStrings> sst= SharedStrings::loadFromXmlData(zipReader.fileData(path));
|
||||||
|
m_document->workbook()->d_ptr->sharedStrings = sst;
|
||||||
|
}
|
||||||
|
|
||||||
|
//load theme
|
||||||
|
QList<XlsxRelationship> rels_theme = xlworkbook_Rels.documentRelationships(QStringLiteral("/theme"));
|
||||||
|
if (!rels_theme.isEmpty()) {
|
||||||
|
//In normal case this should be theme/theme1.xml which in xl
|
||||||
|
//:Todo
|
||||||
|
}
|
||||||
|
|
||||||
|
//load worksheets
|
||||||
|
QList<XlsxRelationship> rels_worksheets = xlworkbook_Rels.documentRelationships(QStringLiteral("/worksheet"));
|
||||||
|
if (rels_worksheets.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
for (int i=0; i<sheetNameIdPairList.size(); ++i) {
|
||||||
|
QPair<QString, QString> pair = sheetNameIdPairList[i];
|
||||||
|
QString worksheet_rId = pair.second;
|
||||||
|
QString name = xlworkbook_Rels.getRelationshipById(worksheet_rId).target;
|
||||||
|
QString worksheet_path = xlworkbook_Dir + QLatin1String("/") + name;
|
||||||
|
Worksheet *sheet = m_document->workbook()->addWorksheet(pair.first);
|
||||||
|
sheet->loadFromXmlData(zipReader.fileData(worksheet_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Package::createPackage(QIODevice *package)
|
bool Package::createPackage(QIODevice *package)
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ int SharedStrings::addSharedString(const QString &string)
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SharedStrings::incRefByStringIndex(int idx)
|
||||||
|
{
|
||||||
|
addSharedString(m_stringList[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
void SharedStrings::removeSharedString(const QString &string)
|
void SharedStrings::removeSharedString(const QString &string)
|
||||||
{
|
{
|
||||||
if (!m_stringTable.contains(string))
|
if (!m_stringTable.contains(string))
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ public:
|
|||||||
|
|
||||||
int addSharedString(const QString &string);
|
int addSharedString(const QString &string);
|
||||||
void removeSharedString(const QString &string);
|
void removeSharedString(const QString &string);
|
||||||
|
void incRefByStringIndex(int idx);
|
||||||
|
|
||||||
int getSharedStringIndex(const QString &string) const;
|
int getSharedStringIndex(const QString &string) const;
|
||||||
QString getSharedString(int index) const;
|
QString getSharedString(int index) const;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <QPoint>
|
#include <QPoint>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
namespace QXlsx {
|
namespace QXlsx {
|
||||||
|
|
||||||
@@ -41,6 +42,15 @@ int intPow(int x, int p)
|
|||||||
else return x * tmp * tmp;
|
else return x * tmp * tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList splitPath(const QString &path)
|
||||||
|
{
|
||||||
|
int idx = path.lastIndexOf(QLatin1Char('/'));
|
||||||
|
if (idx == -1)
|
||||||
|
return QStringList()<<QStringLiteral(".")<<path;
|
||||||
|
|
||||||
|
return QStringList()<<path.left(idx)<<path.mid(idx+1);
|
||||||
|
}
|
||||||
|
|
||||||
QPoint xl_cell_to_rowcol(const QString &cell_str)
|
QPoint xl_cell_to_rowcol(const QString &cell_str)
|
||||||
{
|
{
|
||||||
if (cell_str.isEmpty())
|
if (cell_str.isEmpty())
|
||||||
|
|||||||
@@ -28,13 +28,17 @@
|
|||||||
#include "xlsxglobal.h"
|
#include "xlsxglobal.h"
|
||||||
class QPoint;
|
class QPoint;
|
||||||
class QString;
|
class QString;
|
||||||
|
class QStringList;
|
||||||
|
|
||||||
namespace QXlsx {
|
namespace QXlsx {
|
||||||
|
|
||||||
XLSX_AUTOTEST_EXPORT int intPow(int x, int p);
|
XLSX_AUTOTEST_EXPORT int intPow(int x, int p);
|
||||||
|
XLSX_AUTOTEST_EXPORT QStringList splitPath(const QString &path);
|
||||||
|
|
||||||
XLSX_AUTOTEST_EXPORT QPoint xl_cell_to_rowcol(const QString &cell_str);
|
XLSX_AUTOTEST_EXPORT QPoint xl_cell_to_rowcol(const QString &cell_str);
|
||||||
XLSX_AUTOTEST_EXPORT QString xl_col_to_name(int col_num);
|
XLSX_AUTOTEST_EXPORT QString xl_col_to_name(int col_num);
|
||||||
XLSX_AUTOTEST_EXPORT QString xl_rowcol_to_cell(int row, int col, bool row_abs=false, bool col_abs=false);
|
XLSX_AUTOTEST_EXPORT QString xl_rowcol_to_cell(int row, int col, bool row_abs=false, bool col_abs=false);
|
||||||
XLSX_AUTOTEST_EXPORT QString xl_rowcol_to_cell_fast(int row, int col);
|
XLSX_AUTOTEST_EXPORT QString xl_rowcol_to_cell_fast(int row, int col);
|
||||||
|
|
||||||
} //QXlsx
|
} //QXlsx
|
||||||
#endif // XLSXUTILITY_H
|
#endif // XLSXUTILITY_H
|
||||||
|
|||||||
@@ -337,12 +337,4 @@ QSharedPointer<Workbook> Workbook::loadFromXmlData(const QByteArray &data)
|
|||||||
return loadFromXmlFile(&buffer);
|
return loadFromXmlFile(&buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workbook::addWorksheet(const QString &name, QSharedPointer<Worksheet> sheet)
|
|
||||||
{
|
|
||||||
Q_D(Workbook);
|
|
||||||
|
|
||||||
sheet->setSheetName(name);
|
|
||||||
d->worksheets.append(sheet);
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE_XLSX
|
QT_END_NAMESPACE_XLSX
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ private:
|
|||||||
QByteArray saveToXmlData();
|
QByteArray saveToXmlData();
|
||||||
static QSharedPointer<Workbook> loadFromXmlFile(QIODevice *device);
|
static QSharedPointer<Workbook> loadFromXmlFile(QIODevice *device);
|
||||||
static QSharedPointer<Workbook> loadFromXmlData(const QByteArray &data);
|
static QSharedPointer<Workbook> loadFromXmlData(const QByteArray &data);
|
||||||
void addWorksheet(const QString &name, QSharedPointer<Worksheet> sheet);
|
|
||||||
|
|
||||||
SharedStrings *sharedStrings();
|
SharedStrings *sharedStrings();
|
||||||
Styles *styles();
|
Styles *styles();
|
||||||
|
|||||||
+15
-14
@@ -1074,9 +1074,9 @@ QByteArray Worksheet::saveToXmlData()
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Worksheet> Worksheet::loadFromXmlFile(QIODevice *device)
|
bool Worksheet::loadFromXmlFile(QIODevice *device)
|
||||||
{
|
{
|
||||||
Worksheet *sheet = new Worksheet(QStringLiteral("Sheet9999"));
|
Q_D(Worksheet);
|
||||||
|
|
||||||
XmlStreamReader reader(device);
|
XmlStreamReader reader(device);
|
||||||
while(!reader.atEnd()) {
|
while(!reader.atEnd()) {
|
||||||
@@ -1088,16 +1088,16 @@ QSharedPointer<Worksheet> Worksheet::loadFromXmlFile(QIODevice *device)
|
|||||||
if (range.size() == 2) {
|
if (range.size() == 2) {
|
||||||
QPoint start = xl_cell_to_rowcol(range[0]);
|
QPoint start = xl_cell_to_rowcol(range[0]);
|
||||||
QPoint end = xl_cell_to_rowcol(range[1]);
|
QPoint end = xl_cell_to_rowcol(range[1]);
|
||||||
sheet->d_func()->dim_rowmin = start.x();
|
d->dim_rowmin = start.x();
|
||||||
sheet->d_func()->dim_colmin = start.y();
|
d->dim_colmin = start.y();
|
||||||
sheet->d_func()->dim_rowmax = end.x();
|
d->dim_rowmax = end.x();
|
||||||
sheet->d_func()->dim_colmax = end.y();
|
d->dim_colmax = end.y();
|
||||||
} else {
|
} else {
|
||||||
QPoint p = xl_cell_to_rowcol(range[0]);
|
QPoint p = xl_cell_to_rowcol(range[0]);
|
||||||
sheet->d_func()->dim_rowmin = p.x();
|
d->dim_rowmin = p.x();
|
||||||
sheet->d_func()->dim_colmin = p.y();
|
d->dim_colmin = p.y();
|
||||||
sheet->d_func()->dim_rowmax = p.x();
|
d->dim_rowmax = p.x();
|
||||||
sheet->d_func()->dim_colmax = p.y();
|
d->dim_colmax = p.y();
|
||||||
}
|
}
|
||||||
} else if (reader.name() == QLatin1String("c")) {
|
} else if (reader.name() == QLatin1String("c")) {
|
||||||
QXmlStreamAttributes attributes = reader.attributes();
|
QXmlStreamAttributes attributes = reader.attributes();
|
||||||
@@ -1111,8 +1111,9 @@ QSharedPointer<Worksheet> Worksheet::loadFromXmlFile(QIODevice *device)
|
|||||||
reader.readNextStartElement();
|
reader.readNextStartElement();
|
||||||
if (reader.name() == QLatin1String("v")) {
|
if (reader.name() == QLatin1String("v")) {
|
||||||
QString value = reader.readElementText();
|
QString value = reader.readElementText();
|
||||||
|
d->workbook->sharedStrings()->incRefByStringIndex(value.toInt());
|
||||||
XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::String);
|
XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::String);
|
||||||
sheet->d_func()->cellTable[pos.x()][pos.y()] = QSharedPointer<XlsxCellData>(data);
|
d->cellTable[pos.x()][pos.y()] = QSharedPointer<XlsxCellData>(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1121,17 +1122,17 @@ QSharedPointer<Worksheet> Worksheet::loadFromXmlFile(QIODevice *device)
|
|||||||
if (reader.name() == QLatin1String("v")) {
|
if (reader.name() == QLatin1String("v")) {
|
||||||
QString value = reader.readElementText();
|
QString value = reader.readElementText();
|
||||||
XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::Number);
|
XlsxCellData *data = new XlsxCellData(value ,XlsxCellData::Number);
|
||||||
sheet->d_func()->cellTable[pos.x()][pos.y()] = QSharedPointer<XlsxCellData>(data);
|
d->cellTable[pos.x()][pos.y()] = QSharedPointer<XlsxCellData>(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QSharedPointer<Worksheet> (sheet);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Worksheet> Worksheet::loadFromXmlData(const QByteArray &data)
|
bool Worksheet::loadFromXmlData(const QByteArray &data)
|
||||||
{
|
{
|
||||||
QBuffer buffer;
|
QBuffer buffer;
|
||||||
buffer.setData(data);
|
buffer.setData(data);
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ public:
|
|||||||
|
|
||||||
void saveToXmlFile(QIODevice *device);
|
void saveToXmlFile(QIODevice *device);
|
||||||
QByteArray saveToXmlData();
|
QByteArray saveToXmlData();
|
||||||
static QSharedPointer<Worksheet> loadFromXmlFile(QIODevice *device);
|
bool loadFromXmlFile(QIODevice *device);
|
||||||
static QSharedPointer<Worksheet> loadFromXmlData(const QByteArray &data);
|
bool loadFromXmlData(const QByteArray &data);
|
||||||
|
|
||||||
~Worksheet();
|
~Worksheet();
|
||||||
private:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user