Technischer Artikel

Excel-Sparklines in Delphi: HotXLS und die x14-Erweiterung

HotXLS erzeugt Excel-Sparklines — die Miniaturdiagramme, die Excel innerhalb einer einzelnen Zelle zeichnet — aus Delphi und C++Builder mit einem einzigen Aufruf: TXLSXWorksheet.AddSparklineGroup legt eine Sparkline-Gruppe über einem Datenbereich an, und beim Speichern der Arbeitsmappe wird sie als x14-Erweiterungsblock in das extLst des Arbeitsblatts geschrieben, das Excel 2010 und neuer darstellen und ältere Leseprogramme kommentarlos überspringen. Keine Diagrammobjekte, keine Drawing-Parts, keine Anker

Das Szenario, das Sparklines lohnend macht, ist immer dasselbe. Eine Dashboard-Arbeitsmappe enthält einige hundert Zeilen, eine je Produkt, Region oder Konto, mit jeweils zwölf Monatswerten, und jemand möchte am Ende jeder Zeile ein Trendsymbol. Bildet man das mit echten Diagrammen ab, erzeugt man hunderte DrawingML-Diagrammteile, jedes mit eigenem XML-Part, eigener Beziehung und eigener Ankergeometrie, ganz zu schweigen davon, was das für Dateigröße und Öffnungszeit bedeutet. Eine Sparkline-Gruppe ist ein einziger XML-Block, der sagt: „zeichne eine winzige Linie von B2:M2 nach N2 und von B3:M3 nach N3“, und der sich für beliebig viele Zeilen billig wiederholt

Diagramm einer HotXLS-Sparkline-Gruppe in Delphi: eine TXLSXSparklineGroup verzweigt zu zeilenweisen Mitgliedern wie Sheet1!B2:M2, das auf die Wirtszelle N2 abgebildet wird, mit Karten für die Typen Linie, Säule und Gewinn/Verlust
Ein Delphi-Aufruf erzeugt eine Sparkline-Gruppe, und jedes Mitglied bildet einen Quellbereich auf eine Wirtszelle ab. HotXLS bietet die Typen Linie, Säule und Gewinn/Verlust, die Excel innerhalb einer einzelnen Zelle zeichnet

Warum sind Sparklines eine x14-Erweiterung und kein Diagramm?

Sparklines kamen mit Excel 2010, drei Jahre nachdem das ECMA-376-Basisschema eingefroren worden war, sodass sie nicht im eigentlichen Arbeitsblatt-Markup leben konnten, ohne jedes vorhandene Leseprogramm zu brechen. Microsofts Antwort ist der Mechanismus der Erweiterungsliste: Ein Arbeitsblatt darf mit einem <extLst>-Element enden, das <ext>-Blöcke enthält, jeder ausgezeichnet mit einer URI, die das Feature identifiziert ([MS-XLSX] §2.3.6). Sparklines verwenden die URI {05C60535-1F16-4fd2-B633-F4F36F0B64E0} und den Namensraum x14. Ein Leseprogramm, das die GUID kennt, verarbeitet den Block; eines, das sie nicht kennt, muss ihn überspringen. Das ist die gesamte Geschichte der Vorwärtskompatibilität, und deshalb öffnet Excel 2007 eine Sparkline-Arbeitsmappe sauber — es zeigt schlicht die Quellzahlen ohne die Symbole

Ein Detail des Mechanismus ist erwähnenswert, weil es einer verbreiteten Annahme widerspricht: Am Wurzelelement des Arbeitsblatts ist keine mc:Ignorable-Deklaration nötig. Die Absicherung über die ext-GUID genügt für sich allein, und Excels eigener Writer deklariert den x14-Namensraum lokal am <ext>-Element, statt die Wurzel anzufassen. HotXLS folgt demselben Muster, was das übrige Arbeitsblatt-XML unberührt lässt. Darin liegt auch der strukturelle Unterschied zu echten Diagrammen: Ein Diagramm ist ein eigener DrawingML-Part mit eigener Rendering-Pipeline, behandelt in dem begleitenden Artikel zu Diagrammen, Bildern und Zeichnungen, während eine Sparkline Arbeitsblatt-Metadaten darstellt, die das Tabellenraster selbst zeichnet

extLst-Struktur des Arbeitsblatts für von HotXLS geschriebene Excel-Sparklines: ein ext-Block mit der x14-Sparkline-URI steuert die Darstellung, Excel 2010 und neuer zeichnen die Symbole, während Excel 2007 und unbekannte Leseprogramme den Block überspringen
Sparklines liegen in einem extLst-Block am Ende des Arbeitsblatt-Parts, ausgezeichnet mit der x14-Sparkline-URI. Leseprogramme, die die GUID kennen, zeichnen die Symbole, während ältere den Block überspringen

Wie fügt man Sparklines programmgesteuert in eine XLSX-Datei ein?

