Technischer Artikel

Excel-AutoFilters ohne Excel in Delphi ausführen: HotXLS

HotXLS wertet die bereits in einer XLSX-Datei gespeicherten AutoFilter-Kriterien aus, ohne Excel zu starten. Seit v2.384.136 führen TXLSXWorksheet.PreviewAutoFilterRows, ApplyAutoFilter und AutoFilterRowVisible Wertelisten, Datumsgruppen, Top/Bottom-n- und Prozentfilter, relative Datums- und Durchschnittsfilter, Füll- und Schriftfarbenfilter sowie Filter auf Icons der bedingten Formatierung aus — unter einem eingefrorenen Referenzdatum und expliziten Ressourcengrenzen

Der übliche Auslöser ist eine Arbeitsmappe, die jemand in Excel gefiltert hat, und ein Server, der damit etwas tun muss. Jemand stellt "Top 10 nach Umsatz", "Diesen Monat" auf dem Bestelldatum und eine rote Füllung auf überfälligen Zeilen ein, speichert und lädt die Datei hoch. Ihr Delphi-Dienst braucht jetzt die Zeilenmenge, die Excel zeigen würde: um sie zu zählen, zu exportieren oder die Datei mit den richtigen Zeilen verborgen zurückzuschreiben. Die Datei hält nur die Definition. Vor diesem Release konnte HotXLS gewöhnliche benutzerdefinierte Kriterien auswerten, aber die fortgeschrittenen Arten lagen im gespeicherten XML, ohne dass etwas sie ausführte — die ehrliche Antwort lautete "in Excel öffnen"

Was führt HotXLS aus einem gespeicherten AutoFilter tatsächlich aus?

HotXLS führt eine Filterart pro Spalte aus, genommen aus dem filterColumn-Element, das Excel geschrieben hat, und kombiniert Spalten mit AND, genau wie die Excel-Dropdowns. Die Elemente stammen aus der AutoFilter-Gruppe in ECMA-376 Part 1 §18.3.2, und jedes mappt auf einen eigenen Auswertungspfad:

HotXLS-AutoFilter-Ausführung in Delphi verteilt jedes gespeicherte filterColumn-Element auf einen von fünf Auswertungspfaden - filters, customFilters, top10, dynamicFilter, colorFilter oder iconFilter - und wirft EXLSXAutoFilterUnsupported für alles andere
HotXLS wertet eine Filterart pro Spalte aus der AutoFilter-Gruppe von ECMA-376 Part 1 aus und kombiniert Spalten mit AND, sodass die sichtbare Zeilenmenge dem entspricht, was die Excel-Dropdowns zeigen würden
  • filters mit filter- und dateGroupItem-Kindern: eine angehakte Werteliste, ein optionaler Leereintrag und Kalenderdatumsgruppen vom Jahr bis zur Sekunde, per ODER verknüpft
  • customFilters: ein oder zwei Vergleichskriterien, verbunden mit AND oder OR — der Pfad, der bereits existierte
  • top10: Top oder Bottom n Einträge, oder n Prozent, mit val begrenzt auf 1-500 Einträge bzw. 1-100 Prozent
  • dynamicFilter: heute, gestern, morgen, diese/letzte/nächste Woche, Monat, Quartal und Jahr, Jahr bis dato, M1-M12, Q1-Q4, über dem Durchschnitt und unter dem Durchschnitt
  • colorFilter und iconFilter: effektive Füll- oder Schriftfarbe, aufgelöst über das Differential-Stylesheet, und Icons der bedingten Formatierung nach Icon-Set und nullbasiertem Icon-Id

Alles außerhalb dieser Liste scheitert mit EXLSXAutoFilterUnsupported, statt eine geratene Zeilenmenge zu produzieren. Das schließt die above- und below-standard-deviation-Typen von ST_DynamicFilterType ein, nicht-gregorianische calendarType-Werte, unbekannte Extension-Elemente, unaufgelöste dxfId-Referenzen und eine Spalte, die ausgerechnet zwei Filterarten gleichzeitig trägt. Eine Filter-Engine, die still "knapp daneben"-Zeilen zurückgibt, ist schlimmer als eine, die sich weigert, denn niemand merkt es, bis ein Report mit den falschen Kunden rausgeht

Erst Vorschau, dann Anwenden

