Weitere Informationen finden Sie in meinem Update unten.
Ich habe gelegentlich Projekte, bei denen ich einige Daten als Excel-Datei (xlsx-Format) ausgeben muss. Der Prozess ist normalerweise:
Der Benutzer klickt auf einige Schaltflächen in meiner Anwendung
Mein Code führt eine DB-Abfrage aus und verarbeitet die Ergebnisse irgendwie
Mein Code generiert eine * .xlsx-Datei, indem er entweder die Excel-COM-Interop-Bibliotheken oder eine Bibliothek eines Drittanbieters (z. B. Aspose.Cells) verwendet.
Ich kann leicht Codebeispiele finden, um dies online zu tun, aber ich suche nach einer stabileren Möglichkeit, dies zu tun. Ich möchte, dass mein Code einigen Entwurfsprinzipien folgt, um sicherzustellen, dass mein Code wartbar und leicht verständlich ist.
So sah mein erster Versuch, eine XLSX-Datei zu generieren, aus:
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);
Vorteile: Nicht viel. Es funktioniert, also ist das gut.
Nachteile:
- Zellreferenzen sind hartcodiert, daher sind in meinem Code magische Zahlen verstreut.
- Es ist schwierig, Spalten und Zeilen hinzuzufügen oder zu entfernen, ohne viele Zellreferenzen zu aktualisieren.
- Ich muss eine Fremdbibliothek lernen. Einige Bibliotheken werden wie andere Bibliotheken verwendet, es kann jedoch weiterhin Probleme geben. Ich hatte ein Problem, bei dem die COM-Interop-Bibliotheken eine 1-basierte Zellreferenzierung verwenden, während Aspose.Cells eine 0-basierte Zellreferenzierung verwendet.
Hier ist eine Lösung, die einige der oben aufgeführten Nachteile behebt. Ich wollte eine Datentabelle als ein eigenes Objekt behandeln, das verschoben und geändert werden kann, ohne in die Zellmanipulation einzugreifen und andere Zellreferenzen zu stören. Hier ist ein Pseudocode:
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);
Als Teil dieser Lösung wird ein BlockEngine-Objekt benötigt, das einen Container mit Blöcken aufnimmt und die erforderlichen Zellmanipulationen ausführt, um die Daten als * .xlsx-Datei auszugeben. An ein Block-Objekt kann eine Formatierung angehängt werden.
Vorteile:
- Dies entfernt die meisten magischen Zahlen, die mein ursprünglicher Code hatte.
- Dadurch wird viel Code zur Zellmanipulation ausgeblendet, obwohl im erwähnten BlockEngine-Objekt noch eine Zellmanipulation erforderlich ist.
- Es ist viel einfacher, Zeilen hinzuzufügen und zu entfernen, ohne andere Teile der Tabelle zu beeinflussen.
Nachteile:
- Es ist immer noch schwierig, Spalten hinzuzufügen oder zu entfernen. Wenn ich die Position der Spalten zwei und drei tauschen wollte, musste ich den Zelleninhalt direkt tauschen. In diesem Fall wären das acht Bearbeitungen und damit acht Möglichkeiten, einen Fehler zu machen.
- Wenn für diese beiden Spalten Formatierungen vorhanden sind, muss diese ebenfalls aktualisiert werden.
- Diese Lösung unterstützt keine horizontale Blockplatzierung. Ich kann nur einen Block unter dem anderen platzieren. Sicher könnte ich haben
tableRight.PutToRightOf(tableLeft)
, aber das würde Probleme verursachen, wenn tableRight und tableLeft unterschiedliche Anzahlen von Zeilen hatten. Um Tabellen zu platzieren, müsste die Engine jede andere Tabelle kennen. Das erscheint mir unnötig kompliziert. - Ich muss noch Code von Drittanbietern lernen, obwohl der Code durch eine Abstraktionsebene über Block-Objekte und eine BlockEngine weniger eng an die Bibliothek von Drittanbietern gekoppelt ist als bei meinem ersten Versuch. Wenn ich viele verschiedene Formatierungsoptionen auf lose Weise unterstützen wollte, müsste ich wahrscheinlich viel Code schreiben. Meine BlockEngine wäre ein großes Durcheinander.
Hier ist eine Lösung, die einen anderen Weg einschlägt. Hier ist der Prozess:
Ich nehme meine Berichtsdaten und generiere eine XML-Datei in einem von mir gewählten Format.
Ich verwende dann eine XSL-Transformation, um die XML-Datei in eine Excel 2003-XML-Tabellenkalkulationsdatei zu konvertieren.
Von dort konvertiere ich einfach das XML-Arbeitsblatt in eine XLSX-Datei unter Verwendung einer Drittanbieter-Bibliothek.
Ich habe diese Seite gefunden , die einen ähnlichen Prozess beschreibt und Codebeispiele enthält.
Vorteile:
- Diese Lösung erfordert fast keine Zellmanipulation. Sie verwenden stattdessen xsl / xpath, um Ihre Manipulationen durchzuführen. Um zwei Spalten in einer Tabelle auszutauschen, verschieben Sie im Gegensatz zu meinen anderen Lösungen, bei denen das Austauschen von Zellen erforderlich wäre, die gesamten Spalten in der xsl-Datei.
- Sie benötigen zwar noch eine Drittanbieter-Bibliothek, die eine Excel 2003-XML-Kalkulationstabelle in eine XLSX-Datei konvertieren kann, aber das ist ungefähr alles, wofür Sie die Bibliothek benötigen. Die Menge an Code, die Sie schreiben müssen, um in die Bibliothek eines Drittanbieters zu gelangen, ist gering.
- Ich denke, diese Lösung ist am einfachsten zu verstehen und erfordert die geringste Menge an Code.
- Der Code, der die Daten in meinem eigenen XML-Format erstellt, ist einfach.
- Die xsl-Datei ist nur deshalb kompliziert, weil das Excel 2003-XML-Arbeitsblatt kompliziert ist. Es ist jedoch einfach, die Ausgabe der xsl-Datei zu überprüfen: Öffnen Sie einfach die Ausgabe in Excel und suchen Sie nach Fehlermeldungen.
- Es ist ganz einfach, Excel 2003-XML-Beispieltabellendateien zu generieren: Erstellen Sie einfach eine Tabelle, die Ihrer gewünschten xlsx-Datei ähnelt, und speichern Sie sie dann als Excel 2003-XML-Tabelle.
Nachteile:
- Excel 2003-XML-Arbeitsblätter unterstützen bestimmte Funktionen nicht. Beispielsweise können Sie Spaltenbreiten nicht automatisch anpassen. Sie können keine Bilder in Kopf- oder Fußzeilen einfügen. Wenn Sie die resultierende xlsx-Datei als PDF exportieren, können Sie keine PDF-Lesezeichen setzen. (Ich habe eine Lösung für dieses Problem mithilfe von Zellkommentaren zusammengestellt.) Sie müssen dies mit Ihrer Drittanbieter-Bibliothek tun.
- Benötigt eine Bibliothek, die Excel 2003 XML Spreadsheets unterstützt.
- Verwendet ein 11 Jahre altes MS Office-Dateiformat.
Hinweis: Mir ist klar, dass XLSX-Dateien eigentlich ZIP-Dateien sind, die XML-Dateien enthalten, aber die XML-Formatierung scheint für meine Zwecke zu kompliziert zu sein.
Schließlich habe ich nach Lösungen für SSRS gesucht, die für meine Zwecke jedoch zu aufgebläht erscheinen.
Zurück zu meiner Ausgangsfrage, was ist ein gutes Entwurfsmuster zum Generieren von Excel-Dateien im Code? Ich kann mir ein paar Lösungen vorstellen, aber keine scheint sich als ideal herauszustellen. Jeder hat Nachteile.
Update: Also habe ich sowohl meine BlockEngine-Lösung als auch meine XML-Tabellenkalkulationslösung zum Generieren ähnlicher XLSX-Dateien ausprobiert. Hier sind meine Meinungen von ihnen:
Die BlockEngine-Lösung:
- Dies erfordert einfach zu viel Code in Anbetracht der Alternativen.
- Ich fand es zu einfach, einen Block mit einem anderen zu überschreiben, wenn ich einen falschen Versatz hatte.
- Ich habe ursprünglich angegeben, dass die Formatierung auf Blockebene angehängt werden kann. Ich fand das nicht viel besser als das Formatieren getrennt vom Blockinhalt. Ich kann mir keine gute Möglichkeit vorstellen, den Inhalt und die Formatierung zu kombinieren. Ich kann auch keinen guten Weg finden, sie getrennt zu halten. Es ist nur ein Durcheinander.
Die XML-Tabellenkalkulationslösung:
- Ich gehe mit dieser Lösung vorerst.
- Es ist zu wiederholen, dass diese Lösung viel weniger Code erfordert. Ich ersetze die BlockEngine effektiv durch Excel. Ich brauche immer noch einen Hack für Features wie Lesezeichen und Seitenumbrüche.
- Das XML-Spreadsheet-Format ist schwierig, aber es ist einfach, kleine Änderungen vorzunehmen und die Ergebnisse mit einer vorhandenen Datei in Ihrem bevorzugten Diff-Programm zu vergleichen. Und sobald Sie eine Eigenart herausgefunden haben, können Sie sie einsetzen und von dort aus vergessen.
- Ich bin immer noch besorgt, dass diese Lösung auf einem älteren Excel-Dateiformat beruht.
- Die von mir erstellte XSLT-Datei ist einfach zu bearbeiten. Der Umgang mit Formatierungen ist hier viel einfacher als mit der BlockEngine-Lösung.