We can read and modify existing simple .xlsx file now

This commit is contained in:
Debao Zhang
2013-10-19 13:28:06 +08:00
parent 7f218898b6
commit d04a02e55c
16 changed files with 135 additions and 33 deletions
+1
View File
@@ -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.
*/
+18
View File
@@ -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;
}
+12
View File
@@ -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
+2 -1
View File
@@ -4,5 +4,6 @@ SUBDIRS = hello style \
image \ image \
mergecells \ mergecells \
rowcolumn \ rowcolumn \
numberformat numberformat \
readwrite
+1
View File
@@ -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
*/ */
+1
View File
@@ -28,6 +28,7 @@
#include "xlsxglobal.h" #include "xlsxglobal.h"
#include <QObject> #include <QObject>
#include <QVariant>
class QIODevice; class QIODevice;
class QImage; class QImage;
+53 -7
View File
@@ -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
//In normal case, this should be "xl/workbook.xml"
QList<XlsxRelationship> rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument")); QList<XlsxRelationship> rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument"));
if (!rels_xl.isEmpty()) { if (rels_xl.isEmpty())
//Get the app property file name if it exists. return false;
//In normal case, this should be "xl/workbook.xml" QString xlworkbook_Path = rels_xl[0].target;
QString xlworkbook_Name = 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
} }
return false; //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;
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)
+5
View File
@@ -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))
+1
View File
@@ -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;
+10
View File
@@ -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())
+4
View File
@@ -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
-8
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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);
+2 -2
View File
@@ -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: