Browse Source

We can read and modify existing simple .xlsx file now

master
Debao Zhang 11 years ago
parent
commit
d04a02e55c
  1. 1
      README.md
  2. 10
      examples/xlsx/readwrite/doc/src/readwrite.qdoc
  3. 18
      examples/xlsx/readwrite/main.cpp
  4. 12
      examples/xlsx/readwrite/readwrite.pro
  5. 3
      examples/xlsx/xlsx.pro
  6. 1
      src/xlsx/doc/src/qtxlsx-index.qdoc
  7. 1
      src/xlsx/xlsxdocument.h
  8. 60
      src/xlsx/xlsxpackage.cpp
  9. 5
      src/xlsx/xlsxsharedstrings.cpp
  10. 1
      src/xlsx/xlsxsharedstrings_p.h
  11. 10
      src/xlsx/xlsxutility.cpp
  12. 4
      src/xlsx/xlsxutility_p.h
  13. 8
      src/xlsx/xlsxworkbook.cpp
  14. 1
      src/xlsx/xlsxworkbook.h
  15. 29
      src/xlsx/xlsxworksheet.cpp
  16. 4
      src/xlsx/xlsxworksheet.h

1
README.md

@ -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/

10
examples/xlsx/readwrite/doc/src/readwrite.qdoc

@ -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
examples/xlsx/readwrite/main.cpp

@ -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
examples/xlsx/readwrite/readwrite.pro

@ -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

3
examples/xlsx/xlsx.pro

@ -4,5 +4,6 @@ SUBDIRS = hello style \
image \ image \
mergecells \ mergecells \
rowcolumn \ rowcolumn \
numberformat numberformat \
readwrite

1
src/xlsx/doc/src/qtxlsx-index.qdoc

@ -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
src/xlsx/xlsxdocument.h

@ -28,6 +28,7 @@
#include "xlsxglobal.h" #include "xlsxglobal.h"
#include <QObject> #include <QObject>
#include <QVariant>
class QIODevice; class QIODevice;
class QImage; class QImage;

60
src/xlsx/xlsxpackage.cpp

@ -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")));
//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;
}
//ToDo: Read the workbook here! //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
} }
return false; //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
src/xlsx/xlsxsharedstrings.cpp

@ -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
src/xlsx/xlsxsharedstrings_p.h

@ -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
src/xlsx/xlsxutility.cpp

@ -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
src/xlsx/xlsxutility_p.h

@ -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
src/xlsx/xlsxworkbook.cpp

@ -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
src/xlsx/xlsxworkbook.h

@ -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();

29
src/xlsx/xlsxworksheet.cpp

@ -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);

4
src/xlsx/xlsxworksheet.h

@ -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:

Loading…
Cancel
Save