HotXLS teilt die Arbeit in eine schreibgeschützte Vorschau und ein transaktionales Anwenden, und beide nehmen denselben TXLSXAutoFilterExecutionOptions-Record. PreviewAutoFilterRows liefert die Zahl der passenden Datenzeilen und rührt die Zeilensichtbarkeit nie an. ApplyAutoFilter(AResetVisible, Options) bereitet zuerst jede Zeilenentscheidung vor und veröffentlicht die neue verborgene-Zeilen-Menge erst dann in einem Schritt, sodass eine Exception während der Vorbereitung das Sheet exakt so lässt, wie es war

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Options: TXLSXAutoFilterExecutionOptions;
  Matching: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('orders-filtered-by-sales.xlsx');
    Sheet := Book.Sheets[1];   // der Sheets-Indexer ist 1-basiert

    // Immer von den Defaults starten, dann einzelne Felder ändern
    Options := XLSDefaultAutoFilterExecutionOptions;
    Options.ReferenceDate := EncodeDate(2026, 10, 19);

    Matching := Sheet.PreviewAutoFilterRows(nil, Options);  // nur Zählen
    WriteLn('Rows Excel would show: ', Matching);

    // True: passende Zeilen werden sichtbar, selbst wenn sie vorher verborgen waren
    Sheet.ApplyAutoFilter(True, Options);
    Book.SaveAs('orders-applied.xlsx');
  finally
    Book.Free;
  end;
end;

Initialisieren Sie den Record bei jedem Mal mit XLSDefaultAutoFilterExecutionOptions. Die Funktion nullt den Record und setzt dann jede Grenze, und der Ausführungskontext weist einen Record, dessen Grenzen nicht alle positiv sind, mit EXLSXAutoFilterLimit ab. Ein auf dem Stack deklarierter und Feld für Feld gefüllter Record trägt in den vergessenen Feldern meist Müll oder Nullen. Die parameterlosen Überladungen (ApplyAutoFilter(True), PreviewAutoFilterRows(Callback), AutoFilterRowVisible(Row)) verwenden dieselben Defaults, mit dem aktuellen Datum als Referenz

Das Flag AResetVisible entscheidet, was mit Zeilen passiert, die den Filter passieren, aber bereits verborgen waren. True macht jede passende Zeile sichtbar — was Excel tut, wenn man erneut anwendet. False behält früheres manuelles Verbergen auf passenden Zeilen bei und ergänzt Verbergen nur für Zeilen, die durchfallen. Zeilen außerhalb des AutoFilter-Bereichs behalten ihren Zustand in beiden Fällen. Hat sich die Arbeitsmappe zwischen Vorbereitung und Veröffentlichung geändert, wirft ApplyAutoFilter, statt Entscheidungen zu veröffentlichen, die aus veralteten Daten berechnet wurden

Warum ignorieren Wertelisten Sternchen und Fragezeichen?

Wertelisten-Einträge in einem filters-Element sind literale Anzeigetokens, also vergleicht HotXLS * und ? als gewöhnliche Zeichen. Ein angehakter Eintrag A* im Dropdown bedeutet, dass die Zelle exakt A* zeigt, nicht "beginnt mit A". Wildcards gehören zu customFilters, wo "beginnt mit" und "enthält" wirklich Muster sind, und diese halten die separaten Regeln ein, die in wie HotXLS Excel-Wildcard-Kriterien und Tilde-Escapes abgleicht behandelt werden. Die beiden Semantiken zu vermischen ist der schnellste Weg, eine Artikelnummern-Spalte in Unsinn zu filtern

Der Vergleich läuft gegen den angezeigten Wert, was die Frage aufwirft: welcher Anzeige. HotXLS formatiert die Zelle mit ihrem Basiszahlenformat, eingeschlossen gespeicherte Style-Overlays, und ignoriert bewusst ein Zahlenformat, das die bedingte Formatierung obendrauf anwendet. Die nativen Excel-Steuerelemente in der HotXLS-Fixture zeigen, warum das Token zählt: die Zahl 1 und der Text "1" passen beide zu einer Auswahl von 1, eine als 0.0 formatierte Zahl 1 passt stattdessen zu 1.0 zusammen mit dem Text "1.0", und der Text "01" bleibt von beiden verschieden. Datumsähnlicher Text wird nie in ein Datum geparst, also fällt eine Textzelle mit "2026-10-19" nicht in eine Datumsgruppe

Wie entscheiden Top 10, Durchschnitt und dynamische Datumsfilter?

