我有一个程序,可以一次读取每个单元格,逐行迭代,从而将excel转换为数据。
为此,我一直在使用两个单独的库:
ExcelFormat (for xls)
Xlsx I/O
我有一个算法的抽象类,每个都有两个派生类。我遇到的问题是ExcelFormat和Xlsx I / O不遵循相同的格式(因为它们是独立的库,并且不遵循相同的基类)。
(请注意,我为xlsxio编写了一个包装程序,因为它是程序性的,并且我需要OO功能)
我想将算法尽可能抽象为基类。
就目前而言,我真正能够做的就是拥有通用的抽象方法Convert(),该方法非常差,因为这两个函数在算法上都非常相似,但是仅由于它们无法遵循统一的接口不要共享相同的基础。
这是我所拥有的:
bool XlsxToData::Convert(const std::string & filePath, std::list<SqlParam*>* params) {
FreeXlsx::XlsxBook book(filePath);
if (book.IsOpen()) {
std::vector<std::string>* sheets = book.GetSheetList();
if (sheets != nullptr) {
std::list<SqlParam*> foundParams;
for (auto itr : *sheets) {
FreeXlsx::XlsxSheet sheet(itr, book);
std::map<int, SqlParam*> foundX;
int longestWidth = 0;
int lastWidth = 0;
if (sheet.IsOpen()) {
sheet.ForSheet([this, &foundParams, &foundX, &longestWidth, &lastWidth, params](const std::string & value, const int & x, const int & y) {
if (x > longestWidth)
longestWidth = x;
lastWidth = x;
GetValueCell(foundX, value, x);
CheckParams(foundX, foundParams, value, x, params);
},
[&longestWidth, &lastWidth, &foundX, this](const int & row) {
if (lastWidth < longestWidth)
for (int i = lastWidth + 1; i <= longestWidth; ++i) {
auto find = foundX.find(i);
if (find != foundX.end()) {
find->second->PushValue("");
}
}
});
sheet.Close();
}
if (params->size() < 1)
break;
}
delete sheets;
while (foundParams.size() > 0) {
params->push_back(*foundParams.begin());
foundParams.erase(foundParams.begin());
}
}
book.Close();
return true;
}
return false;
}
bool XlsToData::Convert(const std::string & filePath, std::list<SqlParam*>* params) {
ExcelFormat::BasicExcel book;
if (book.Load(filePath.c_str())) {
int sheets = book.GetTotalWorkSheets();
std::list<SqlParam*> foundParams;
for (int i = 0; i < sheets; ++i) {
ExcelFormat::BasicExcelWorksheet* sheet = book.GetWorksheet(i);
std::map<int, SqlParam*> foundX;
if (sheet != nullptr) {
const int rows = sheet->GetTotalRows();
const int cols = sheet->GetTotalCols();
std::map<int, SqlParam*> foundX;
for (int row = 0; row < rows; ++row) {
bool willBreak = false;
for (int col = 0; col < cols; ++col) {
ExcelFormat::BasicExcelCell * cell = sheet->Cell(row, col);
if (cell != nullptr) {
std::string value = getval(cell);
GetValueCell(foundX, value, col);
CheckParams(foundX, foundParams, value, col, params);
}
}
if (willBreak)
break;
}
}
}
while (foundParams.size() > 0) {
params->push_back(*foundParams.begin());
foundParams.erase(foundParams.begin());
}
book.Close();
return true;
}
return false;
}
我希望能够将打开书/表格的方法抽象为单个方法,作为迭代每个单元格的过程。
我已经考虑过可能为Xlsx I / O修改ExcelFormat和Wrapper类的源,以使其与统一的抽象库一起使用。
这将是最明智的方法吗?
是否已经有针对此类冲突的设计模式?
我是否应该实现一个继承自Excel Format的类的适配器类,然后使Xlsxio包装器和新的适配器类符合新的抽象基础?
还是有人有更好的解决方案?
谢谢。
编辑:另外,请注意,我意识到这显然具有较长的方法代码气味。我打算用更通用的算法来重构它。
最佳答案
您是否考虑过使用https://sourceforge.net/projects/xlslib/?
它稍微过时了,更便于携带。
对于XLSX I / O,如果您需要遍历包括空单元格在内的所有单元格,则建议为xlsxioread_process使用XLSXIOREAD_SKIP_NONE标志。
对于其余的部分,由于库之间的方法不同,我认为编写一个通用的基类并不像您所说的那样显而易见。
我的建议是使抽象类尽可能抽象,这意味着您不应基于任何一个库,而应基于它们的公共属性。
我个人已经放弃了.xls支持,因为这是Microsoft自Office 2007起就不再主动使用的封闭格式。