TXLSXWorksheet.AddSparklineGroup(AType, ASourceRange, ALocation) ist der Weg mit einem einzigen Aufruf: Er erzeugt eine Gruppe des angegebenen Typs, versieht sie mit Excels voreingestellter Serienfarbe und fügt die erste Sparkline hinzu, die einen blattqualifizierten Quellbereich auf eine Wirtszelle abbildet. Die zurückgegebene TXLSXSparklineGroup nimmt anschließend über ihre Methode Add weitere Sparklines auf, ein F/Sqref-Paar je Zeile, die alle Typ und Formatierung der Gruppe teilen. Für den Dashboard-Fall ist genau das die gewünschte Form: eine Gruppe, ein Satz visueller Optionen, hunderte Mitglieder

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Grp: TXLSXSparklineGroup;
  Row: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('dashboard.xlsx');
    Sheet := Book.Sheets[0];

    // Eine Gruppe: jede Produktzeile teilt Typ und Formatierung
    Grp := Sheet.AddSparklineGroup(xlsxSparklineLine,
      'Sheet1!B2:M2', 'N2');
    for Row := 3 to 201 do
      Grp.Add(Format('Sheet1!B%d:M%d', [Row, Row]),
        Format('N%d', [Row]));

    Book.SaveAs('dashboard-trends.xlsx');
  finally
    Book.Free;
  end;
end;

TXLSXSparklineType deckt die drei Arten ab, die Excel bietet: xlsxSparklineLine für Trendlinien, xlsxSparklineColumn für winzige Balkendiagramme und xlsxSparklineStacked für Gewinn/Verlust-Streifen, in denen jeder Wert als Block nach oben oder unten erscheint. Jede Mitglieds-Sparkline besteht nur aus zwei Strings — F, dem blattqualifizierten Quellbereich, und Sqref, der Zelle, in der das Symbol gezeichnet wird —, sodass es je Zeile nichts weiter zu konfigurieren gibt. Gruppen lassen sich auch vollständig von Hand über die Sammlung Worksheet.SparklineGroups aufbauen, wenn Sie lieber mit einer leeren Gruppe als mit der vorbelegten Voreinstellung beginnen

Marker, Farbslots und Achsenskalierung am typisierten Modell

TXLSXSparklineGroup stellt den vollen Optionsumfang aus Excels Menüband „Sparklinetools“ als gewöhnliche Eigenschaften bereit. Sechs boolesche Schalter heben Datenpunkte hervor: Markers für jeden Punkt einer Linien-Sparkline sowie HighPoint, LowPoint, NegativePoints, FirstPoint und LastPoint. Dazu gehören acht ARGB-Farbslots — ColorSeries, ColorNegative, ColorAxis, ColorMarkers, ColorFirst, ColorLast, ColorHigh, ColorLow — mit der Konvention, dass ein auf 0 belassener Slot nicht in die Datei geschrieben wird und Excel seine eigene Voreinstellung anwendet. Dieselbe voll deckende ARGB-Form findet sich in der ganzen Bibliothek, sodass $FFD00000 hier dasselbe Rot bedeutet wie in Stilen der bedingten Formatierung

Grp := Sheet.AddSparklineGroup(xlsxSparklineStacked,
  'Sheet1!B2:M2', 'N2');
Grp.NegativePoints := True;          // Verlustmonate treten hervor
Grp.ColorNegative := $FFD00000;
Grp.HighPoint := True;
Grp.ColorHigh := $FF00B050;
Grp.MinAxisType := xlsxSparklineAxisGroup;   // eine Skala für alle Zeilen
Grp.MaxAxisType := xlsxSparklineAxisGroup;
Grp.DisplayEmptyCellsAs := xlsxSparklineEmptyGap;

Die Achseneigenschaften verdienen einen Moment Nachdenken, bevor Sie die Voreinstellungen übernehmen. MinAxisType und MaxAxisType nehmen jeweils individuelle, gruppenweite oder benutzerdefinierte Skalierung an: Individuell dehnt jede Sparkline auf ihr eigenes Minimum und Maximum, wodurch eine Zeile, die zwischen 99 und 101 schwankt, ebenso dramatisch aussieht wie eine Zeile, die sich verdreifacht. Gruppenskalierung stellt alle Mitglieder auf eine gemeinsame vertikale Skala, sodass die Höhe eines Symbols in jeder Zeile dieselbe Menge bedeutet — meist das, was ein vergleichendes Dashboard braucht. DisplayEmptyCellsAs entscheidet, was eine leere Quellzelle mit einer Linie macht: eine Lücke lassen, als Null zählen oder das Loch durch Verbinden der Nachbarn überspannen

Optionsfläche der HotXLS-TXLSXSparklineGroup in Delphi: sechs Punktschalter, acht ARGB-Farbslots, bei denen Null Weglassen bedeutet, und die Achsenskalierungsmodi individuell, Gruppe und benutzerdefiniert
Die typisierte Gruppe stellt die vollständige Oberfläche der Sparklinetools bereit: sechs Punktschalter und acht ARGB-Farbslots. Die Achsenskalierung kann individuell, gruppenweit oder benutzerdefiniert sein, und leere Quellzellen können eine Lücke lassen, als Null zählen oder überspannt werden

