Teknisk artikel

Skriva ISO 29500 Strict XLSX-filer från Delphi

HotXLS skriver ISO/IEC 29500 Strict Open XML-arbetsböcker från Delphi och C++Builder genom att sätta en enda egenskap, StrictOOXML, före sparning. Varje del i paketet, från xl/workbook.xml ner till relationsfilerna och innehållstyperna, skrivs med de strikta purl.oclc.org-vokabulärerna istället för de övergångsvisa schemas.openxmlformats.org-vokabulärerna, och funktioner som Strict inte tillåter avvisas med ett uttryckligt undantag istället för att ändå skrivas ut

De flesta utvecklare möter detta krav via ett upphandlingsdokument. Offentliga upphandlingar i flera jurisdiktioner efterfrågar den ISO-standardiserade formen av Open XML, inte den övergångsform som Office skriver som standard, och ett arkiv som kräver ISO 29500 Strict avvisar en normal .xlsx även om Excel öppnar den perfekt. De övergångsvisa namnrymderna finns för att tillmötesgå äldre binärt beteende; de strikta är själva standarden

Vad skiljer egentligen Strict från Transitional?

Den synliga skillnaden är vokabulär. En strikt arbetsboksdel deklarerar http://purl.oclc.org/ooxml/spreadsheetml/main som sin rotnamnrymd och http://purl.oclc.org/ooxml/officeDocument/relationships för relationsreferenser, och ingen övergångsvis namnrymd får finnas kvar någonstans i paketet. Relationstyper ändras med det, så rotens relationsdel namnger .../ooxml/officeDocument/relationships/officeDocument snarare än den bekanta openxmlformats-motsvarigheten, och den utökade egenskapstypen skrivs camelCase som extendedProperties

Den osynliga skillnaden är omfattning. Strict utelämnar avsiktligt delar av det övergångsvisa schemat som bara fanns för att kunna läsas fram och tillbaka med äldre binärfiler, tillsammans med de leverantörsutökningar Office lade till senare. Det är därför konverteringen inte är en sök-och-ersätt över strängar: vissa funktioner har helt enkelt ingen strikt stavning och får inte skrivas ut alls

Att slå på det

Vanlig kod för att bygga arbetsböcker ändras inte. Bygg arbetsboken som du alltid gör, sätt flaggan och spara:

var
  Wb: TXLSXWorkbook;
  Sh: TXLSXWorksheet;
begin
  Wb := TXLSXWorkbook.Create;
  try
    Sh := Wb.Sheets.Add('Data');
    Sh.Cells[1, 1].Value := 'Product';
    Sh.Cells[1, 2].Value := 'Amount';
    Sh.Cells[2, 1].Value := 'Widget';
    Sh.Cells[2, 2].Value := 17;
    Sh.Cells[3, 2].Formula := '=SUM(B2:B2)';

    Wb.StrictOOXML := True;          // ISO/IEC 29500 Strict-utdata
    if Wb.SaveAs('archive-copy.xlsx') <> 1 then
      raise Exception.Create('strict save failed');
  finally
    Wb.Free;
  end;
end;

Flaggan återställs vid början av varje sparoperation och tilldelas på nytt från arbetsboksegenskapen, så ett undantag under en sparning kan inte läcka strikt läge in i nästa. Den detaljen spelar roll i serverprocesser där ett enda arbetsboksobjekt betjänar flera exportförfrågningar

Varför kan en strikt sparning vägra köras?

Fyra funktionsfamiljer är Microsoft-utökningar utan någon ISO 29500 Strict-motsvarighet, och HotXLS kastar ett undantag vid sparningstillfället istället för att skriva ut ett paket som hävdar strikt konformitet fast det inte är:

// Strict-utdata kan inte bädda in ett VBA-projekt
//   -> spara makroaktiverade arbetsböcker som övergångsvis .xlsm
// Strict-utdata kan inte bära formulärkontroller
//   -> knappar, kryssrutor, kombinationsrutor och deras ctrlProps
// Strict-utdata kan inte bära trådade kommentarer
//   -> den moderna persons/threads-modellen, inte klassiska anteckningar
// Strict-utdata kan inte bära metadata för dynamiska matriser
//   -> spill-intervall registrerade genom metadata-delen

