用Cocos開發模型特效工具編輯器,跨Mac和windows,當中有個需求是讀取並解析excel文件,但網上的查找的例子幾乎都只能是在windows下面使用,再或者是命令行腳本之類的。於是,自己寫了一個非常輕量級的excel解析代碼,純cpp,除了依賴幾個cocos2d 方法(zip解壓和tinyxml2解析庫),不依賴任何系統API。 目前只能解析常見的表式結構(如果把excel當成word文檔使用就別看下面了),分享給大家,
如轉發還請注明出處,感謝。
為了保證mac和windows都可以跑過,所以去掉注釋,原諒我是VS菜鳥,當然代碼夠簡單不寫也能看懂。
getSheetArray返回的是excel的 行數組 ,因為c++里面難以實現動態類結構,所以不得已寫成這種方式,一般情況下該數據拿到后需要二次加工,你可以拿一個簡單的excel表格(比如道具物品表),測試打個斷點就知道有哪些數據結構。 我還有一個純js版本的,適合cocos2d-js使用,待日后完善了再丟出來。
//
// Excel.h
// 基於com.lipi.excel as3 版本設計,感謝lipi的源碼參考
// Created by howe on 15/5/5.
// auto excel = new Excel();
// bool result = excel->parseExcelFile(filepath, 1);
// std::vector<LineInfo> arr = std::move( excel->getSheetArray() );
//
#ifndef __ModelEditor__Excel__
#define __ModelEditor__Excel__
#include <stdio.h>
#include <vector>
#include <map>
struct LineInfo
{
int lineIndex;
std::vector<std::string> array;
};
class Excel
{
public:
Excel();
bool parseExcelFile(const std::string &filepath,int sheetIndex);
std::vector<LineInfo> getSheetArray();
private:
std::vector<std::string> _getValueArray();
private:
std::map<int,LineInfo> excelHash;
std::string _excelFilePath;
};
#endif /* defined(__ModelEditor__Excel__) */
Excel.cpp 實現部分
//
// Excel.cpp
//
// Created by howe on 15/5/5.
//
//
#include <iostream>
#include <string>
#include "Excel.h"
#include "cocos2d.h"
#include "external/tinyxml2/tinyxml2.h"
using namespace tinyxml2;
using namespace std;
unsigned char* getFileDataFromZip(const std::string& zipFilePath, const std::string& filename, ssize_t *size)
{
return cocos2d::FileUtils::getInstance()->getFileDataFromZip(zipFilePath, filename, size);
}
void deleteNum( std::string &content)
{
string::iterator t = content.begin();
while(t != content.end())
{
if(*t >= '0' && *t <= '9')
{
content.erase(t);
}
else
{
t++;
}
}
}
int getColIndex(std::string &content)
{
auto returnValue = 0;
for (auto i =0; i < content.length(); i++)
{
char n = content[i];
auto cValue = n - 64;
returnValue *= 26;
returnValue += cValue;
}
return returnValue - 1;
}
Excel::Excel()
:_excelFilePath("")
{
}
bool Excel::parseExcelFile(const std::string &ilepath, int sheetIndex)
{
_excelFilePath = ilepath;
excelHash.clear();
char xml_file[256] = {0};
sprintf(xml_file, "xl/worksheets/sheet%d.xml",sheetIndex+1);
ssize_t size;
auto fileData = getFileDataFromZip(_excelFilePath, xml_file, &size);
if (!fileData)
{
CCLOG(ilepath.c_str(), "The excel file is not exist!");
return false;
}
auto valueArray = std::move(_getValueArray());
tinyxml2::XMLDocument doc;
doc.Parse((const char*)fileData,size);
XMLElement *root = doc.RootElement();
XMLElement * sheetDataElement = root->FirstChildElement("sheetData");
XMLElement * rowElement =sheetDataElement->FirstChildElement("row");
while (rowElement)
{
LineInfo lineInfo;
auto rowIndex = atoi(rowElement->Attribute("r")) - 1;
lineInfo.lineIndex = rowIndex;
std::vector<std::string> &rowArray = lineInfo.array;
auto cElement = rowElement->FirstChildElement("c");
while (cElement)
{
std::string cc = cElement->Attribute("r");
deleteNum(cc);
auto colIndex = getColIndex( cc );
std::string t = "";
std::string v = "";
if (cElement->Attribute("t"))
{
t = cElement->Attribute("t");
}
auto vElement = cElement->FirstChildElement("v");
if (vElement)
{
v = vElement->GetText();
}
if (rowArray.size() < colIndex)
{
int len = rowArray.size();
for (auto i = 0;i < colIndex - len;i++)
{
rowArray.push_back(""); //
}
}
if (t == "s")
{
rowArray.push_back(valueArray[atoi(v.c_str())]);
}
else
{
rowArray.push_back(v);
}
cElement = cElement->NextSiblingElement("c");
}
auto bb = false;
for (auto iii : rowArray)
{
if (iii.length() > 1)
{
bb = true;
break;
}
}
if (bb)
{
excelHash[rowIndex] = lineInfo;
}
rowElement = rowElement->NextSiblingElement("row");
}
return true;
}
std::vector<std::string> Excel::_getValueArray()
{
std::vector<std::string> result;
ssize_t size;
auto fileData = getFileDataFromZip(_excelFilePath, "xl/sharedStrings.xml", &size);
tinyxml2::XMLDocument doc;
doc.Parse((const char*)fileData,size);
XMLElement *root = doc.RootElement();
XMLElement *siElement = root->FirstChildElement("si");
while (siElement)
{
std::string temp = "";
auto tElement = siElement->FirstChildElement("t");
while (tElement)
{
temp = temp + tElement->GetText();
tElement = tElement->NextSiblingElement("t");
}
result.push_back(temp);
siElement = siElement->NextSiblingElement("si");
}
return result;
}
std::vector<LineInfo> Excel::getSheetArray()
{
std::vector<LineInfo> result;
for ( auto ite = excelHash.begin();ite != excelHash.end();ite++)
{
auto &lineInfo_ = ite->second;
result.push_back(lineInfo_);
}
return result;
}
