Technisch artikel

ISO 29500 Strict XLSX-bestanden schrijven vanuit Delphi

HotXLS schrijft ISO/IEC 29500 Strict Open XML-werkmappen vanuit Delphi en C++Builder door vóór het opslaan één enkele eigenschap in te stellen, StrictOOXML. Elk onderdeel in het pakket, van xl/workbook.xml tot en met de relatiebestanden en content types, wordt geschreven met de strikte purl.oclc.org-vocabulaires in plaats van de transitionele schemas.openxmlformats.org-vocabulaires, en functies die Strict niet toestaat, worden geweigerd met een expliciete uitzondering in plaats van toch te worden weggeschreven

De meeste ontwikkelaars komen deze eis tegen via een aanbestedingsdocument. Aanbestedingen in de publieke sector in verschillende jurisdicties vragen om de ISO-gestandaardiseerde vorm van Open XML, niet de transitionele vorm die Office standaard schrijft, en een archief dat ISO 29500 Strict verplicht stelt, weigert een normaal .xlsx-bestand, ook al opent Excel het probleemloos. De transitionele namespaces bestaan om legacy binair gedrag te accommoderen; de strikte namespaces zijn de eigenlijke standaard

Wat verschilt er eigenlijk tussen Strict en Transitional?

Het zichtbare verschil is de vocabulaire. Een strikt werkmaponderdeel declareert http://purl.oclc.org/ooxml/spreadsheetml/main als root-namespace en http://purl.oclc.org/ooxml/officeDocument/relationships voor relatieverwijzingen, en geen enkele transitionele namespace mag ergens in het pakket overleven. Relatietypen veranderen mee, dus het root-relatieonderdeel noemt .../ooxml/officeDocument/relationships/officeDocument in plaats van het vertrouwde openxmlformats-equivalent, en het type voor uitgebreide eigenschappen wordt in camelCase geschreven als extendedProperties

Het onzichtbare verschil is het bereik. Strict laat bewust delen van het transitionele schema weg die alleen bestonden om legacy binaire bestanden rondtrip-compatibel te maken, samen met de leveranciersextensies die Office er later aan toevoegde. Daarom is de conversie geen zoek-en-vervang-actie over strings: sommige functies hebben simpelweg geen strikte spelling en mogen helemaal niet worden geschreven

Het inschakelen

Gewone code voor het opstellen verandert niet. Bouw de werkmap zoals u altijd doet, stel de vlag in en sla op:

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-uitvoer
    if Wb.SaveAs('archive-copy.xlsx') <> 1 then
      raise Exception.Create('strict save failed');
  finally
    Wb.Free;
  end;
end;

De vlag wordt aan het begin van elke opslagbewerking gereset en opnieuw toegewezen vanuit de werkmapeigenschap, zodat een uitzondering tijdens de ene opslagbewerking geen strikte modus kan laten doorlekken naar de volgende. Dat detail doet ertoe in serverprocessen waar één werkmapobject meerdere exportverzoeken bedient

Waarom kan een strikte opslag weigeren te draaien?

Vier functiefamilies zijn Microsoft-extensies zonder ISO 29500 Strict-equivalent, en HotXLS werpt bij het opslaan een uitzondering in plaats van een pakket te produceren dat strikte conformiteit claimt terwijl dat niet zo is:

// Strict-uitvoer kan geen VBA-project insluiten
//   -> sla macro-ingeschakelde werkmappen op als transitioneel .xlsm
// Strict-uitvoer kan geen formuliercontrols dragen
//   -> knoppen, selectievakjes, keuzelijsten en hun ctrlProps
// Strict-uitvoer kan geen threaded comments dragen
//   -> het moderne persons/threads-model, niet klassieke notities
// Strict-uitvoer kan geen metadata voor dynamische arrays dragen
//   -> spill-bereiken vastgelegd via het metadata-onderdeel

Luid falen is hier de juiste afweging. Een stilzwijgend weggevallen VBA-project verandert een werkende werkmap in een kapotte werkmap die nog steeds opent, en het foutrapport komt weken later binnen via een gebruiker. Een uitzondering benoemt de functie en de eigenschap die moet worden gewijzigd, terwijl de aanroepende code nog weet wat ze aan het exporteren was. Behoud van macro's en externe links op het transitionele pad wordt behandeld in het behouden van VBA-projecten en externe links