Att misslyckas högljutt är rätt avvägning här. Ett tyst bortsläppt VBA-projekt förvandlar en fungerande arbetsbok till en trasig som ändå går att öppna, och rapporten om felet kommer från en användare veckor senare. Ett undantag namnger funktionen och egenskapen att ändra medan anropande kod fortfarande vet vad den exporterade. Bevarande av makron och externa länkar på den övergångsvisa vägen täcks i bevarande av VBA-projekt och externa länkar

Två utökningsfamiljer hanteras annorlunda, och det är värt att veta varför. Databalkar, sparklines och liknande funktioner lever i vokabulärerna x14 och xm, och SVG-varianterna av bilder lever i c15. Dessa är utökningslisteinnehåll vars namnrymder är självbeskrivande, allmänna kalkylbladstolkar tolererar dem, och det finns ingen ISO-motsvarighet att översätta dem till. HotXLS behåller dem istället för att kasta bort användarinnehåll. Om en validerare i din pipeline är strikt även vad gäller utökningar och inte bara namnrymder, ta bort dessa funktioner från källarbetsboken innan export

Översättningen måste nå delar ingen normalt skriver om

Det intressanta ingenjörsproblemet i strikt utdata är inte kalkylblads-XML:en. Det är de delar en snabb skrivare hellre skulle kopiera ordagrant. HotXLS bevarar teman, anslutningar, externa länkar, diagram och pivotblobbar genom att kopiera deras ursprungliga komprimerade byte rakt igenom, vilket är precis det rätta för trohet och precis det fel för strikt utdata, eftersom kopierade byte bär övergångsvisa namnrymder

Under StrictOOXML växlar dessa fem bevarade vägar till ombyggnad eller till en översättande återuppspelning, som kringgår den byte-kopierande snabbvägen. All XML går genom en enda översättningsrutin, som ankrar på citattecken-omslutna attributvärden så att en URI-liknande sträng inuti en cell aldrig kan skrivas om av misstag. Celltext som innehåller samma URI eskaperas som en entitet i XML:en, så den ankrade ersättningen kan inte se den. Den strömmande skrivaren översätter sitt skelett först och delar sedan vid sheetData, eftersom radblocken inte innehåller några vokabulär-URI:er alls. Relaterad mekanik för bevarandevägen täcks i förlustfria tur-och-returer för teman, utökningslistor och calcChain

Att läsa filer som Excel sparat som strict

Utdata är bara halva historien. Excel erbjuder "Strict Open XML Spreadsheet" som ett sparalternativ, och filer producerade på det sättet måste öppnas korrekt. HotXLS normaliserar relationstyper vid varje relationstolkningsplats i paketet, roten, externa länkar, kalkylblad, ritningar och pivottabeller, så att en strikt relationstyp matchar samma interna konstant som sin övergångsvisa motsvarighet

Motsvarigheten på läsarsidan är normalisering av namnrymdsprefix, vilket tillåter godtyckliga prefix och båda vokabulärerna att lösas till en kanonisk namntabell. Det arbetet gynnar vanliga filer lika väl som strikta, eftersom tredjepartsgeneratorer binder prefix fritt, och det är samma maskineri som beskrivs i OPC-relationsupplösning i XLSX-paket

En kort checklista innan du levererar strikt utdata

Verifiera med paketet, inte med Excel. Excel öppnar båda formerna gärna, så en lyckad öppning bevisar ingenting om konformitet. Packa upp resultatet och bekräfta att xl/workbook.xml deklarerar purl-namnrymden, att ingen del innehåller schemas.openxmlformats.org/spreadsheetml, och att relationstyperna i _rels/.rels och xl/_rels/workbook.xml.rels använder de strikta formerna

Öppna sedan filen igen via HotXLS och jämför värden, formler, format och hyperlänkar mot källan. Ett återläsningstest är det enda billiga sättet att bevisa att översättningen inte skadade innehållet, och det motionerar samtidigt normaliseringen på läsarsidan. Om dina arbetsböcker bär diagram, kontrollera dem också, eftersom diagramdelen är en av de bevarade delarna som växlar till en ombyggd väg i strikt läge

Strikt utdata, tolerant läsning och förlustfritt bevarande är alla delar av samma OOXML-motor för Delphi och C++Builder; den fullständiga funktionslistan finns på sidan för HotXLS Delphi-kalkylbladskomponent