Teknisk artikkel

Åpne og lagre ODS-regneark i Delphi med HotXLS

En Delphi-rapporteringsbackend som har sendt ut .xlsx i årevis, får et nytt krav: en offentlig sektor-kundes anskaffelsesregler krever OpenDocument Spreadsheet-utdata, og analytikerne på den kontoen sender redigeringene sine tilbake som .ods-filer lagret fra LibreOffice. Så nå må samme kode skrive ODS og lese den. HotXLS, losLabs native Object Pascal-regnearkbibliotek for Delphi og C++Builder, håndterer begge retningene uten at Excel eller LibreOffice er installert noe sted. Det den ikke gjør, er å gjøre de to retningene symmetriske. Eksport bærer langt mer enn import gjenoppretter, og et team som antar noe annet, vil se formler og formatering fordampe et sted mellom kundens revisjon og neste rapport, uten noen feilmelding å peke på

ODS-støtte bor på XLSX-fasaden, ikke XLS-en

HotXLS leverer to uavhengige klassehierarkier i én enkelt pakke: TXLSWorkbook i enheten lxHandle for binære BIFF8 .xls-filer, og TXLSXWorkbook i enheten lxHandleX for OOXML .xlsx-pakker. Hvert OpenDocument-inngangspunkt - OpenODS, SaveAsODS, GetODSSheetNames - henger på TXLSXWorkbook. Plasseringen er ikke vilkårlig. En ODS-pakke, som spesifisert i OASIS ODF 1.3, er et zip-arkiv som bærer et mimetype-medlem, en manifest og en content.xml-kropp, noe som gjør den til en strukturell fetter av OOXML-zip-en; BIFF8 er en binær poststrøm fra 1990-tallet uten noe til felles

Den plasseringen har en praktisk kant: en gammel .xls-arbeidsbok kan ikke bli .ods i ett kall. Du bygger bro over BIFF-innholdet inn i XLSX-modellen først, med SaveXLSWorkbookAsXLSX fra enheten lxXlsxExport, åpner resultatet på nytt gjennom TXLSXWorkbook, og eksporterer deretter derfra. Broen er ikke tapsfri, og det er verdt å kjenne gapene før du bygger på den. Den kopierer verdier, formler, tallformater, fonter, fyll og kolonnebredder. Den dropper kanter, sammenslåtte områder, kommentarer, diagrammer og betinget formatering. En .xls-kilde med tung formatering vil nå ODS og se mer nøkternt ut enn den forlot, og det er en egenskap ved broen, ikke ved ODS-skriveren

Deteksjon på importsiden er automatisk. Den vanlige Open-metoden gjenkjenner en ODS-pakke på mimetype-medlemmet, og faller tilbake til en toppnivå-content.xml-sjekk når det medlemmet mangler, så en generisk «åpne hva enn brukeren lastet opp»-kodesti trenger ingen egen filendelsesnusing. Etter åpning rapporterer SourceFormat-egenskapen hvilken gren som utløste

Diagram over HotXLS klasseoppsett i Delphi der hvert ODS-inngangspunkt bor på TXLSXWorkbook, og en SaveXLSWorkbookAsXLSX-bro bærer BIFF8 .xls-innhold over
Hvert OpenDocument-inngangspunkt henger på TXLSXWorkbook, og en eldre .xls når ODS bare gjennom den tapsfulle BIFF-til-XLSX-broen

Å eksportere til ODS med TODSExportOptions

Selve eksportkallet er én linje; alternativobjektet rundt det bærer beslutningene en gjennomgår vil spørre om senere:

var
  Book: TXLSXWorkbook;
  Opts: TODSExportOptions;
begin
  Book := TXLSXWorkbook.Create;
  try
    Book.Open('quarterly-report.xlsx');
    Opts := TODSExportOptions.Create;        // den som kaller, eier og frigjør denne
    try
      Opts.Generator := 'ReportService 4.2'; // meta:generator-overstyring
      Opts.IncludeCharts := True;
      Opts.IncludeImages := True;
      Book.SaveAsODS('quarterly-report.ods', Opts);
    finally
      Opts.Free;
    end;
  finally
    Book.Free;
  end;
end;

Alternativobjektet eies av den som kaller. HotXLS vil ikke frigjøre det, som er hvorfor den indre try..finally-en er der og ikke valgfri. De to egenskapene som endrer utdataene, snarere enn bare å merke dem, er verdt et nærmere blikk. Å sette IncludeCharts := False gjør mer enn å skjule diagrammer: det fjerner diagram-underdokumentene og manifestoppføringene deres ut av pakken, noe som er akkurat det du vil ha når konsumenten er en datapipeline som ville snuble over dem. Generator overstyrer ODF meta:generator-strengen, som ellers leser HotXLS/<version>; overstyr den når nedstrøms verktøy fingeravtrykker filprodusenter for å rute support. Hvis ingenting av det gjelder, hopp over alternativobjektet helt. Å kalle SaveAs(FileName, xlsxOpenDocumentSpreadsheet) er det samme som SaveAsODS med standardverdier, og strømoverbelastninger på begge lar deg skrive pakken rett inn i et HTTP-svar uten midlertidig fil

Hva importstien leser - og hva den bevisst hopper over

Les denne delen nøye før du lover noen tur-retur-trofasthet. ODS-import i HotXLS er bevisst en lettvektssti. Den bevarer skalare celleverdier og det bufrede resultatet hver formel bar ved lagringstidspunktet, og den utvider gjentatte rader og kolonner ut i rutenettet. Den bringer ikke over stiler, ODS-formeluttrykk eller tegninger

