Technischer Artikel

Excel-Diagramme ohne ChartML-Verlust bearbeiten in HotXLS

HotXLS behält das originale ChartML eines importierten Excel-Diagramms und spielt es Byte für Byte erneut ab, wenn sich im typisierten Modell nichts geändert hat, sodass das Öffnen und erneute Speichern einer Arbeitsmappe nicht stillschweigend die Teile eines Diagramms entfernt, die das Objekt-Modell nicht repräsentiert. Editiert man einen Titel, eine Serie oder eine Achse, fügt HotXLS die neuen typisierten Knoten strukturell in den ursprünglichen Baum ein statt das Diagramm von Grund auf neu zu erzeugen

Diese Unterscheidung — erneutes Abspielen, wenn unangetastet, Zusammenführen, wenn bearbeitet — ist es, die eine Delphi-Anwendung sicher macht, wenn sie auf Diagramme gerichtet wird, die ein Analyst in Excel gebaut hat. Ein Diagramm aus einem typisierten Modell neu zu erzeugen verliert stets das, was das Modell nicht kennt, und Excel-Diagramme sind voll von Dingen, die eine Bibliothek nicht kennt: eigene Styles, Erweiterungs-Listen, Alternate-Content-Zweige, namensraum-qualifizierte Formatierung aus Add-Ins

Warum flacht das erneute Speichern einer Arbeitsmappe ihre Diagramme ab?

Weil die übliche Implementierung das liest, was sie versteht, und das schreibt, was sie versteht. Alles dazwischen — eine extLst aus einer neueren Excel-Version, ein mc:AlternateContent-Zweig, ein Form-Effekt, für den das Modell keine Eigenschaft hat — existiert in der Datei, hat kein Zuhause im Objekt-Modell und verschwindet beim Speichern. Der Nutzer sieht ein Diagramm, das seinen Farbverlauf, seine eigenen Datenbeschriftungen oder seinen 3D-Effekt verloren hat, und die Arbeitsmappe kann nicht erklären, warum

Mit PreserveUnsupportedParts auf der Arbeitsmappe aktiviert, speichert HotXLS beim Import die ursprünglichen UTF-8-Chart-Bytes zusammen mit einer Länge und einem 64-Bit-Fingerprint des modellierten Inhalts. Hat sich das typisierte Modell bis zum Speichern nicht geändert, schreibt es die ursprünglichen Bytes zurück. Kein XML-Umsortieren, kein Whitespace-Drift, keine residente UTF-16-Kopie des Diagramms im Speicher für ein Diagramm, das niemand bearbeitet hat

var
  Workbook: TXLSXWorkbook;
  Chart: TXLSXChart;
begin
  Workbook := TXLSXWorkbook.Create(nil);
  try
    Workbook.PreserveUnsupportedParts := True;   // set before Open
    Workbook.Open('quarterly-review.xlsx');
    Chart := Workbook.Sheets[1].Charts[0];   // Sheets[] is 1-based
    if Chart.HasPreservedXml then
      Log('original ChartML retained; untouched charts replay exactly');
    Chart.Title := 'Revenue by region, Q3 2026';  // now the merge path runs
    Workbook.SaveAs('quarterly-review-out.xlsx');
  finally
    Workbook.Free;
  end;
end;

Was die Zusammenführung behält und was das Modell ownet

Die Regel lautet Eigentum. Öffentliche Modell-Knoten — Titel, Serien, Caches, Plot-Gruppen, Achsen — werden vom neu erzeugten Baum entschieden. Unmodellierte Teilbäume werden aus dem Original übernommen. Diese Asymmetrie ist bewusst, und es ist der Teil, den man einen Moment verinnerlichen muss: Eine Serie zu löschen darf die alte Serie aus dem erhaltenen XML nicht wieder auferstehen lassen, also wird alles, was das Modell ownet, aus dem Modell genommen, selbst wenn das Modell „weg" sagt

Inhalt ohne Eigentümer wird neben den übereinstimmenden Knoten eingefügt, neben denen er saß, und extLst bleibt innerhalb seines Elternteils der Letzte, weil das Schema das verlangt. Eine bekannte Eigenschaft zu löschen — ein Bold-Flag entfernen, eine Farbe ablegen — wird als Löschung behandelt, nicht als Lücke, die aus dem ursprünglichen Baum zu füllen ist. Unbekannte Attribute in derselben Nachbarschaft behalten ihren Platz

Markup-Compatibility-Inhalt erhält spezifische Behandlung. Beim Parsen überspringt HotXLS mc:Choice und liest mc:Fallback; falls dieser Fallback-Zweig eine Plot-Gruppe umschließt, die das Modell kennt, schreibt die Zusammenführung den neuen typisierten Inhalt zurück in den Fallback-Teilbaum. Ohne diesen Schritt würde ein Speichern die neue Plot-Gruppe emittieren und die alte im Fallback belassen, und das Diagramm trüge zwei

Ein Diagramm ausnehmen

ClearPreservedXml verwirft das originale XML und den Fingerprint für ein Diagramm, sodass der nächste Speichervorgang dieses Diagramm rein aus dem typisierten Modell neu aufbaut. Es ist eine Entscheidung pro Diagramm; die Arbeitsmappen-Ebene PreserveUnsupportedParts steuert weiterhin, ob beim Import ein Erhaltungszustand aufgebaut wird

