HotXLS, det opprinnelige Excel-biblioteket for Delphi og C++Builder, er bygd for tapsfrie XLSX-tur-returer: åpne en arbeidsbok, endre én celle, lagre, og kundens tilpassede tema, fremmede extLst-utvidelsesblokker og beregningskjede (calculation chain) vil alle overleve. Tre mekanismer gjør at dette fungerer — ordrett bufring av xl/theme/theme1.xml, hendelsesbasert re-serialisering av ukjente <ext>-blokker og en ny, spesifikasjonsgyldig xl/calcChain.xml ved hver lagring av en formelarbeidsbok
Scenarioet som motiverer alle tre er deprimerende vanlig. En faktureringstjeneste laster inn en mal kunden har utformet i Excel — bedriftens fargetema, miniatyrdiagrammer (sparklines) i en KPI-kolonne, en betinget formateringsregel lagt til av en nyere Excel-versjon — skriver én fakturasum inn i celle B3, og lagrer. Kunden åpner resultatet, og merkevarefargene har gått tilbake to standard Office-blå, miniatyrdiagrammene er borte, og Excel tilbyr å "reparere" filen. Ingenting i koden berørte noen av disse funksjonene. Det gjorde biblioteket, ganske enkelt ved å lagre
Hvorfor mister Excel-filer formatering etter redigering med et bibliotek?
Excel-filer mister formatering etter redigering med et bibliotek fordi de fleste biblioteker ikke redigerer filen — de bygger den opp på nytt. En .xlsx-pakke er en ZIP med XML-deler: xl/workbook.xml, én xl/worksheets/sheetN.xml per ark, xl/styles.xml, xl/theme/theme1.xml, xl/calcChain.xml, med mer. Et typisk bibliotek tolker disse delene inn i en objektmodell ved åpning, og regenererer hver del fra den modellen ved lagring. Enhver funksjon modellen ikke representerer — et tema den aldri tolket, en utvidelsesblokk fra en nyere Excel — har ingen steder å leve i minnet, så den regenererte delen utelater den lydløst
ECMA-376 forutså halvparten av dette problemet. SpreadsheetML definerer extLst (ECMA-376 del 1, "Future Feature Data Storage Area", §18.2.10 for elementet på arbeidsboknivå) som et utpekt utvidelsespunkt: nyere produsenter plasserer funksjoner der, hver pakket inn i et <ext>-element som bærer et uri-attributt som identifiserer funksjonen, og eldre forbrukere forventes å bevare det de ikke forstår. Miniatyrdiagrammer, utsnitt (slicers) og nyere betingede formateringstyper overføres alle på denne måten. Et bibliotek som kaster ukjente <ext>-blokker er derfor ikke bare ufullstendig — det bryter fremoverkompatibilitets-kontrakten som formatet ble designet rundt. Spørsmålet du må stille til et hvilket som helst regnearkbibliotek du vurderer er kontant: hvis jeg endrer én celle, hva annet endres
Hvordan beholder HotXLS et tilpasset tema byte for byte?
HotXLS bevarer en arbeidsboks tema ved å bufre de opprinnelige bytene til xl/theme/theme1.xml ved åpningstidspunktet og skrive dem tilbake ordrett ved lagringstidspunktet. Temadelen (ECMA-376 del 1, §14.2.7) er DrawingML, ikke SpreadsheetML — fargevalg, skriftvalg, formatvalg — og en regnearkmotor har ingen grunn til å modellere den i dybden. Tidligere HotXLS-versjoner regenererte et fast Office-tema ved hver lagring, noe som er nøyaktig "merkevarefargene gikk tilbake"-feilen ovenfor; siden v2.89.46 lagres det åpnede pakketemaet rått og sendes uendret ut igjen, og det innebygde Office-temaet genereres bare for arbeidsbøker opprettet fra bunnen av. Rå byte er den sterkest mulige garantien for nøyaktighet: ingen tolking, ingen re-serialisering, ingen sjanse for avvik
Den ordrette kopien vinner bevisst over programmatisk tematilgang. TXLSXWorkbook eksponerer ThemeMajorFont og ThemeMinorFont slik at du kan velge skrifttyper for overskrift og brødtekst for nye arbeidsbøker, men når et ordrett tema ble fanget opp ved åpning, har ikke disse setterne noen effekt på den lagrede filen — tur-returen har prioritet. Hvis du virkelig trenger å endre en eksisterende arbeidsboks tema, er det et signal om å redigere malen i Excel selv i stedet for via et datalorientert API. Det vanlige tilfellet trenger ikke noe API i det hele tatt:
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('branded-invoice.xlsx');
Book.Sheets[0].Cells[3, 2].Value := 42750.00; // the one edit
Book.SaveAs('branded-invoice-out.xlsx');
// theme1.xml in the output is byte-identical to the input
finally
Book.Free;
end;
end;
Hva skjer med ukjente extLst-blokker ved lagring?
HotXLS fanger opp hver <ext>-blokk på regnearknivå den ikke modellerer innfødt, og spiller den av igjen i det lagrede regnearkets extLst, slik at funksjoner skrevet av nyere Excel-versjoner overlever tur-returen intakt. Siden v2.131.0 er de fangede fragmentene synlige via den skrivebeskyttede egenskapen RawWorksheetExts, en TStringList på hvert XLSX-regneark, noe som gjør garantien kontrollerbar fra testkode fremfor å være en tillitssak:
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)); // peek at each uri
finally
Book.Free;
end;
end;
Implementasjonsdetaljen det er verdt å kjenne til er at fangingen er en re-serialisering på hendelsesnivå, ikke en rå bytekopi. HotXLS' strømmende XML-leser eksponerer ingen kilde-forskyvninger, så det ukjente undertreet bygges opp på nytt fra Element-, Text- og EndElement-hendelser etter hvert som de strømmer forbi. Den tilnærmingen skjuler en klassisk felle: et selvlukkende element som <a/> utløser bare en Element-hendelse merket tom, og aldri en EndElement, så enhver dybdeteller som dekrementerer utelukkende på EndElement vil aldri se undertreet lukkes. Håndter det, og det gjenoppbygde fragmentet er semantisk ekvivalent med originalen — attributt-anførselstegn og selvlukkende former normaliseres, så det er ikke byte-identisk, men Excel leser mening, ikke byte. To egenskaper ved Excels egne utdata gjør avspillingen trygg: Excel erklærer de nødvendige xmlns-attributtene på <ext>-elementet eller inne i det, så hvert fangede fragment er selvstendig med hensyn til navnerom (namespace), og den samme selvstendigheten er grunnen til at duplisering av et regneark innenfor eller på tvers av arbeidsbøker kan bære med seg de fremmede blokkene med en enkel string-list assign
Skrive calcChain.xml slik at Excel stoler på formlene dine
HotXLS skriver xl/calcChain.xml (Calculation Chain-delen, ECMA-376 del 1, §12.3.1) når den lagrede arbeidsboken inneholder formler, og den velger mellom to sorteringer. Hvis formelavhengighetsgrafen allerede er bygd og er gjeldende — du kalte Recalculate etter den siste redigeringen — sendes kjeden ut i full topologisk rekkefølge, avhengigheter før avhengige, med eventuelle sirkulære referansemedlemmer lagt til på slutten. Ellers listes cellene i dokumentrekkefølge. Begge er riktige: Microsofts implementasjonsmerknader for formatet, [MS-XLSX], behandler beregningskjeden som et hint Excel verifiserer og reorganiserer under innlasting, så enhver opplisting er lovlig, og HotXLS nekter bevisst å tvinge frem et grafbygg inne i SaveAs — kantkonstruksjon er kvadratisk i celleantall, en uakseptabel skjult kostnad ved lagring av en million celler
Hvorfor bry seg om en del Excel behandler som rådgivende? Fordi dens fravær er et signal. Noen forbrukere — reparasjonsheuristikker, tredjepartsvisere, sammenligningsverktøy — forventer at en formelarbeidsbok har en beregningskjede, og et bibliotek som lydløst dropper delen ved lagring produserer filer som er litt ulikt alt Excel skriver. Å sende ut en gyldig kjede holder utdataene innenfor rammene av det resten av økosystemet har blitt testet mot, noe som er den stille, lite glamorøse kjernen i tur-retur-utvikling
Hvor tapsfri tur-retur slutter
Ærlighet betyr mer enn en avkrysningsboks for markedsføring her, så grensene fortjener like mye plass. HotXLS kopierer ikke hele pakken byte for byte: regneark-XML, stiler, delte strenger og arbeidsbokdeler regenereres fra den tolkedde modellen, så utdataene er semantisk troverdige, men ikke binært identiske — ZIP-lokale headere bærer alene friske DOS-tidsstempler. Fangede <ext>-fragmenter kommer tilbake normalisert, som beskrevet ovenfor. Programmatiske temaskrift-overstyringer ignoreres når et ordrett tema er til stede. Og bevaringsnettet har en definert maskevidde: funksjoner HotXLS modellerer innfødt (miniatyrdiagrammer, for eksempel, tolkes og skrives om i stedet for å bli blindt kopiert) pluss fremmed extLst-innhold pluss de ordrett-bufrede delene. En del som verken er modellert eller befinner seg innenfor et utvidelsespunkt — en eksotisk tilleggsfunksjons tilpassede del, for eksempel — faller utenfor de tre mekanismene denne artikkelen dekker, så test dine faktiske maler i stedet for å anta
Tilstøtende bevaringsarbeid fullfører bildet. VBA prosjekter og eksterne arbeidsbokreferanser overlever lagring på samme "behold det du ikke modellerer"-filosofi, dekket i ledsagerartikkelen om bevaring av VBA og eksterne lenker, og dokumentegenskaper i docProps har sitt eget lese-skrive-API i stedet for å bli lydløst droppet. Når du evaluerer et regnearkbibliotek, kjør én-celle-testen: åpne en funksjonsrik produksjonsarbeidsbok, endre en enkelt verdi, lagre, og sammenlign de utpakkede delene mot originalen. Hva som ble endret utover arket du berørte, forteller deg mer om biblioteket enn noen funksjonsmatrise
Tur-retur-mekanismene beskrevet her — ordrett temabevaring siden v2.89.46, fanging av fremmede extLst og utsendelse av calcChain.xml siden v2.131.0 — leveres i gjeldende HotXLS Delphi Excel Component, hvis produktside dokumenterer det fullstendige lese- og skrivefunksjonssettet for XLSX for Delphi og C++Builder