Formelvalget er det som mest sannsynlig vil bite, og det ble tatt med hensikt. En ODF-celle lagrer to ting side om side: formeluttrykket, skrevet i OpenFormula-dialekten definert i ODF 1.3 del 4, og den siste verdien det produserende programmet beregnet for den. Å oversette OpenFormula til Excel-formelsyntaks er sitt eget dialekt-konverteringsproblem, med reelle grensetilfeller rundt funksjonsvokabularer, referansesyntaks og feilmodeller. Å lese den bufrede verdien i stedet unngår hele den klassen av stille feiloversettelse, så tallene du importerer, er nøyaktig de tallene avsenderen sist så. Kostnaden er at de ankommer som tall, ikke som de levende formlene som produserte dem

Feilmodusen å designe rundt følger direkte: et regneark hvis totaler var korrekte da LibreOffice sist lagret det, importeres med korrekte tall, men de tallene er nå konstanter. Rediger en inndatacelle, beregn på nytt, og ingenting rører seg - formelen er borte, bare sluttresultatet dens gjenstår. Hvis arbeidsflyten trenger levende formler etter import, gjenoppbygg dem programmatisk fra dine egne forretningsregler gjennom Cell.Formula, som på XLSX-fasaden tar uttrykket uten en innledende likhetstegn

Å designe rundt den asymmetriske tur-returen

Eksport gjengir fra den fulle arbeidsbokmodellen i minnet: verdier, stiler, og, hvis du ber om dem, diagrammer og bilder. Import returnerer bare verdier. Så .xlsx-til-.ods-strekket er høy troskap, og .ods-til-.xlsx-strekket bringer tilbake verdier og bufrede resultater, men ingen stiling og ingen levende formler. Kjed de to sammen, og asymmetrien forsterkes. En full .xlsx-til-.ods-til-.xlsx-syklus skriver alt trofast på vei ut og mister stilene og formlene på vei tilbake inn, selv om ingenting gikk galt i noe av trinnene

Diagram over den asymmetriske HotXLS ODS tur-retur fra Delphi: fulltrohetseksport fra arbeidsbokmodellen i minnet, og en kun-verdier-import som lar formler forbli som konstanter
Eksport rendrer hele i-minne-modellen mens import returnerer verdier og hurtigbufrede resultater, så en full .xlsx-til-.ods-til-.xlsx-syklus slipper stiler og levende formler i stillhet
Book := TXLSXWorkbook.Create;
try
  Book.Open('vendor-revision.ods');          // format automatisk gjenkjent
  if Book.SourceFormat = xlsxOpenDocumentSpreadsheet then
  begin
    // Verdier og bufrede formelresultater er til stede etter en ODS-
    // import; stiler og levende formler er ikke det. Gjenoppbygg hva enn
    // nedstrøms-pipelinen er avhengig av, før lagring.
    Book.Sheets[0].Cells[2, 5].Formula := 'SUM(B2:D2)';
    Book.SaveAs('vendor-revision.xlsx');
  end;
finally
  Book.Free;
end;

Det arkitektoniske mønsteret som faller ut av dette: behandle innkommende .ods-filer som datafeeder, ikke som dokumenter å redigere på stedet. Hold den kanoniske arbeidsboken i .xlsx, les verdier ut av kunderevisjoner, og send ut fersk ODS på forespørsel fra den kanoniske kopien. Verifisering hører hjemme i begge leire - åpne eksporterte filer i LibreOffice Calc, referanse-ODF-konsumenten, og i Excel, som har lest ODS i årevis, men er uenig med LibreOffice i ytterkantene av diagram- og stilstøtte. Arkantall, en håndfull nøkkelceller og diagramtilstedeværelse utgjør en tilstrekkelig røyktest per eksportprofil

Å triagere en ODS-fil før du forplikter deg til en import

Når et endepunkt godtar opplastinger, er det å liste arknavn langt billigere enn en full parsing, og det fanger strukturelle overraskelser tidlig:

Diagram over HotXLS opplastings-triageport i Delphi der GetODSSheetNames avviser uleselige ODS-pakker og manglende ark før en full import kjører
En GetODSSheetNames-probe koster langt mindre enn en full parse og fanger omdøpt-ark-feilen mens feilen fortsatt kan navngi filen
Names := TStringList.Create;
Book := TXLSXWorkbook.Create;
try
  if Book.GetODSSheetNames('incoming.ods', Names) <= 0 then
    raise Exception.Create('not a readable ODS package');
  if Names.IndexOf('Data') < 0 then
    raise Exception.Create('revision is missing the Data sheet');
finally
  Book.Free;
  Names.Free;
end;

Returkonvensjonen snubler folk: HotXLS-kall returnerer generelt et positivt antall eller 1 ved suksess og -1 ved feil, og tømmer listen når de feiler, så test <= 0 i stedet for å sammenligne mot én spesifikk positiv verdi. GetODSSheetNames verken nullstiller eller fyller ut arbeidsbokinstansen, så ett enkelt sondeobjekt kan sjekke en hel mappe med innkommende filer. Strukturelle sjekker som dette fanger den vanligste virkelige feilen - en analytiker som gir nytt navn til eller sletter et ark før revisjonen sendes tilbake - ved porten, der feilmeldingen fortsatt kan navngi filen og det manglende arket i stedet for å dukke opp som en nil-referanse tre lag dypere

Hvis du bygger en bredere konverteringspipeline rundt dette, viser mønsteret for arbeidsbok-revisjon og konverteringsverksted hvordan du inventarerer en fils funksjoner før du velger et målformat, og veiledningen for ytelse på store arbeidsbøker holder batcheksporter innenfor fornuftige minnegrenser

HotXLS er et nativt regnearkbibliotek for Delphi og C++Builder med full kildekode; den fullstendige funksjonslisten og lisensdetaljene finnes på HotXLS Delphi Component-produktsiden