詳細については、下部の更新を参照してください。
Excelファイル(xlsx形式)としてデータを出力する必要があるプロジェクトがときどきあります。通常、プロセスは次のとおりです。
ユーザーが私のアプリケーションのいくつかのボタンをクリックする
私のコードはDBクエリを実行し、結果を何らかの方法で処理します
私のコードは、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 interopライブラリが1ベースのセル参照を使用し、Aspose.Cellsが0ベースのセル参照を使用するという問題がありました。
上に挙げたいくつかの短所に対処する1つのソリューションを次に示します。データのテーブルを、セルの操作や他のセル参照を妨害することなく移動したり変更したりできる独自のオブジェクトとして扱いたいと思いました。擬似コードは次のとおりです。
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);
このソリューションの一部として、ブロックのコンテナーを取得し、データを* .xlsxファイルとして出力するために必要なセル操作を実行するBlockEngineオブジェクトを用意します。ブロックオブジェクトには、書式を添付できます。
長所:
- これにより、最初のコードにあったほとんどのマジックナンバーが削除されます。
- これにより、多くのセル操作コードが非表示になりますが、私が述べたBlockEngineオブジェクトではセル操作が必要です。
- スプレッドシートの他の部分に影響を与えずに行を追加および削除する方がはるかに簡単です。
短所:
- 列の追加または削除は依然として困難です。2列目と3列目の位置を入れ替えたい場合は、セルの内容を直接入れ替える必要があります。この場合、それは8つの編集であり、したがって8つのミスを犯す可能性があります。
- これらの2つの列の書式が設定されている場合は、それも更新する必要があります。
- このソリューションは、水平ブロック配置をサポートしていません。1つのブロックのみを別のブロックの下に配置できます。もちろんできますが
tableRight.PutToRightOf(tableLeft)
、tableRightとtableLeftの行数が異なる場合、問題が発生します。テーブルを配置するには、エンジンは他のすべてのテーブルを認識する必要があります。これは不必要に複雑に思えます。 - 私はまだサードパーティのコードを学ぶ必要がありますが、BlockオブジェクトとBlockEngineを介した抽象化の層を通して、コードは最初の試みよりもサードパーティのライブラリに強く結合されません。多数の異なる書式設定オプションを疎結合の方法でサポートしたい場合、おそらく多くのコードを記述する必要があります。私のBlockEngineは巨大な混乱です。
別のルートをとるソリューションを次に示します。プロセスは次のとおりです。
レポートデータを取得し、選択した形式のxmlファイルを生成します。
次に、xsl変換を使用して、xmlファイルをExcel 2003 XMLスプレッドシートファイルに変換します。
そこから、サードパーティのライブラリを使用して、xmlスプレッドシートをxlsxファイルに変換するだけです。
同様のプロセスを説明し、コード例を含むこのページを見つけました。
長所:
- このソリューションでは、細胞の操作はほとんど必要ありません。代わりに、xsl / xpathを使用して操作を行います。テーブル内の2つの列を交換するには、セル交換を必要とする他のソリューションとは異なり、xslファイル内の列全体を移動します。
- Excel 2003 XMLスプレッドシートをxlsxファイルに変換できるサードパーティライブラリがまだ必要ですが、それだけでライブラリが必要になります。サードパーティのライブラリを呼び出すコードを書くのに必要な量はごくわずかです。
- このソリューションは最も理解しやすく、必要なコードも最小限だと思います。
- 独自のxml形式でデータを作成するコードは簡単です。
- Excel 2003 XMLスプレッドシートが複雑であるため、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ファイルを生成するための優れたデザインパターンは何ですか?いくつかの解決策を考えることができますが、理想的なものとして突出しているものはありません。それぞれに欠点があります。
更新:そこで、似たようなXLSXファイルを生成するために、BlockEngineソリューションとXML Spreadsheetソリューションの両方を試しました。私の意見は次のとおりです。
BlockEngineソリューション:
- これには、代替案を考慮すると、必要なコードが多すぎます。
- オフセットが間違っていた場合、あるブロックを別のブロックで上書きするのは簡単すぎると感じました。
- 当初、書式設定はブロックレベルで添付できると述べました。これは、ブロックのコンテンツとは別にフォーマットを行うよりもはるかに優れていることがわかりました。コンテンツとフォーマットを組み合わせる良い方法は考えられません。また、それらを分離する良い方法を見つけることもできません。それはただの混乱です。
XMLスプレッドシートソリューション:
- 今のところ、このソリューションを使用します。
- このソリューションで必要なコードがはるかに少ないことを繰り返します。BlockEngineをExcel自体に効果的に置き換えています。ブックマークや改ページなどの機能をハックする必要があります。
- XMLスプレッドシート形式は細心の注意を払っていますが、小さな変更を加えて、お気に入りのDiffプログラムの既存のファイルと結果を比較するのは簡単です。そして、特異性を理解したら、それを所定の場所に置いて、そこからそれを忘れることができます。
- このソリューションが古いExcelファイル形式に依存していることを今でも心配しています。
- 作成したXSLTファイルは簡単に操作できます。ここでは、フォーマットの処理がBlockEngineソリューションの場合よりもはるかに簡単です。