在游戏开发工作中,策划和运营一般会用Excel来编写配置文件,但是程序读取配置,最方便的还是xml文件.所以最好约定一个格式,然后在二者之间做一个转化.

本文利用libxl来读取Excel文件,利用 timyxml2 来写入xml文件

libxl3.65破解版 : http://pan.baidu.com/s/1boYaeRl  提取码:3xbe

tinyxml2 源码: https://github.com/leethomason/tinyxml2

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <string>
#include <vector>
#include <iostream>
#include <windows.h>
#include <ctime>
#include <io.h>
#include <direct.h>
#include "libxl.h"
#include "tinyxml2.h" const char *formatErrorMsg_NoSeparateRows = "sheet format error:no separate rows!";
const char *formatErrorMsg_GroupNameNull = "sheet format error:group name null!";
const char *formatErrorMsg_CellValueNull = "cell format error:cell value null!"; enum
{
enmFileExtensionLength = ,
}; enum ErrorDef
{
enmErrorDef_OK = ,
enmErrorDef_CreateBookFailed = ,
enmErrorDef_NotExcelFile = ,
enmErrorDef_LoadExcelFileFailed = ,
enmErrorDef_SaveXmlFileFailed = ,
enmErrorDef_CalculateXmlFilePathError = ,
enmErrorDef_MakeXmlFilePathError = ,
}; int32_t ExcelToXml(const char *excelFilePath, const char *xmlFilePath);
int32_t ExcelToXmls(const char *excelFileDirectory, const char *xmlFileDirectory);
int32_t BookToXmlDoc(libxl::Book* book, tinyxml2::XMLDocument *xmlDoc);
int32_t SheetToXmlEle(libxl::Sheet *sheet, tinyxml2::XMLDocument *xmlDoc, tinyxml2::XMLElement *ele);
void GetPathExtensionName(const char *filePath, char ext[], const uint32_t extLen);
bool IsConfigSheet(const char *sheetName);
bool IsCellEmpty(int32_t cellType);
const char* ReadCellContent(libxl::Sheet *sheet, const int32_t row, const int32_t col);
void GBKToUTF8(const char* asciiBuf, WCHAR wcharTmp[], char utf8Buf[], const int32_t utf8BufLen);
void GetFilesFromDirectory(std::vector<std::string> &files, const std::string &directoryPath);
int32_t CalculateXmlFilePath(const char *excelFileDirectory, const char *xmlFileDirectory, const char *excelFilePath, char xmlFilePath[], const int32_t xmlFilePathMaxLen);
int32_t CreateDirectory(const char *directoryPath); int32_t ExcelToXml(const char *excelFilePath, const char *xmlFilePath)
{
libxl::Book* book = NULL;
char ext[enmFileExtensionLength] = { };
GetPathExtensionName(excelFilePath, ext, enmFileExtensionLength);
if (strcmp(ext, ".xls") == )
{
book = xlCreateBook();
}
else if (strcmp(ext, ".xlsx") == )
{
book = xlCreateXMLBook();
}
else
{
return enmErrorDef_NotExcelFile;
}
if (!book)
{
return enmErrorDef_CreateBookFailed;
}
if (!book->load(excelFilePath))
{
return enmErrorDef_LoadExcelFileFailed;
}
tinyxml2::XMLDocument xmlDoc;
int32_t ret = BookToXmlDoc(book, &xmlDoc);
if (ret != enmErrorDef_OK)
{
return ret;
}
if (xmlDoc.SaveFile(xmlFilePath) != tinyxml2::XML_SUCCESS)
{
return enmErrorDef_SaveXmlFileFailed;
}
book->release();
return enmErrorDef_OK;
} int32_t BookToXmlDoc(libxl::Book* book, tinyxml2::XMLDocument *xmlDoc)
{
tinyxml2::XMLDeclaration *declaration = xmlDoc->NewDeclaration("version=\"1.0\" encoding=\"utf-8\"");
xmlDoc->LinkEndChild(declaration);
for (int32_t i = ; i < book->sheetCount(); ++i)
{
if (!IsConfigSheet(book->getSheet(i)->name())){ continue; }
tinyxml2::XMLElement *ele = xmlDoc->NewElement(book->getSheet(i)->name() + );
xmlDoc->LinkEndChild(ele);
// printf("%s\n", book->getSheet(i)->name());
int32_t ret = SheetToXmlEle(book->getSheet(i), xmlDoc, ele);
if (ret != enmErrorDef_OK)
{
return ret;
}
}
return enmErrorDef_OK;
} int32_t SheetToXmlEle(libxl::Sheet *sheet, tinyxml2::XMLDocument *xmlDoc, tinyxml2::XMLElement *ele)
{
tinyxml2::XMLElement *group = NULL;
static std::vector<std::string> titles;
titles.clear();
for (int32_t row = ; row < sheet->lastRow(); ++row)
{
// 获取该行前两个单元格
int32_t firstCellType = sheet->cellType(row, );
int32_t secondCellType = sheet->cellType(row, );
// 如果都是空白,表明是空白行
if (IsCellEmpty(firstCellType) && IsCellEmpty(secondCellType))
{
titles.clear();
continue;
}
// 如果都不是空白,表明是标题行,获取标题
else if (!IsCellEmpty(firstCellType) && !IsCellEmpty(secondCellType))
{
do
{
// 标题列不为空,表明没有分隔,有问题
if (!titles.empty())
{
group = xmlDoc->NewElement(formatErrorMsg_NoSeparateRows);
break;
}
const char *firstCell = ReadCellContent(sheet, row, );
if (NULL == firstCell)
{
group = xmlDoc->NewElement(formatErrorMsg_GroupNameNull);
break;
}
group = xmlDoc->NewElement(firstCell);
for (int32_t col = ; col <= sheet->lastCol(); ++col)
{
const char *text = ReadCellContent(sheet, row, col);
if (text == NULL || _stricmp(text, "EOF") == )
{
break;
}
titles.push_back(text);
}
} while ();
ele->LinkEndChild(group);
}
// 第一个为空,第二个不为空,表示是数据列
else if (IsCellEmpty(firstCellType) && !IsCellEmpty(secondCellType))
{
tinyxml2::XMLElement *cfg = xmlDoc->NewElement("cfg");
group->LinkEndChild(cfg);
for (uint32_t col = ; col < titles.size(); ++col)
{
const char *text = ReadCellContent(sheet, row, col + );
if (NULL == text)
{
text = formatErrorMsg_CellValueNull;
}
cfg->SetAttribute(titles[col].c_str(), text);
}
}
}
return enmErrorDef_OK;
} void GetPathExtensionName(const char *filePath, char ext[], const uint32_t extLen)
{
int32_t len = strlen(filePath), lastSep = , m = ;
for (lastSep = len - ; lastSep >= ; --lastSep)
{
if (filePath[lastSep] == '.' || filePath[lastSep] == '\\' || filePath[lastSep] == '/')
{
break;
}
}
if (lastSep < )
{
lastSep = ;
}
for (; lastSep < len; ++lastSep)
{
ext[m++] = filePath[lastSep];
}
ext[m] = '\0';
} bool IsConfigSheet(const char *sheetName)
{
if (NULL == sheetName)
{
return false;
}
return sheetName[] == '_';
} bool IsCellEmpty(int32_t cellType)
{
return (cellType == libxl::CELLTYPE_BLANK) || (cellType == libxl::CELLTYPE_EMPTY);
} const char* ReadCellContent(libxl::Sheet *sheet, const int32_t row, const int32_t col)
{
int32_t cellType = sheet->cellType(row, col);
switch (cellType)
{
case libxl::CELLTYPE_STRING:
do
{
const char *text = sheet->readStr(row, col);
// 先判断是不是全是acsii字符
bool isAscii = true;
int32_t textLen = strlen(text);
for (int32_t i = ; i < textLen; ++i)
{
if (!isascii(text[i]))
{
isAscii = false;
break;
}
}
// 如果是,则不用转换格式
if (isAscii)
{
return text;
}
// 否则,需要转成UTF8格式
else
{
const int32_t textUtf8StrLen = * ;
static char textUtf8Str[textUtf8StrLen];
static WCHAR wcharTemp[textUtf8StrLen];
GBKToUTF8(text, wcharTemp, textUtf8Str, textUtf8StrLen);
return textUtf8Str;
}
} while ();
case libxl::CELLTYPE_NUMBER:
do
{
const int32_t doubleStrLen = ;
static char doubleStr[doubleStrLen];
sprintf_s(doubleStr, doubleStrLen, "%f", sheet->readNum(row, col));
for (int32_t i = strlen(doubleStr) - ; i >= ; --i)
{
if (doubleStr[i] > '' && doubleStr[i] <= '')
{
break;
}
else if ((doubleStr[i] == '' || doubleStr[i] == '.') && (i != ))
{
doubleStr[i] = ;
}
}
return doubleStr;
} while ();
default:
break;
}
return NULL;
} void GBKToUTF8(const char* asciiBuf, WCHAR wcharTmp[], char utf8Buf[], const int32_t utf8BufLen)
{
int32_t len = MultiByteToWideChar(CP_ACP, , asciiBuf, -, NULL, );
MultiByteToWideChar(CP_ACP, , asciiBuf, -, wcharTmp, len);
len = WideCharToMultiByte(CP_UTF8, , wcharTmp, -, NULL, , NULL, NULL);
WideCharToMultiByte(CP_UTF8, , wcharTmp, -, utf8Buf, len, NULL, NULL);
} void GetFilesFromDirectory(std::vector<std::string> &files, const std::string &directoryPath)
{
struct _finddata_t fileinfo;
long hFile = ;
char tmpPath[MAX_PATH] = { };
sprintf_s(tmpPath, "%s\\*", directoryPath.c_str());
if ((hFile = _findfirst(tmpPath, &fileinfo)) == -){ return; }
do
{
if ((fileinfo.attrib & _A_SUBDIR))
{
if (strcmp(fileinfo.name, ".") != && strcmp(fileinfo.name, "..") != )
{
sprintf_s(tmpPath, "%s\\%s", directoryPath.c_str(), fileinfo.name);
GetFilesFromDirectory(files, tmpPath);
}
}
else
{
sprintf_s(tmpPath, "%s\\%s", directoryPath.c_str(), fileinfo.name);
files.push_back(tmpPath);
}
} while (_findnext(hFile, &fileinfo) == );
_findclose(hFile);
} int32_t ExcelToXmls(const char *excelFileDirectory, const char *xmlFileDirectory)
{
char xmlFilePath[MAX_PATH];
std::vector<std::string> files;
GetFilesFromDirectory(files, excelFileDirectory);
for (uint32_t i = ; i < files.size(); ++i)
{
printf("%s\n", files[i].c_str());
int32_t ret = CalculateXmlFilePath(excelFileDirectory, xmlFileDirectory, files[i].c_str(), xmlFilePath, MAX_PATH);
if (ret != enmErrorDef_OK){ return ret; }
ret = CreateDirectory(xmlFilePath);
if (ret != enmErrorDef_OK){ return ret; }
ExcelToXml(files[i].c_str(), xmlFilePath);
printf("\t%s\n", xmlFilePath);
}
return enmErrorDef_OK;
} int32_t CalculateXmlFilePath(const char *excelFileDirectory, const char *xmlFileDirectory, const char *excelFilePath, char xmlFilePath[], const int32_t xmlFilePathMaxLen)
{
int32_t excelFileDirectoryLen = strlen(excelFileDirectory);
int32_t excelFilePathLen = strlen(excelFilePath);
if (excelFileDirectoryLen > excelFilePathLen){ return enmErrorDef_CalculateXmlFilePathError; }
sprintf_s(xmlFilePath, xmlFilePathMaxLen, "%s%s", xmlFileDirectory, excelFilePath + excelFileDirectoryLen);
int32_t xmlFilePathLen = strlen(xmlFilePath);
for (int32_t i = xmlFilePathLen - ; i >= ; --i)
{
if (xmlFilePath[i] == '.')
{
xmlFilePath[i + ] = 'x';
xmlFilePath[i + ] = 'm';
xmlFilePath[i + ] = 'l';
xmlFilePath[i + ] = ;
break;
}
}
return enmErrorDef_OK;
} int32_t main()
{
for (int32_t i = ; i < ; ++i)
{
ExcelToXmls("excel", "xml");
}
system("pause");
return ;
} int32_t CreateDirectory(const char *directoryPath)
{
int32_t dirPathLen = strlen(directoryPath);
if (dirPathLen > MAX_PATH)
{
return enmErrorDef_MakeXmlFilePathError;
}
char tmpDirPath[MAX_PATH] = { };
for (int32_t i = ; i < dirPathLen; ++i)
{
tmpDirPath[i] = directoryPath[i];
if (tmpDirPath[i] == '\\' || tmpDirPath[i] == '/')
{
if (_access(tmpDirPath, ) != )
{
int32_t ret = _mkdir(tmpDirPath);
if (ret != )
{
return enmErrorDef_MakeXmlFilePathError;
}
}
}
}
return enmErrorDef_OK;
}