Twee extensiefamilies worden anders behandeld, en het is de moeite waard om te weten waarom. Databalken, sparklines en vergelijkbare functies bevinden zich in de x14- en xm-vocabulaires, en de SVG-varianten van afbeeldingen bevinden zich in c15. Dit is extension-list-inhoud waarvan de namespaces zelfbeschrijvend zijn, algemene spreadsheetparsers tolereren ze, en er is geen ISO-equivalent om ze naar te vertalen. HotXLS behoudt ze in plaats van gebruikersinhoud te laten vallen. Als een validator in uw pijplijn even strikt is over extensies als over namespaces, verwijder die functies dan uit de bronwerkmap vóór het exporteren

Vertaling moet onderdelen bereiken die niemand normaal herschrijft

Het interessante technische probleem bij strikte uitvoer is niet de werkblad-XML. Het zijn de onderdelen die een snelle writer liever letterlijk zou kopiëren. HotXLS behoudt thema's, verbindingen, externe links, grafieken en draaitabel-blobs door hun originele gecomprimeerde bytes rechtstreeks door te kopiëren, wat precies het juiste is voor getrouwheid en precies het verkeerde voor strikte uitvoer, omdat gekopieerde bytes transitionele namespaces met zich meedragen

Onder StrictOOXML schakelen die vijf behouden paden over naar herbouw of naar een vertalende replay, waarbij het snelle byte-kopieerpad wordt omzeild. Alle XML gaat door één vertaalroutine, die verankert op dubbel aangehaalde attribuutwaarden, zodat een string die op een URI lijkt binnen een cel nooit per ongeluk kan worden herschreven. Celtekst die dezelfde URI bevat, wordt in de XML geëscaped als entiteit, zodat de verankerde vervanging deze niet kan zien. De streaming writer vertaalt eerst zijn skelet en splitst dan bij sheetData, omdat de rijblokken helemaal geen vocabulaire-URI's bevatten. Verwante mechanica voor het behoudpad wordt behandeld in verliesvrije round-trips van thema's, extension lists en calcChain

Bestanden lezen die Excel als strict heeft opgeslagen

Uitvoer is maar het halve verhaal. Excel biedt "Strict Open XML Spreadsheet" als opslagoptie, en bestanden die op die manier zijn geproduceerd, moeten correct openen. HotXLS normaliseert relatietypen op elke plek in het pakket waar relaties worden geparst: de root, externe links, werkbladen, tekeningen en draaitabellen, zodat een strikt relatietype overeenkomt met dezelfde interne constante als zijn transitionele tegenhanger

De tegenhanger aan de lezerskant is normalisatie van namespace-prefixen, waardoor willekeurige prefixen en beide vocabulaires kunnen worden herleid tot één canonieke naamtabel. Dat werk komt zowel gewone als strikte bestanden ten goede, aangezien generatoren van derden prefixen vrij toekennen, en het is dezelfde machinerie beschreven in OPC-relatieresolutie in XLSX-pakketten

Een korte checklist voordat u strikte uitvoer uitlevert

Verifieer met het pakket, niet met Excel. Excel opent beide vormen probleemloos, dus een succesvolle opening bewijst niets over conformiteit. Pak het resultaat uit en bevestig dat xl/workbook.xml de purl-namespace declareert, dat geen enkel onderdeel schemas.openxmlformats.org/spreadsheetml bevat, en dat relatietypen in _rels/.rels en xl/_rels/workbook.xml.rels de strikte vormen gebruiken

Open het bestand vervolgens opnieuw via HotXLS en vergelijk waarden, formules, opmaak en hyperlinks met de bron. Een terugleestest is de enige goedkope manier om te bewijzen dat de vertaling de inhoud niet heeft beschadigd, en oefent tegelijk de normalisatie aan de lezerskant. Als uw werkmappen grafieken bevatten, controleer die ook, aangezien het grafiekonderdeel een van de behouden onderdelen is dat onder strikte modus overschakelt naar een herbouwd pad

Strikte uitvoer, tolerante lezing en verliesvrij behoud maken allemaal deel uit van dezelfde OOXML-engine voor Delphi en C++Builder; de volledige functielijst staat op de HotXLS Delphi-spreadsheetcomponentpagina