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. 58
      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
* https://github.com/jmcnamara/XlsxWriter
* http://openpyxl.readthedocs.org
* http://officeopenxml.com/anatomyofOOXML-xlsx.php
* http://www.libxl.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 \
mergecells \
rowcolumn \
numberformat
numberformat \
readwrite

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

@ -110,5 +110,6 @@
\li \l{Xlsx Hello Example}
\li \l{Xlsx Style Example}
\li \l{Xlsx DocProperties Example}
\li \l{Xlsx Readwrite Example}
\endlist
*/

1
src/xlsx/xlsxdocument.h

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

58
src/xlsx/xlsxpackage.cpp

@ -25,6 +25,8 @@
#include "xlsxpackage_p.h"
#include "xlsxworkbook.h"
#include "xlsxworksheet.h"
#include "xlsxworkbook_p.h"
#include "xlsxutility_p.h"
#include "xlsxcontenttypes_p.h"
#include "xlsxsharedstrings_p.h"
#include "xlsxdocpropscore_p.h"
@ -38,6 +40,8 @@
#include "xlsxdocument.h"
#include <QBuffer>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
namespace QXlsx {
@ -125,17 +129,59 @@ bool Package::parsePackage(QIODevice *packageDevice)
m_document->setDocumentProperty(name, props.property(name));
}
//load workbook now
QList<XlsxRelationship> rels_xl = rootRels.documentRelationships(QStringLiteral("/officeDocument"));
if (!rels_xl.isEmpty()) {
//Get the app property file name if it exists.
//load workbook now, Get the workbook file path from the root rels file
//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")));
//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
}
//ToDo: Read the workbook here!
//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)

5
src/xlsx/xlsxsharedstrings.cpp

@ -59,6 +59,11 @@ int SharedStrings::addSharedString(const QString &string)
return index;
}
void SharedStrings::incRefByStringIndex(int idx)
{
addSharedString(m_stringList[idx]);
}
void SharedStrings::removeSharedString(const QString &string)
{
if (!m_stringTable.contains(string))

1
src/xlsx/xlsxsharedstrings_p.h

@ -54,6 +54,7 @@ public:
int addSharedString(const QString &string);
void removeSharedString(const QString &string);
void incRefByStringIndex(int idx);
int getSharedStringIndex(const QString &string) const;
QString getSharedString(int index) const;

10
src/xlsx/xlsxutility.cpp

@ -28,6 +28,7 @@
#include <QPoint>
#include <QRegularExpression>
#include <QMap>
#include <QStringList>
namespace QXlsx {
@ -41,6 +42,15 @@ int intPow(int x, int p)
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)
{
if (cell_str.isEmpty())

4
src/xlsx/xlsxutility_p.h

@ -28,13 +28,17 @@
#include "xlsxglobal.h"
class QPoint;
class QString;
class QStringList;
namespace QXlsx {
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 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_fast(int row, int col);
} //QXlsx
#endif // XLSXUTILITY_H

8
src/xlsx/xlsxworkbook.cpp

@ -337,12 +337,4 @@ QSharedPointer<Workbook> Workbook::loadFromXmlData(const QByteArray &data)
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

1
src/xlsx/xlsxworkbook.h

@ -78,7 +78,6 @@ private:
QByteArray saveToXmlData();
static QSharedPointer<Workbook> loadFromXmlFile(QIODevice *device);
static QSharedPointer<Workbook> loadFromXmlData(const QByteArray &data);
void addWorksheet(const QString &name, QSharedPointer<Worksheet> sheet);
SharedStrings *sharedStrings();
Styles *styles();

29
src/xlsx/xlsxworksheet.cpp

@ -1074,9 +1074,9 @@ QByteArray Worksheet::saveToXmlData()
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);
while(!reader.atEnd()) {
@ -1088,16 +1088,16 @@ QSharedPointer<Worksheet> Worksheet::loadFromXmlFile(QIODevice *device)
if (range.size() == 2) {
QPoint start = xl_cell_to_rowcol(range[0]);
QPoint end = xl_cell_to_rowcol(range[1]);
sheet->d_func()->dim_rowmin = start.x();
sheet->d_func()->dim_colmin = start.y();
sheet->d_func()->dim_rowmax = end.x();
sheet->d_func()->dim_colmax = end.y();
d->dim_rowmin = start.x();
d->dim_colmin = start.y();
d->dim_rowmax = end.x();
d->dim_colmax = end.y();
} else {
QPoint p = xl_cell_to_rowcol(range[0]);
sheet->d_func()->dim_rowmin = p.x();
sheet->d_func()->dim_colmin = p.y();
sheet->d_func()->dim_rowmax = p.x();
sheet->d_func()->dim_colmax = p.y();
d->dim_rowmin = p.x();
d->dim_colmin = p.y();
d->dim_rowmax = p.x();
d->dim_colmax = p.y();
}
} else if (reader.name() == QLatin1String("c")) {
QXmlStreamAttributes attributes = reader.attributes();
@ -1111,8 +1111,9 @@ QSharedPointer<Worksheet> Worksheet::loadFromXmlFile(QIODevice *device)
reader.readNextStartElement();
if (reader.name() == QLatin1String("v")) {
QString value = reader.readElementText();
d->workbook->sharedStrings()->incRefByStringIndex(value.toInt());
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 {
@ -1121,17 +1122,17 @@ QSharedPointer<Worksheet> Worksheet::loadFromXmlFile(QIODevice *device)
if (reader.name() == QLatin1String("v")) {
QString value = reader.readElementText();
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;
buffer.setData(data);

4
src/xlsx/xlsxworksheet.h

@ -74,8 +74,8 @@ public:
void saveToXmlFile(QIODevice *device);
QByteArray saveToXmlData();
static QSharedPointer<Worksheet> loadFromXmlFile(QIODevice *device);
static QSharedPointer<Worksheet> loadFromXmlData(const QByteArray &data);
bool loadFromXmlFile(QIODevice *device);
bool loadFromXmlData(const QByteArray &data);
~Worksheet();
private:

Loading…
Cancel
Save