完整工程源码 : http://pan.baidu.com/s/1i47z4up 提取码:06sn

C++ 利用 libxl 将 Excel 文件转化为 Xml 文件的更多相关文章

  1. WPF: 读取XPS文件或将word、txt文件转化为XPS文件

    读取XPS格式文件或将doc,txt文件转化为XPS文件,效果图如下: 1.XAML页面代码: <Window x:Class="WpfWord.MainWindow" xm ...

  2. WFP: 读取XPS文件或将word、txt文件转化为XPS文件

    读取XPS格式文件或将doc,txt文件转化为XPS文件,效果图如下: 1.XAML页面代码: <Window x:Class="WpfWord.MainWindow"    ...

  3. 怎样将word文件转化为Latex文件:word-to-latex-2.56具体解释

    首先推荐大家读一读这篇博文:http://blog.csdn.net/ibingow/article/details/8613556 --------------------------------- ...

  4. jupyter命令把.ipynb文件转化为.py文件

    jupyter nbconvert --to script *.ipynb 就能把当前文件夹下面的所有的.ipynb文件转化为.py文件

  5. 使用vivado将bit文件转化为mcs文件

    使用vivado将bit文件转化为mcs文件 1.在Tcl Console中运行脚本: write_cfgmem -force -format MCS -size 64 -interface spix ...

  6. 将caj文件转化为pdf文件进行全文下载脚本(ubuntu下亲测有用)

    最近ubuntu下caj阅读器,突然崩掉了,而偏偏要准备开题,在网上搜索原因未果,准备放弃时候,突然在网上看到一个脚本,说是很好用,可以在指定页面将caj文件转化为pdf文件,亲测有用,这里直接给出脚 ...

  7. Netlib文件转化为mps文件

    Netlib文件转化为mps文件 简单方法1 下载并执行: git clone https://github.com/mtanneau/Netlib_experiments.git cd Netlib ...

  8. 使用Pull解析器生成XML文件和读取xml文件

    有些时候,我们需要生成一个XML文件,生成XML文件的方法有很多,如:可以只使用一个StringBuilder组拼XML内容,然后把内容写入到文件中:或者使用DOM API生成XML文件,或者也可以使 ...

  9. Maven入门2-pom.xml文件与settings.xml文件

    Maven入门2-pom.xml文件与settings.xml文件 本文内容来源于官网文档部分章节,settings.xml文件:参考http://maven.apache.org/settings. ...

