Artykuł techniczny

Edycja wykresów Excela bez utraty ChartML w HotXLS

HotXLS trzyma oryginalny ChartML importowanego wykresu Excela i odtwarza go bajt po bajcie, gdy nic w typizowanym modelu się nie zmieniło, więc otwarcie i ponowny zapis skoroszytu po cichu nie obdiera części wykresu, których model obiektów nie reprezentuje. Edytuj tytuł, serię lub oś, a HotXLS strukturalnie włącza nowe typizowane węzły do oryginalnego drzewa zamiast regenerować wykres od zera

To rozróżnienie — odtwarzanie, gdy nietknięte, scalanie, gdy edytowane — to właśnie czyni aplikację Delphi bezpieczną do wycelowania w wykresy zbudowane przez analityka w Excelu. Regeneracja wykresu z typizowanego modelu zawsze gubi to, czego model nie wie, a wykresy Excela są pełne rzeczy, których biblioteka nie wie: własne style, listy rozszerzeń, gałęzie alternate content, formatowanie kwalifikowane przestrzenią nazw z dodatków

Dlaczego ponowny zapis skoroszytu spłaszcza jego wykresy?

Ponieważ zwykła implementacja czyta to, co rozumie, i pisze to, co rozumie. Wszystko pomiędzy — extLst z nowszej kompilacji Excela, gałąź mc:AlternateContent, efekt kształtu, dla którego model nie ma właściwości — istnieje w pliku, nie ma domu w modelu obiektów i znika przy zapisie. Użytkownik widzi wykres, który stracił swój gradient, własne etykiety danych albo efekt 3D, a skoroszyt nie potrafi wyjaśnić dlaczego

Przy PreserveUnsupportedParts włączonym na skoroszycie HotXLS przechowuje oryginalne bajty UTF-8 wykresu przy imporcie wraz z długością i 64-bitowym odciskiem palca treści modelowanej. Jeśli typizowany model nie zmienił się do czasu zapisu, zapisuje oryginalne bajty z powrotem. Bez przestawiania XML, bez dryfu białych znaków, bez rezydentnej kopii UTF-16 wykresu krążącej w pamięci dla wykresu, którego nikt nie edytował

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;

Co scalanie zachowuje, a co posiada model

Regułą jest własność. Publiczne węzły modelu — tytuł, serie, pamięci podręczne, grupy wykresów, osie — są decydowane przez nowo wygenerowane drzewo. Niemodelowane poddrzewa są przenoszone z oryginału. Ta asymetria jest celowa i to jest część, której uświadomienie sobie zajmuje chwilę: usunięcie serii nie może wskrzesić starej serii z zachowanego XML, więc wszystko, co posiada model, jest brane z modelu nawet wtedy, gdy model mówi „zniknęło"

Treść bez właściciela jest reinserowana obok dopasowanych węzłów, obok których siedziała, a extLst zostaje ostatni w swoim rodzicu, bo tego wymaga schemat. Czyszczenie znanej właściwości — usunięcie flagi bold, porzucenie koloru — jest traktowane jako czyszczenie, nie jako luka do wypełnienia z oryginalnego drzewa. Nieznane atrybuty w tym samym sąsiedztwie zachowują swoje miejsce

Treść markup-compatibility dostaje specyficzną obsługę. Przy parsowaniu HotXLS pomija mc:Choice i czyta mc:Fallback; jeśli ta gałąź fallbacku opakowuje grupę wykresów, którą model zna, scalanie wpisuje nową typizowaną treść z powrotem do poddrzewa fallbacku. Bez tego kroku zapis wyemitowałby nową grupę wykresów i zostawił starą wewnątrz fallbacku, a wykres niósłby dwie

Wyłączenie jednego wykresu

ClearPreservedXml porzuca oryginalny XML i odcisk palca dla jednego wykresu, więc kolejny zapis przebudowuje ten wykres czysto z typizowanego modelu. To decyzja per wykres; skoroszytowy PreserveUnsupportedParts wciąż rządzi tym, czy stan zachowywania jest budowany przy imporcie