Was HotXLS beim Speichern in das extLst des Arbeitsblatts schreibt

Beim Speichern serialisiert HotXLS jede Gruppe als x14:sparklineGroup-Element, das die Typ- und Schalterattribute trägt, die Farbslots als Kindelemente und eine x14:sparklines-Liste, deren Mitglieder eine xm:f-Bereichsformel mit einer xm:sqref-Wirtszelle paaren. Die gesamte Struktur sitzt in <extLst><ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"> am Ende des Arbeitsblatt-Parts, mit dem direkt am Block deklarierten x14-Namensraum, genau so, wie Excel es schreibt. Ein Arbeitsblatt ohne Sparkline-Gruppen gibt überhaupt kein extLst aus, sodass Dateien, die das Feature nie genutzt haben, Byte für Byte identisch zu dem herauskommen, was frühere HotXLS-Versionen erzeugt haben — dieselbe Disziplin eines zurückhaltenden Writers, die der Artikel zur verlustfreien Round-Trip-Infrastruktur beschreibt

Ein Detail der Spezifikation zählt, falls Sie die Ausgabe je mit der von Excel vergleichen oder das XML von Hand prüfen: Der Schema-Standard für lineWeight ist 0,75 Punkt, nicht die 1,25, die manche Sekundärquellen nennen — [MS-XLSX] definiert CT_SparklineGroup@lineWeight mit dem Standardwert 0.75, was der Stärke entspricht, die Excels Oberfläche tatsächlich anwendet. HotXLS respektiert den Standard durch Weglassen: Setzen Sie LineWeight auf etwas anderes als 0,75, wird das Attribut geschrieben; lassen Sie es bei 0,75, wird es weggelassen. Wer das in die eine oder andere Richtung falsch macht, erzeugt Dateien, die subtil kräftiger oder feiner dargestellt werden als dieselbe aus Excel gespeicherte Arbeitsmappe

Round-Trips, Blattkopien und Erweiterungen, die HotXLS nicht modelliert

Das Öffnen ist das Spiegelbild des Speicherns. Wenn HotXLS eine Arbeitsmappe mit Sparklines öffnet — gleich ob HotXLS oder Excel sie geschrieben hat —, prüft der Parser die Sparkline-ext-GUID und baut jede Gruppe, jedes Mitglied, jede Farbe und jede Achsenoption im typisierten Modell wieder auf, sodass ein Zyklus aus Öffnen, Bearbeiten und Speichern sie vollständig erhält. Beim Kopieren eines Arbeitsblatts in eine andere Arbeitsmappe werden die Sparkline-Gruppen zusammen mit dem übrigen Blatt geklont, was die vorlagengesteuerte Berichtserzeugung unkompliziert macht: Halten Sie ein gestaltetes Vorlagenblatt vor, kopieren Sie es je Bericht und richten Sie die Bereiche neu aus

Das extLst kann auch Erweiterungsblöcke enthalten, für die HotXLS kein typisiertes Modell hat — Excel schreibt x14-Blöcke für Funktionen wie Datenschnitte und erweiterte bedingte Formatierung in dieselbe Liste. Seit v2.131.0 bleiben diese fremden Blöcke über einen Round-Trip hinweg wortgetreu erhalten, statt verworfen zu werden: Der Parser erfasst sie, stellt sie schreibgeschützt über Worksheet.RawWorksheetExts bereit und schreibt sie beim Speichern zurück, und sie wandern mit einem Blatt mit, wenn es in eine andere Arbeitsmappe kopiert wird. Das erhaltene XML wird aus Parser-Ereignissen rekonstruiert, ist also semantisch gleichwertig zum Original statt byte-identisch, doch Excel akzeptiert es, und die Funktionen überleben. Die praktische Folge ist die, auf die es in der Produktion ankommt: Das Öffnen und erneute Speichern einer Kundenarbeitsmappe entfernt keine Erweiterungen mehr, um deren Verständnis Sie HotXLS nie gebeten haben

Die ehrliche Abgrenzung: Sparklines werden in Excel 2010 und neuer dargestellt sowie in jedem anderen Leseprogramm, das die x14-Erweiterung umsetzt; Excel 2007 zeigt die Daten ohne die Symbole, was genau die Degradation ist, für die das Format entworfen wurde. Die drei Sparkline-Typen, die acht Farbslots, die Punktschalter und die drei Achsenmodi decken den vollen Optionsumfang ab, den Excels eigener Dialog bietet. Die Sparkline-Unterstützung wird zusammen mit dem übrigen hier gezeigten XLSX-Motor in der HotXLS Delphi Excel Component für Delphi und C++Builder ausgeliefert