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

Der Umgang mit Inline und Shared Strings in Excel

Beim Quellcode aus Teil 1 muss noch einiges erklärt werden. Das Erste wäre das Einfügen des Worksheet Parts und das Anlegen einer Tabelle in demselben. Ich habe dort die Funktion InsertWorksheetPart aufgerufen, die jetzt noch implementiert werden muss. Der komplizierteste Teil dabei ist das Ermitteln der neuen ID für die einzufügende Tabelle. Wichtig ist, dass die neue ID nicht schon vorkommt. Dabei hilft ein wenig LINQ. Mit Hilfe einer Lambda Function kann man schnell die höchste Sheet ID herausfinden.

 

 private WorksheetPart InsertWorksheetPart(WorkbookPart wbPart, string sheetName)
{
  // Hinzufügen eines Worksheet Parts zum Workbook.
  WorksheetPart wsPart = wbPart.AddNewPart<WorksheetPart>();
  string rId = wbPart.GetIdOfPart(wsPart);

  // eindeutige ID ermitteln = höchste sheetID + 1:
  uint sheetId = 1;
  Sheets sheets = wbPart.Workbook.GetFirstChild<Sheets>();
  if (sheets.Elements<Sheet>().Count() > 0)
    sheetId = sheets.Elements<Sheet>().Select(s => s.SheetId.Value).Max() + 1;

  // Das Worksheet mit dem Workbook verbinden:
  Sheet sheet = new Sheet() { Id = rId, SheetId = sheetId, Name = sheetName };
  sheets.Append(sheet);
  wbPart.Workbook.Save();

  return wsPart;
}

Die Funktion ist relative praktisch, da es unerheblich ist, ob man eine neue Datei anlegt oder einfach eine neue Tabelle in eine bestehende Arbeitsmappe hängt.

Nun zum Hinzufügen von Zellen mit Strings. In Teil 1 wurde schon angedeutet, dass Tabellen zeilenweise aufgebaut sind. Wir hatten auch festgehalten, dass es Inline Strings und Shared Strings gibt.

 

 private Cell CreateCellWithInlineString(string cellRef, string cellValue)
{
  Cell c = new Cell();
  c.DataType = CellValues.InlineString;
  c.CellReference = cellRef;
  InlineString istr = new InlineString(
                        new Text(cellValue));
  c.AppendChild(istr);
  return c;
}

Die Markup-Repräsentation eines Inline Strings würde folgendermaßen aussehen:

 <x:c r="A1" t="inlineStr">
   <x:is>
      <x:t>Der Zellwert als String</x:t> 
  </x:is>
</x:c>

Shared Strings sind etwas aufwändiger zu handhaben, da immer zuerst geschaut werden muss, ob der String als solcher schon in der Shared Strings Tabelle vorhanden ist bzw. diese überhaupt da ist. Das Grundgerüst für die Zelle sieht so aus:

 private Cell CreateCellWithSharedString(string cellRef, string sharedString, 
                                        SharedStringTablePart sstPart)
{
  Cell c = new Cell();
  c.CellReference = cellRef;
  c.DataType = CellValues.SharedString;
  c.CellValue = 
    new CellValue(InsertSharedStringItem(sharedString, sstPart).ToString());
  return c;
}

Einen String in die Shared Strings Tabelle eintragen:

 private static int InsertSharedStringItem(string newString, 
                                          SharedStringTablePart sstPart)
{
  // SharedStringTable erzeugen, falls nicht vorhanden
  if (sstPart.SharedStringTable == null)
    sstPart.SharedStringTable = new SharedStringTable();

  // SharedStringTable durchsuchen. Wenn String vorhanden, Index zurück geben
  int i = 0;
  foreach (SharedStringItem ssi in sstPart.SharedStringTable.Elements<SharedStringItem>())
  {
    if (ssi.InnerText == newString)
      return i;
    i++;
  }

  // String ist nicht da ==> SharedStringItem erzeugen
  sstPart.SharedStringTable.AppendChild 
  (new SharedStringItem(new Text(newString)));
  sstPart.SharedStringTable.Save();

  return i;
}

Die Markup-Repräsentation eines Shared Strings würde folgendermaßen aussehen:

 <c r="D1" t="s">
  <v>0</v>
</c>

Der Verweis zeigt auf den String an der Position 0 in der Shared Strings Tabelle, die im Markup so aussehen könnte:

 <sst xmlns="https://schemas...spreadsheetml/2006/main" count="5" uniqueCount="3">
  <si>
    <t>Microsoft</t> 
  </si>
  <si>
    <t>Jens Häupel</t> 
  </si>
  <si>
    <t>Der Zellwert als String</t> 
  </si>
</sst>

[ Fortsetzung folgt ]