HotXLS berechnet Rang- und Durchschnittsgrenzen einmal über die ganze Quellspalte, nicht über die Zeilen, die ein anderer Filter sichtbar gelassen hat. Nur endliche Zahlen kommen in die Population, das heißt, numerisch aussehender Text wie "100" wird ausgeschlossen, und die Population wird gesammelt, bevor irgendeine Zeilenentscheidung fällt. In der nativen Kontroll-Arbeitsmappe hält ein Above-Average-Filter einen Mittelwert von 27 über die volle Spalte, selbst nachdem eine zweite Spalte den Wert 50 verborgen hat; er schaltet nicht auf den 21,25-Mittelwert der verbleibenden Zeilen um

Gleichstände zählen an der Grenze mit, wie in Excel. Ein Top-3-Filter über Werten mit zwei an 20 gleichgestandenen Einträgen wählt vier Zeilen. Der Prozentmodus nimmt den abgetrennten Anteil der numerischen Population, mit einem Minimum von einem Eintrag, also wählt Top 50 Prozent von fünf Werten zwei Werte mit einer Schwelle von 30. Bottom-Varianten spiegeln den Vergleich. Diese Zahlen stammen aus den in den HotXLS-Test-Fixtures aufgezeichneten eigenen Zeilenmengen von Excel, nicht aus dem Lesen der Spezifikation, die zu den meisten davon schweigt

HotXLS berechnet Excel-AutoFilter-Top-10-, Prozent- und Above-Average-Grenzen in Delphi einmal über die ganze Quellspalte, hält verborgene Werte in der Population und Gleichstände an der Grenze im Ergebnis
Above-Average behält den Spaltenmittelwert 27 statt des Restzeilen-Mittelwerts 21,25, und ein Top-3-Filter über Werten mit zwei an 20 gleichgestandenen Einträgen wählt vier Zeilen

Dynamische Daten brauchen ein eingefrorenes Referenzdatum

TXLSXAutoFilterExecutionOptions.ReferenceDate friert die Bedeutung von "heute" für eine ganze Operation ein. Relative Filter wie diese Woche oder letztes Quartal und die Datumsregeln der bedingten Formatierung, die Farbfilter speisen, werden alle gegen dieses eine Datum ausgewertet, sodass eine Vorschau um 23:59:59 und ein eine Sekunde späteres Anwenden übereinstimmen. Ein Nullwert wählt das aktuelle Datum einmal beim Start der Operation; Serialwerte respektieren das 1900er- oder 1904er-Datensystem der Arbeitsmappe, eingeschlossen Excels fiktive Serial 60 im 1900er-System für die M2- und Q1-Filter

Die Fenster sind halb offene Kalenderintervalle: Diese Woche läuft von Sonntag bis zum folgenden Sonntag, dieses Quartal vom ersten Tag des Quartals bis zum ersten Tag des nächsten, und Jahr bis dato vom 1. Januar bis zum Ende des Referenztags. Setzen Sie ReferenceDate in allem, was im Batch oder im Test läuft, explizit. Ein nächtlicher Job, der Mitternacht kreuzt, oder ein Unit-Test, der im Oktober geschrieben wurde und im Januar bestehen muss, produziert sonst Zeilenmengen, die ohne sichtbaren Grund differieren

HotXLS wertet Excel-dynamicFilter-relative Datumsregeln in Delphi gegen ein eingefrorenes TXLSXAutoFilterExecutionOptions.ReferenceDate aus, mit halb offenen Diese-Woche-, Quartals- und Jahr-bis-dato-Fenstern
Das Eingefrieren des Referenzdatums lässt eine 23:59:59-Vorschau und das eine Sekunde späteres Anwenden übereinstimmen und nagelt die Serial-60-Besonderheit des 1900er-Systems fest, die die M2- und Q1-Filter betrifft

Formelzellen werden über ihre gecachten Werte gefiltert. Die Filter-Engine rechnet die Arbeitsmappe nicht still neu, also braucht eine Datei, gespeichert von einem Writer, der keine gecachten Ergebnisse hinterließ, einen expliziten Berechnungsdurchlauf, bevor der Filter sinnvolle Zahlen oder Daten sehen kann

Welche Farben sieht ein Farbfilter?

Ein HotXLS-Farbfilter sieht die effektive Farbe aus direkter Zellformatierung plus jede passende Überschreibung durch bedingte Formatierung, und nichts, was nur aus einem Tabellenstil kommt. Excel verhält sich genauso: Eine gebänderte Zeile, die ein eingebauter Tabellenstil hellblau malt, ist für das Filter-Dropdown nicht "hellblau". In den nativen Steuerelementen wird eine durch bedingte Formatierung rot gemalte Zelle von einem Rot-Füllungsfilter ausgewählt, während eine direkt rot formatierte Zelle, die von einer aktiven gelben Regel überschrieben wird, ausgeschlossen bleibt

