有关更多信息,请参见底部的我的更新。
有时,我有一些项目必须将某些数据输出为Excel文件(xlsx格式)。该过程通常是:
用户单击我的应用程序中的一些按钮
我的代码运行数据库查询并以某种方式处理结果
我的代码使用Excel com互操作库或某些第三方库(例如Aspose.Cells)生成* .xlsx文件
我可以轻松地找到有关如何在线执行此操作的代码示例,但是我正在寻找一种更强大的方法来执行此操作。我希望我的代码遵循一些设计原则,以确保我的代码可维护且易于理解。
这是我最初尝试生成xlsx文件的样子:
var wb = new Workbook();
var ws = wb.Worksheets[0];
ws.Cells[0, 0].Value = "Header";
ws.Cells[1, 0].Value = "Row 1";
ws.Cells[2, 0].Value = "Row 2";
ws.Cells[3, 0].Value = "Row 3";
wb.Save(path);
优点:不多。它可以工作,所以很好。
缺点:
- 单元格引用是经过硬编码的,因此在我的代码中到处都是乱七八糟的数字。
- 如果不更新许多单元格引用,则很难添加或删除列和行。
- 我需要学习一些第三方库。一些库的使用方式与其他库一样,但是仍然存在问题。我有一个问题,com互操作库使用基于1的单元格引用,而Aspose.Cells使用基于0的单元格引用。
这是一种解决上面列出的缺点的解决方案。我想将数据表当作自己的对象,可以在不深入了解单元操作和不干扰其他单元格引用的情况下随意移动和更改数据。这是一些伪代码:
var headers = new Block(new string[] { "Col 1", "Col 2", "Col 3" });
var body = new Block(new string[,]
{
{ "Row 1", "Row 1", "Row 1" },
{ "Row 2", "Row 2", "Row 2" },
{ "Row 3", "Row 3", "Row 3" }
});
body.PutBelow(headers);
作为该解决方案的一部分,我将具有一些BlockEngine对象,该对象将容纳一个Blocks容器并执行将数据输出为* .xlsx文件所需的单元格操作。块对象可以附加格式。
优点:
- 这将删除我的初始代码中的大多数魔术数字。
- 尽管我提到的BlockEngine对象中仍然需要进行单元操作,但这隐藏了许多单元操作代码。
- 在不影响电子表格其他部分的情况下,添加和删除行要容易得多。
缺点:
- 添加或删除列仍然很困难。如果要交换第二列和第三列的位置,则必须直接交换单元格内容。在这种情况下,这将是八个编辑,因此有八个机会犯错。
- 如果这两列有任何格式,我也必须更新。
- 该解决方案不支持水平块放置;我只能将一个方块放在另一个方块之下。当然可以
tableRight.PutToRightOf(tableLeft)
,但是如果tableRight和tableLeft的行数不同,那会引起问题。要放置表,引擎必须知道其他所有表。对我来说,这似乎不必要地复杂。 - 我仍然需要学习第三方代码,尽管通过Block对象和BlockEngine的抽象层,代码将比我最初尝试的紧密耦合到第三方库。如果我想以松散耦合的方式支持许多不同的格式设置选项,则可能不得不编写很多代码。我的BlockEngine真是一团糟。
这是采用不同路线的解决方案。过程如下:
我获取报告数据并以我选择的某种格式生成一个xml文件。
然后,我使用xsl转换将xml文件转换为Excel 2003 XML Spreadsheet文件。
从那里,我简单地使用第三方库将xml电子表格转换为xlsx文件。
我发现此页面描述了类似的过程,并包含代码示例。
优点:
- 该解决方案几乎不需要细胞操作。相反,您可以使用xsl / xpath进行操作。为了交换一个表中的两列,您将xsl文件中的整个列都移动了,这与我的其他需要单元交换的解决方案不同。
- 尽管您仍然需要可以将Excel 2003 XML电子表格转换为xlsx文件的第三方库,但这几乎就是您所需要的库。您需要编写的可调用第三方库的代码量很小。
- 我认为此解决方案最容易理解,所需代码最少。
- 以我自己的xml格式创建数据的代码将很简单。
- 仅因为Excel 2003 XML Spreadsheet很复杂,xsl文件才会变得复杂。但是,检查xsl文件的输出很容易:只需在Excel中打开输出并检查错误消息即可。
- 生成示例Excel 2003 XML电子表格文件很容易:只需创建一个看起来像所需的xlsx文件的电子表格,然后将其另存为Excel 2003 XML电子表格即可。
缺点:
- Excel 2003 XML电子表格不支持某些功能。例如,您不能自动调整列宽。您不能在页眉或页脚中包含图片。如果要将生成的xlsx文件导出为pdf,则不能设置pdf书签。(我使用单元格注释共同解决了此问题。)。您必须使用第三方库来执行此操作。
- 需要一个支持Excel 2003 XML电子表格的库。
- 使用11岁的MS Office文件格式。
注意:我意识到xlsx文件实际上是包含xml文件的zip文件,但是xml格式对于我而言似乎太复杂了。
最后,我研究了涉及SSRS的解决方案,但对于我的目的而言似乎太过膨胀。
回到我最初的问题,什么是在代码中生成Excel文件的良好设计模式?我可以想到一些解决方案,但是似乎没有一个解决方案是理想的。每个都有缺点。
更新:所以我尝试使用BlockEngine解决方案和XML Spreadsheet解决方案来生成类似的XLSX文件。这是我对他们的看法:
BlockEngine解决方案:
- 考虑到替代方案,这仅需要太多代码。
- 如果发现偏移错误,我发现用另一个块覆盖一个块太容易了。
- 我最初说过,格式化可以附加在块级别。我发现这并没有比将块内容单独进行格式化更好。我想不出一种将内容和格式结合起来的好方法。我也找不到一种将它们分开的好方法。只是一团糟。
XML电子表格解决方案:
- 我现在要使用这种解决方案。
- 需要重复说明的是,该解决方案需要更少的代码。我实际上是用Excel本身替换BlockEngine。我仍然需要针对书签和分页符等功能进行破解。
- XML Spreadsheet格式有点挑剔,但是很容易进行一些小的更改并将结果与您喜欢的Diff程序中的现有文件进行比较。一旦发现了一些特质,就可以将其放在适当的位置,然后从那里忘记它。
- 我仍然担心此解决方案依赖于较旧的Excel文件格式。
- 我创建的XSLT文件易于使用。在这里,处理格式比使用BlockEngine解决方案要简单得多。