Open XML Dateien aufbauen und verändern (Teil 1)

Der Umgang mit Strings in Excel

Nach längerer Zeit der Funkstille, begründet durch emsiges Herumreisen, gemeinsames Herumsitzen in eingeschneiten Fliegern auf dem Rollfeld sowie sonstiger allgemeiner vorweihnachtliche Hatz, will ich mir wieder etwas Zeit für die Technologie nehmen. Gerade in letzter Zeit wurde an einigen Stellen – wohl im Zuge der Erneuerung – die Frage in Richtung Open XML gelenkt. Oftmals sollten Dateien (Reports) aufgebaut oder ergänzt werden. Diesem Thema will ich mich in den nächsten Wochen widmen.

Da Excel-Dateien eine Art dreidimensionaler Struktur aufweisen – Zeilen, Spalten und Tabellen), verkompliziert sich deren Aufbau im Vergleich zu Word etwas. Um Speicherplatz zu sparen, wird eine Shared Strings-Tabelle verwendet, die für alle in einer Arbeitsmappe enthaltenen Tabellen zuständig ist. Der gesamte Inhalt einer Zelle innerhalb einer Tabelle entspricht einem Shared String, sofern er nicht eine Formel oder Zahl darstellt. In der Reihenfolge des Anlegens werden die Strings in der Shared Strings-Tabelle indiziert und über den Indexwert in der Zelle verlinkt.

Daneben gibt es noch Inline Strings, also Zeichenketten, die direkt innerhalb der Zelle in deren Markup gespeichert werden. Inline Strings werden von Excel allerdings automatisch in Einträge in der Shared Strings-Tabelle umgewandelt. Welchen Sinn haben sie dann? Nun, sie stellen einen einfachen Weg dar, Tabellen aufzubauen, ohne sich um die Komplexität der (externen) Shared Strings-Tabelle kümmern zu müssen.

Neben der WindowsBase Assembly wird die Bibliothek für das Open XML SDK 2.0 benötigt. Diese liefert zum einen eine höhere Abstraktion als die Methoden von System.IO.Packaging und zum anderen werden die Elemente des Markups (WordML, SpreadsheetML, etc.) als Objekte zur Verfügung gestellt. Damit werden viele Fehler (sofern es denn Leute gibt, die welche machen…) in die Compiletime verlagert (statt sie zur Laufzeit zu bekommen).

clip_image002

Wir unterscheiden zwischen den Parts, die eine logische Einheit innerhalb eines Open XML Files darstellen (Workbook, Worksheet) und dem XML, das die Repräsentation des eigentlichen Inhalts der Tabellen ist. Beides muss angelegt werden. Das grobe Gerüst ist hier zu sehen:

private void CreateExcelFile(string FName)
{

  using (SpreadsheetDocument sDoc =
SpreadsheetDocument.Create(FName, SpreadsheetDocumentType.Workbook))

  {
WorkbookPart partWB = sDoc.AddWorkbookPart();

   // Formatvorlagen hinzufügen:
WorkbookStylesPart partStyles = …

// Basisdokument Workbook.xml anlegen:
Workbook wb = new Workbook(new Sheets());
wb.Save(partWB); // Basis-WorksheetPart hinzufügen:
WorksheetPart partWS =

InsertWorksheetPart(partWB, "Open XML SDK Samples");

// SharedStringTable hinzufügen:
SharedStringTablePart partSharedStrings =
      partWB.AddNewPart<SharedStringTablePart>();

// worksheet.xml erzeugen:
Worksheet ws = new Worksheet();
SheetData sd = new SheetData();
ws.AppendChild(sd);

   // Zeilenweise Zellen hinzufügen:
Row r1 = new Row();
r1.RowIndex = 1;
r1.AppendChild( +++ );

   Row r3 = new Row();
r3.RowIndex = 3;
r3.AppendChild( +++ );

   sd.AppendChild(r1);
sd.AppendChild(r3);
ws.Save(partWS);

} }

Excel verlangt nach einer Datei, in der die Formatvorlagen definiert sind, dem WorkbookStylesPart. Ich gehe davon, dass keiner diesen Part von Anfang an erzeugt, sondern Excel als Templating Tool verwendet. Man nehme einfach eine Excel-Arbeitsmappe, die die gewünschte Formatierung enthält (bzw. formatiert Teile der Tabelle wie gewünscht). Das kann auf zwei Arten in unser Programm integriert werden:

Möglichkeit 1:

Man öffnet diese Excel-Datei mit dem Open XML SDK 2.0 Productivity Tool und lässt vom Reflector den Code erzeugen.

clip_image004

Der Aufruf sieht dann folgendermaßen aus:

WorkbookStylesPart partStyles = partWB.AddNewPart<WorkbookStylesPart>();
partStyles.Stylesheet = GenerateStylesSheet();
partStyles.Stylesheet.Save(partStyles);

Möglichkeit 2:

Man gibt der Excel-Datei den Suffix .zip und öffnet den Container. Im Ordner \xl befindet sich die Datei styles.xml. Diese wird in die Ressourcen des eigenen Programms aufgenommen.

image

Der Aufruf sieht dann folgendermaßen aus:

 WorkbookStylesPart partStyles = partWB.AddNewPart<WorkbookStylesPart>();<br>XmlDocument stylesXML = new XmlDocument();<br>stylesXML.LoadXml(Properties.Resources.styles); 
 using (StreamWriter streamStylesXML =     
new StreamWriter(partStyles.GetStream(FileMode.Create, FileAccess.Write)))<br>{<br>   stylesXML.Save(streamStylesXML);<br>} 

Die weitere Vorgehensweise ist schnell erklärt: Das Workbook.xml enthält Informationen über in der Arbeitsmappe enthaltene Tabellen (Worksheets). Gespeichert wird sie im Workbook Part. Danach muss mindestens eine Tabelle (Worksheet.xml) angelegt und im Worksheet Part gespeichert werden.

Wichtig in der worksheet.xml ist das sheetdata Element. An dieses werden die Zeilen angehängt, die wiederum die Zellen enthalten.

Die Shared Strings-Tabelle wird ebenfalls schon hier angelegt, wir benötigen sie erst später.

[ Fortsetzung folgt ]