Drei Verfeinerungen kamen in Nachfolge-Releases. Version 2.384.138 behandelt Linear- und Path-Gradient-Füllungen als eigenständig gegenüber Solid Colors und keiner Füllung, sodass ein Gradient nie ein Solid-Color-Kriterium erfüllt, selbst wenn einer seiner Stops genau diese Farbe hat. Version 2.384.140 ergänzte Schriftfarbenfiltering für Rich Text, bei dem eine Zelle passt, wenn irgendein nicht leerer Run die angeforderte RGB-, Automatic- oder geerbte Farbe trägt. Version 2.384.150 vervollständigte die Entscheidungen zu bedingtem Rich Text, die sich als die seltsamen herausstellten

Natives Excel kann eine Farbentscheidung zwischen einer Rich-Text-Zelle und einer normalen Zelle mit demselben Text, demselben Basisstil und demselben passenden Pfad einer bedingten Regel wiederverwenden, sodass die sichtbare Zeilenmenge von der Reihenfolge dieser Zellen abhängen kann. HotXLS reproduziert das, indem es den vollständigen Datenbereich in aufsteigender Zeilenreihenfolge vorbereitet, selbst wenn Sie AutoFilterRowVisible nur über eine Zeile fragen. Zeile 40 zu inspizieren kostet also einen Durchlauf über den Bereich, aber Zeileninspektion, Vorschau und Anwenden liefern für dieselbe Zeile stets dieselbe Antwort

Jede Ressource hat eine Grenze, und was man fängt

HotXLS begrenzt jede Art von Arbeit in einer AutoFilter-Operation mit eigenem Feld in TXLSXAutoFilterExecutionOptions, denn eine gefilterte Arbeitsmappe aus einem Upload-Formular ist nicht vertrauenswürdige Eingabe. Die Defaults sind 1048576 für MaxXmlCharacters, 16384 für MaxXmlNodes, 4096 für MaxFilterItems, 4000000 für MaxExaminedCells, je 1000000 für MaxEffectiveFormatCells und MaxPopulationValues, 67108864 Bytes für MaxContextBytes und 16000000 für MaxConditionalSteps. MaxContextBytes misst gehaltenen logischen Zustand und reservierte temporäre Hüllen, nicht Prozessspeicher

type
  TFilterJob = class
  public
    Deadline: TDateTime;
    VisibleRows: TList<Integer>;
    procedure HandleRow(Sender: TObject; SheetIndex, Row: Integer;
      Visible: Boolean; var Cancel: Boolean);
    procedure HandleWork(Sender: TObject; ACompleted: Int64;
      var ACancel: Boolean);
  end;

procedure TFilterJob.HandleRow(Sender: TObject; SheetIndex, Row: Integer;
  Visible: Boolean; var Cancel: Boolean);
begin
  // Für jede Datenzeile aufgerufen; Visible ist die Filterentscheidung
  if Visible then
    VisibleRows.Add(Row);
end;

procedure TFilterJob.HandleWork(Sender: TObject; ACompleted: Int64;
  var ACancel: Boolean);
begin
  // ACompleted zählt geprüfte Zellen und kann während der Formatierung stillstehen
  ACancel := Now > Deadline;
end;

Der Zeilen-Callback von PreviewAutoFilterRows empfängt jede Datenzeile mit ihrer Entscheidung, nicht nur die passenden, und die Funktion liefert weiterhin die Trefferzahl. Das Setzen seines Cancel-Parameters stoppt den Besuch früh ohne Exception. OnWork ist der Abbruch-Hook: ACancel auf True zu setzen wirft EXLSXAutoFilterCancelled. Während die Operation Entscheidungen vorbereitet, hält sie eine Lesepacht auf der Arbeitsmappe, also darf keiner der Callbacks diese Arbeitsmappe ändern

Options := XLSDefaultAutoFilterExecutionOptions;
Options.ReferenceDate := Date;
Options.MaxExaminedCells := 500000;   // engere Grenze für hochgeladene Dateien
Options.OnWork := Job.HandleWork;
try
  Sheet.PreviewAutoFilterRows(Job.HandleRow, Options);
  Sheet.ApplyAutoFilter(True, Options);