Sięgnij po to, gdy chcesz czysty wykres zamiast wiernego — na przykład gdy wykres z szablonu niesie formatowanie ze starego motywu korporacyjnego i celem operacji jest jego odrzucenie. Nie sięgaj po to jako odruch debuggowy: wykres, który renderuje się źle po edycji, to częściej kwestia modelowania niż zachowywania, a wyczyszczenie zachowanego XML niszczy dowód

Wykresy kombinarne i druga oś

AddPlotGroup buduje uporządkowane wykresy kombinarne, gdzie każda grupa wykresów trzyma własną rodzinę wykresu i własne przypisanie osi podstawowej lub drugorzędnej. To jest to, czego potrzebuje wszechobecny wykres biznesowy: przychód jako kolumny na lewej osi, marża procentowa jako linia na prawej

Wykresy wystawiają podstawowe i drugorzędne osie kategorii i wartości oraz oś serii, z typizowanymi ustawieniami kategorii, wartości, daty i osi serii obejmującymi pozycje, identyfikatory, przecięcia, jednostki daty, interwały etykiet i widoczność. Starsze płaskie API — ChartType, AddSeries, płaska kolekcja Series — wciąż adresuje podstawową grupę wykresów, więc istniejący kod działa dalej, podczas gdy model pod spodem trzyma każdą uporządkowaną grupę

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;

Zanim ten model istniał, otwarcie i ponowny zapis wykresu kombinarnego zwijały go do jednej rodziny wykresu i gubiły osie drugorzędne, daty i serii. Referencje formuł wykresu i buforowane wartości serii przeżywają teraz też kopie skoroszytu i cykle otwórz/zapis, a kotwice wykresów są dopasowywane do swoich części wykresu po identyfikatorze relacji — więc aplikacja, która przestawia wpisy relacji, nie zamienia już treści wykresów między pozycjami arkusza

Pułapka manualnego układu

Jeśli pozycjonujesz obszar kreślenia, tytuł, tytuł osi lub legendę ręcznie, zapisz wszystkie cztery współrzędne. Office wymaga x, y, w i h jako kompletnej grupy, gdy tylko jedna z nich jest obecna, a inaczej ignoruje cały manualLayout. HotXLS zawsze emituje pełny prostokąt z tego powodu, a SetPositionAndSize ustawia i włącza go jednym wywołaniem

Dwa kolejne szczegóły idą za Excelem zamiast za pełną swobodą specyfikacji. Pozycja jest zapisywana z xMode i yMode ustawionymi na edge, podczas gdy rozmiar używa factor dla wMode i hMode, bo to jest to, co pisze Excel i na co konwertuje inne kombinacje. A layoutTarget jest emitowany tylko dla obszaru kreślenia, nigdy dla tytułów ani legend, gdzie notatki implementacyjne Microsoftu tego zabraniają

Wpisanie tego w podróż skoroszytu w obie strony

Zachowywanie wykresów to jedna instancja ogólnej polityki: biblioteka, która edytuje dokumenty autorowane gdzie indziej, powinna zmienić to, o co poproszono, i nic więcej. To samo rozumowanie napędza HotXLS wobec motywów, łańcuchów obliczeń i rozszerzeń arkusza, opisane w notatkach o beztstratnych podróżach w obie strony dla motywu, extLst i calcChain oraz wobec projektów VBA i łączy zewnętrznych w zachowywaniu VBA i łączy zewnętrznych. Dla samej powierzchni autorskiej wykresów — tworzenia wykresów, umieszczania obrazów i rysunków z Delphi — zobacz przewodnik po wykresach, obrazach i rysunkach w HotXLS

HotXLS czyta, edytuje i zapisuje wykresy XLSX z natywnego kodu Delphi i C++Builder bez instalacji Excela na maszynie, co właśnie czyni z fidelity problem biblioteki zamiast problemu automatyzacji — strona komponentu arkuszowego HotXLS ma listę funkcji wykresów i wersję próbną