Danach greifen, wenn man ein sauberes Diagramm statt eines treuen will — etwa wenn ein Vorlagen-Diagramm Formatierung aus einem alten Firmen-Theme trägt und der Sinn der Operation darin besteht, sie zu verwerfen. Nicht als Debug-Reflex danach greifen: Ein Diagramm, das nach einer Bearbeitung falsch rendert, ist häufiger eine Modellierungs-Frage als eine Erhaltungs-Frage, und das erhaltene XML zu löschen zerstört die Beweise

Kombinationsdiagramme und die zweite Achse

AddPlotGroup baut geordnete Kombinationsdiagramme, wobei jede Plot-Gruppe ihre eigene Diagramm-Familie und ihre eigene primäre oder sekundäre Achsen-Zuweisung behält. Das ist, was das allgegenwärtige Geschäftsdiagramm braucht: Umsatz als Säulen auf der linken Achse, Margenprozentsatz als Linie auf der rechten

Diagramme legen primäre und sekundäre Kategorie- und Wert-Achsen plus eine Serien-Achse frei, mit typisierten Kategorie-, Wert-, Datums- und Serien-Achsen-Einstellungen für Positionen, Bezeichner, Kreuzungen, Datumseinheiten, Beschriftungs-Intervalle und Sichtbarkeit. Die ältere flache API — ChartType, AddSeries, die flache Series-Kollektion — adressiert nach wie vor die primäre Plot-Gruppe, sodass bestehender Code weiter funktioniert, während das Modell darunter jede geordnete Gruppe hält

var
  Chart: TXLSXChart;
  Line: TXLSXChartPlotGroup;
begin
  // Column chart anchored over rows 1..15, columns 5..12
  Chart := Sheet.Charts.Add(xlsxChartColumn, 'Revenue and margin',
    1, 5, 15, 12);
  Chart.AddSeries('Revenue', 'Data!$A$2:$A$13', 'Data!$B$2:$B$13');
  // Second plot group: a line, read against the secondary value axis
  Line := Chart.AddPlotGroup(xlsxChartLine, xlsxAxisSecondary);
  Line.AddSeries('Margin %', 'Data!$A$2:$A$13', 'Data!$C$2:$C$13');
end;

Bevor es dieses Modell gab, kollabierte das Öffnen und erneute Speichern eines Kombinationsdiagramms zu einer einzigen Diagramm-Familie und verlor die sekundären, Datum- und Serien-Achsen. Diagramm-Formel-Referenzen und gecachte Serien-Werte überleben jetzt auch Arbeitsmappen-Kopien und Öffnen/Speichern-Zyklen, und Diagramm-Anker werden über ihren Relationship-Bezeichner zu ihren Diagramm-Parts zugeordnet — sodass eine Anwendung, die Relationship-Einträge umordnet, nicht mehr Diagramm-Inhalte zwischen Arbeitsblatt-Positionen vertauscht

Die Manual-Layout-Falle

Wer eine Plot-Area, einen Titel, einen Achsen-Titel oder eine Legende per Hand positioniert, sollte alle vier Koordinaten schreiben. Office verlangt x, y, w und h als vollständige Gruppe, sobald auch nur eine davon vorhanden ist, und ignoriert andernfalls das gesamte manualLayout. HotXLS emittiert deshalb stets das vollständige Rechteck, und SetPositionAndSize setzt und aktiviert es in einem Aufruf

Zwei weitere Details folgen Excel statt der vollen Freiheit der Spezifikation. Die Position wird mit xMode und yMode auf edge geschrieben, während die Größe factor für wMode und hMode verwendet, weil das das ist, was Excel schreibt und worin es andere Kombinationen umwandelt. Und layoutTarget wird nur für die Plot-Area emittiert, niemals für Titel oder Legenden, wo die Implementierungshinweise von Microsoft es verbieten

Das in einen Arbeitsmappen-Roundtrip einpassen

Diagramm-Erhaltung ist eine Instanz einer allgemeinen Policy: Eine Bibliothek, die woanders erstellte Dokumente bearbeitet, sollte das ändern, was sie ändern sollte, und nichts sonst. Desselben Gedankens treibt HotXLS bei Themes, Berechnungs-Ketten und Arbeitsblatt-Erweiterungen, beschrieben in den Hinweisen zu verlustfreien Roundtrips für Theme, extLst und calcChain, und zu VBA-Projekten und externen Links in Erhaltung von VBA und externen Links. Für die Diagramm-Autoren-Oberfläche selbst — Diagramme erstellen, Bilder und Zeichnungen aus Delphi platzieren — siehe die Erläuterung zu Diagrammen, Bildern und Zeichnungen in HotXLS

HotXLS liest, bearbeitet und schreibt XLSX-Diagramme aus nativem Delphi- und C++Builder-Code ohne Excel-Installation auf der Maschine, was aus Treue ein Bibliotheks-Problem statt eines Automatisierungs-Problems macht — die HotXLS-Spreadsheet-Komponenten-Seite führt die Diagramm-Funktionsliste und einen Trial-Download