except
  on E: EXLSXAutoFilterUnsupported do
    Log('Filter needs Excel: ' + E.Message);
  on E: EXLSXAutoFilterLimit do
    Log('Filter exceeded a budget: ' + E.Message);
  on E: EXLSXAutoFilterCancelled do
    Log('Filter cancelled at deadline');
  on E: EXLSXAutoFilterExecution do
    Log('Filter state invalid: ' + E.Message);
end;

Alle drei spezifischen Exceptions leiten sich von EXLSXAutoFilterExecution ab, das selbst ungültige Zustände abdeckt, etwa ein Referenzdatum außerhalb des unterstützten Kalenders oder eine Arbeitsmappe, die sich vor der Veröffentlichung geändert hat — halten Sie die Basisklasse also zuletzt. In jedem Fall bleibt die Zeilensichtbarkeit des Sheets unverändert, was "loggen, überspringen, Datei zur manuellen Prüfung markieren" zu einer sicheren Default-Policy macht

Wo die Grenzen verlaufen

Die Abdeckung ist breit, aber ein paar Kanten sollte man kennen, bevor man einem Kunden Parität verspricht:

  • Dynamische Standardabweichungsfilter werden abgewiesen, solange es keine verifizierte Policy gibt, obwohl die Enumeration Werte dafür hat
  • Wochenfenster starten am Sonntag; Arbeitsmappen, die auf einem anderen Wochenstart beruhen, werden nicht modelliert
  • Formelergebnisse kommen nur aus dem gespeicherten Cache, ohne Neuberechnung innerhalb des Filteraufrufs
  • Tabellenstil-Farben erfüllen nie einen Farbfilter, aus Designgründen und im Einklang mit Excel
  • Unbekannte Rich-Text-Struktur oder unbekannte Farbmetadaten scheitern explizit, während bekannte Nicht-Farb-Eigenschaften wie die Schriftfamilie einen Farbtreffer nicht blockieren
  • Die XLS-Fassade und ihr BIFF8-Speicher sind ein separater Pfad, behandelt in wie HotXLS BIFF8-AutoFilter-DOPER-Kriterien schreibt

Wenn Sie noch darüber entscheiden, wie AutoFilter-Definitionen, Datenvalidierung und Tabellen in einer selbst erzeugten Arbeitsmappe zusammenhängen, beginnen Sie mit HotXLS-Datenvalidierung, AutoFilter und Tabellen in Delphi, das SetAutoFilter, Spalten-Ids und den Zeitpunkt behandelt, wann ein Filter tatsächlich greift

FAQ

Ändert PreviewAutoFilterRows, welche Zeilen verborgen sind?

Nein. PreviewAutoFilterRows wertet nur die gespeicherten Kriterien aus und meldet Entscheidungen über ihren Rückgabewert und den optionalen Callback. Nur ApplyAutoFilter veröffentlicht eine neue verborgene-Zeilen-Menge, und zwar erst, nachdem alle Entscheidungen vorbereitet sind, sodass ein Fehlschlag die ursprüngliche Sichtbarkeit unberührt lässt

Warum liefert ein relativer Datumsfilter an verschiedenen Tagen verschiedene Zeilen?

Filter wie heute, diese Woche oder letzter Monat sind relativ zum aktuellen Datum definiert, genau wie in Excel. Setzen Sie ReferenceDate in TXLSXAutoFilterExecutionOptions auf ein festes Datum, wenn Sie wiederholbare Ergebnisse brauchen; ein Nullwert bedeutet das Datum, an dem die Operation startet

Kann HotXLS nach Farben filtern, die aus einem Tabellenstil kommen?

Nein, und Excel kann es auch nicht. HotXLS-Farbfilter passen nur direkte Zellformatierung und unterstützte Überschreibungen durch bedingte Formatierung. Farben, die allein von einem eingebauten oder benutzerdefinierten Tabellenstil gemalt werden, nehmen nicht teil, sodass ein Farbfilter-Ergebnis dem entspricht, was das Excel-Dropdown auswählen würde

Die erweiterte AutoFilter-Ausführung kommt mit der XLSX-Worksheet-API von HotXLS, der Delphi-Spreadsheet-Komponente zum Lesen und Schreiben von Excel-Dateien ohne Excel, ab v2.384.136, mit Gradient-, Rich-Text- und bedingten Rich-Text-Farbbehandlungen ergänzt bis v2.384.150