随机推荐

  1. 4.EasyUI学习总结(四)——EasyUI组件使用 (通过用户登录来演示dialog、ajax的使用,serialize方法的使用,前后台怎样交互等)

    一.EasyUI组件的简单介绍 详细可看api: http://www.jeasyuicn.com/api/docTtml/index.htm easyUI提供了很多组件让我们使用,如下图所示: 很多 ...

  2. Python~~~关键字~~~

    https://docs.python.org/2.7/library/index.html # -*- coding: UTF-8 -*- 缩进indent raw_input tuple()   ...

  3. Pycharm 快捷键

    Ctrl + Alt + Space   快速导入任意类 Alt + enter键    快速导入模块.创建类 Ctrl + /  注释/取消行注释 Ctrl + Shift + /         ...

  4. ios 消息通知

    苹果的通知分为本地通知和远程通知,这里主要说的是远程通知 历史介绍 iOS 3 - 引入推送通知UIApplication 的 registerForRemoteNotificationTypes 与 ...

  5. 【MongoDB】递归获取字段更新表达式,更新复杂数据类型对象

    在实际更新Mongo对象时发现,原有的更新代码无法更新复杂的数据类型对象.恰好看到张占岭老师有对该方法做相关的改进,因此全抄了下来. 总的核心思想就是运用反射与递归,对对象属性一层一层挖掘下去,循环创 ...

  6. 使用Lua脚本语言开发出高扩展性的系统,AgileEAS.NET SOA中间件Lua脚本引擎介绍

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  7. Android真机调试 Android.Util.AndroidRuntimeException: You cannot combine custom titles with other title features

    参考连接:http://blog.csdn.net/scyatcs/article/details/9003285 Android.Util.AndroidRuntimeException: You ...

  8. T-SQL 基础学习 04

    索引        示意图 定义 索引提供指针指向存储在表中指定列的数据值,然后根据指定的排序次序排列这些指针 作用 通过使用索引,大大提高数据库的检索速度,改善数据库性能 索引六大类 1.      ...

  9. HDU 1712 ACboy needs your help(分组背包)

    题意:给你n的课程组,每个课程组有m个课程,每个课程有一个完成时间与价值.问在m天内每组课程组最多选择一个,这样可以得到的最大价值是多少 题解:分组背包,其实就是每个课程组进行01背包,再在课程组内部 ...

  10. ASP.NET常见面试题及答案(130题)

    1.C#中 property 与 attribute(抽像类)的区别,他们各有什么用处,这种机制的好处在哪里?答:property和attribute汉语都称之为属性.不过property是指类向外提 ...