HotXLS, det inbyggda Excel-biblioteket för Delphi och C++Builder, är byggt för förlustfria XLSX-round-trips: öppna en arbetsbok, ändra en cell, spara, och kundens anpassade tema, utländska extLst-tilläggsblock samt beräkningskedjan överlever alla. Tre mekanismer får det att fungera — ordagrann cachelagring av xl/theme/theme1.xml, händelsebaserad om-serialisering av okända <ext>-block och en ny, specifikationsgiltig xl/calcChain.xml vid varje sparning av en formelarbetsbok
Scenariot som motiverar alla tre är deprimerande vanligt. En faktureringstjänst läser in en mall som kunden designat i Excel — företagets färgtema, miniatyrdiagram (sparklines) i en KPI-kolumn, en regel för villkorsstyrd formatering som lagts till av en nyare Excel-version — skriver en fakturasumma i cell B3 och sparar. Kunden öppnar resultatet och varumärkesfärgerna har återgått till standardmässigt Office-blått, miniatyrdiagrammen är borta och Excel erbjuder sig att ”reparera” filen. Ingenting i koden rörde någon av dessa funktioner. Biblioteket gjorde det, helt enkelt genom att spara
Varför förlorar Excel-filer formatering efter redigeringar med bibliotek?
Excel-filer förlorar formatering efter redigeringar med bibliotek eftersom de flesta bibliotek inte redigerar filen — de bygger om den. Ett .xlsx-paket är en ZIP-fil med XML-delar: xl/workbook.xml, en xl/worksheets/sheetN.xml per blad, xl/styles.xml, xl/theme/theme1.xml, xl/calcChain.xml med mera. En typiskt bibliotek tolkar dessa delar till en objektmodell vid öppning och återskapar varje del från den modellen vid sparning. Varje funktion som modellen inte representerar — ett tema som den aldrig tolkade, ett tilläggsblock från en nyare Excel — har ingenstans att ta vägen i minnet, så den återskapade delen utelämnar den tyst
ECMA-376 förutsåg hälften av detta problem. SpreadsheetML definierar extLst (ECMA-376 del 1, ”Future Feature Data Storage Area”, §18.2.10 för elementet på arbetsboksnivå) som en utsedd tilläggspunkt: nyare producenter placerar funktioner där, var och en omsluten av ett <ext>-element med ett uri-attribut som identifierar funktionen, och äldre konsumenter förväntas bevara det de inte förstår. Miniatyrdiagram, utsnitt (slicers) och nyare typer av villkorsstyrd formatering färdas alla på detta sätt. Ett bibliotek som kastar bort okända <ext>-block är därför inte bara förlustbringande — det bryter mot kontraktet för framåtriktad kompatibilitet som formatet designades kring. Frågan du bör ställa till alla kalkylbladsbibliotek du utvärderar är rak: om jag ändrar en cell, vad mer ändras
Hur bevarar HotXLS ett anpassat tema byte för byte?
HotXLS bevarar en arbetsboks tema genom att cachelagra de ursprungliga byten av xl/theme/theme1.xml vid öppningstillfället och skriva tillbaka dem ordagrant vid sparning. Temadelen (ECMA-376 del 1, §14.2.7) is DrawingML, not SpreadsheetML — colour schemes, font schemes, format schemes — and a spreadsheet engine has no reason to model it deeply. Tidigare versioner av HotXLS återskapade ett fast Office-tema vid varje sparning, vilket är exakt det fel med återställda varumärkesfärger som beskrivs ovan; sedan v2.89.46 lagras det öppnade paketets tema i råformat och skickas ut orört igen, och det inbyggda Office-temat genereras endast för arbetsböcker som skapas från grunden. Råa byte är starkast möjliga precisiongaranti: ingen tolkning, ingen om-serialisering, ingen risk för avvikelse
Den ordagranna kopian vinner avsiktligt över programmatisk temaåtkomst. TXLSXWorkbook exponerar ThemeMajorFont och ThemeMinorFont så att du kan välja typsnitt för rubriker och brödtext för nya arbetsböcker, men när ett ordagrant tema fångades vid öppning har dessa tilldelningar ingen effekt på den sparade filen — round-trip prioriteras. Om du verkligen behöver ändra en befintlig arbetsboks tema är det en signal om att redigera mallen i Excel själv snarare än via ett databaserat API. Det vardagliga fallet behöver inget API alls:
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('branded-invoice.xlsx');
Book.Sheets[0].Cells[3, 2].Value := 42750.00; // den enda redigeringen
Book.SaveAs('branded-invoice-out.xlsx');
// theme1.xml i utdata är byte-identisk med indata
finally
Book.Free;
end;
end;
Vad hände med okända extLst-block vid sparning?
HotXLS fångar upp varje <ext>-block på kalkylbladsnivå som det inte modellerar nativt och spelar upp det i den sparade arbetsbokens extLst, så att funktioner som skrivits av nyare Excel-versioner överlever resan fram och tillbaka intakta. Sedan v2.131.0 är de fångade fragmenten synliga via den skrivskyddade egenskapen RawWorksheetExts, en TStringList på varje XLSX-arbetsblad, vilket gör garantin kontrollerbar från testkod snarare än en trosfråga:
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
i: Integer;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('from-newer-excel.xlsx');
Sheet := Book.Sheets[0];
WriteLn(Format('%d foreign ext block(s) captured',
[Sheet.RawWorksheetExts.Count]));
for i := 0 to Sheet.RawWorksheetExts.Count - 1 do
WriteLn(Copy(Sheet.RawWorksheetExts[i], 1, 100)); // kika på varje uri
finally
Book.Free;
end;
end;
Implementeringsdetaljen som är värd att känna till är att insamlingen är en om-serialisering på händelsenivå, inte en rå byte-kopiering. HotXLS strömmande XML-läsare exponerar inga källförskjutningar, så det okända underträdet byggs upp från händelserna Element, Text och EndElement när de strömmar förbi. Det tillvägagångssättet döljer en klassisk fälla: ett självstängande element som <a/> utlöser endast en Element-händelse som flaggats som tom och aldrig ett EndElement, så alla djupmätare som minskas enbart på EndElement kommer aldrig att se underträdet stängas. Hantera det, så är det återuppbyggda fragmentet semantiskt likvärdigt med originalet — attributcitering och självstängande former normaliseras, så det är inte byte-identiskt, men Excel läser betydelse, inte byte. Två egenskaper hos Excels egna utdata gör uppspelningen säker: Excel deklarerar nödvändiga xmlns-attribut på <ext>-elementet eller inuti det, så varje fångat fragment är namnrymds-självständigt, och just denna självständighet är anledningen till att duplicering av ett kalkylblad inom eller mellan arbetsböcker kan bära med sig de utländska blocken med en vanlig tilldelning av stränglistor
Skriva calcChain.xml så att Excel litar på dina formler
HotXLS skriver xl/calcChain.xml (beräkningskedjedelen, ECMA-376 del 1, §12.3.1) när den sparade arbetsboken innehåller formler, och den väljer mellan två ordningar. Om formelberoendegrafen redan har byggts och är aktuell — du anropade Recalculate efter din senaste redigering — skickas kedjan ut i fullständig topologisk ordning, beroenden före beroende, med eventuella medlemmar i cirkelreferenser tillagda i slutet. Annars listas cellerna i dokumentordning. Båda är korrekta: Microsofts implementeringsanteckningar för formatet, [MS-XLSX], behandlar beräkningskedjan som en ledtråd som Excel verifierar och ordnar om under inläsning, så alla fullständiga listningar är lagliga, och HotXLS vägrar medvetet att tvinga fram ett grafbygge inuti SaveAs — konstruktion av kanter är kvadratisk i förhållande till cellantalet, en oacceptabel dold kostnad vid sparning av en miljon celler
Book.Open('model.xlsx');
Book.Sheets[0].Cells[10, 4].Formula := '=SUM(D2:D9)';
// Sparas nu, calcChain.xml listar formelceller i dokumentordning.
// Efter Recalculate finns beroendegrafen, så samma sparning
// skickar ut en fullständig topologisk ordning istället:
Book.Recalculate;
Book.SaveAs('model-out.xlsx');
Var förlustfri round-trip slutar
Ärlighet spelar större roll än en marknadsföringsbock här, så gränserna förtjänar samma uppmärksamhet. HotXLS kopierar inte hela paketet byte för byte: kalkylblads-XML, stilar, delade strängar och arbetsboksdelar återskapas från den tolkningsbara modellen, så utdata är semantiskt trogen men inte binärt identisk — lokala ZIP-rubriker enbart bär på nya DOS-tidsstämplar. Fångade <ext>-fragment returneras normaliserade enligt beskrivningen ovan. Programmatiska åsidosättningar av tematypsnitt ignoreras när ett ordagrant tema är närvarande. Och bevarandenätet har en definierad maskvidd: funktioner HotXLS modellerar nativt (miniatyrdiagram, till exempel, tolkas och skrivs om istället för att kopieras blint) plus utländskt extLst-innehåll samt de ordagrant cachelagrade delarna. En del som varken modelleras eller finns inuti en tilläggspunkt — till exempel en specifik del för ett exotiskt tilläggsprogram — faller utanför de tre mekanismer som denna artikel täcker, så testa dina faktiska mallar istället för att anta saker
Närliggande bevarande arbete kompletterar bilden. VBA-projekt och externa arbetsboksreferenser åtföljer sparningen enligt samma filosofi att behålla-det-du-inte-modellerar, vilket behandlas i följeslagsartikeln om bevarande av VBA och externa länkar, och dokumentegenskaper i docProps har sitt eget läs- och skriv-API istället för att tyst kastas bort. När du utvärderar ett kalkylbladsbibliotek, kör testet med en cell: öppna en funktionsrik produktionsarbetsbok, ändra ett enda värde, spara, och jämför (diffa) de uppzippade delarna mot originalet. Vad som ändrades utöver det blad du rörde berättar mer om biblioteket än någon funktionsmatris
Round-trip-mekanismerna som beskrivs här — ordagrant tema-bevarande sedan v2.89.46, fångst av utländsk extLst och utgivning av calcChain.xml sedan v2.131.0 — levereras i den aktuella HotXLS Delphi Excel Component, vars produktsida dokumenterar hela uppsättningen av XLSX-läs- och skrivfunktioner för Delphi och C++Builder