Articolo tecnico

Scrivere file XLSX ISO 29500 Strict da Delphi

HotXLS scrive cartelle di lavoro Open XML ISO/IEC 29500 Strict da Delphi e C++Builder impostando una singola proprietà, StrictOOXML, prima del salvataggio. Ogni parte del pacchetto, da xl/workbook.xml fino ai file di relazione e ai content type, viene scritta con i vocabolari strict purl.oclc.org anziché quelli transitional schemas.openxmlformats.org, e le funzionalità che Strict non permette vengono rifiutate con un'eccezione esplicita anziché scritte comunque

La maggior parte degli sviluppatori incontra questo requisito attraverso un documento di appalto. I bandi del settore pubblico in diverse giurisdizioni richiedono la forma standardizzata ISO di Open XML, non la forma transitional che Office scrive per impostazione predefinita, e un archivio che impone ISO 29500 Strict rifiuterà un normale .xlsx anche se Excel lo apre perfettamente. I namespace transitional esistono per accomodare il comportamento binario legacy; quelli strict sono lo standard vero e proprio

Cosa differisce realmente tra Strict e Transitional?

La differenza visibile è il vocabolario. Una parte workbook strict dichiara http://purl.oclc.org/ooxml/spreadsheetml/main come namespace radice e http://purl.oclc.org/ooxml/officeDocument/relationships per i riferimenti di relazione, e nessun namespace transitional può sopravvivere in alcun punto del pacchetto. I tipi di relazione cambiano di conseguenza, quindi la parte delle relazioni radice si chiama .../ooxml/officeDocument/relationships/officeDocument anziché il familiare equivalente openxmlformats, e il tipo delle proprietà estese è in camelCase come extendedProperties

La differenza invisibile è l'ambito. Strict omette deliberatamente le parti dello schema transitional che esistevano solo per il round-trip dei file binari legacy, insieme alle estensioni proprietarie che Office ha aggiunto in seguito. Ecco perché la conversione non è una ricerca e sostituzione di stringhe: alcune funzionalità semplicemente non hanno una grafia strict e non devono essere scritte affatto

Attivarlo

Il codice di scrittura ordinario non cambia. Costruisci la cartella di lavoro come fai sempre, imposta il flag e salva:

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

Il flag viene azzerato all'inizio di ogni operazione di salvataggio e riassegnato dalla proprietà della cartella di lavoro, così un'eccezione durante un salvataggio non può propagare la modalità strict al successivo. Questo dettaglio conta nei processi server dove un singolo oggetto workbook serve più richieste di esportazione

Perché un salvataggio strict può rifiutarsi di essere eseguito?

Quattro famiglie di funzionalità sono estensioni Microsoft senza equivalente ISO 29500 Strict, e HotXLS solleva un'eccezione al momento del salvataggio anziché emettere un pacchetto che dichiara conformità strict senza esserlo davvero:

// L'output Strict non può incorporare un progetto VBA
//   -> salva le cartelle di lavoro con macro come .xlsm transitional
// L'output Strict non può contenere controlli modulo
//   -> pulsanti, caselle di controllo, caselle combinate e le loro ctrlProps
// L'output Strict non può contenere commenti in thread
//   -> il modello moderno persons/threads, non le note classiche
// L'output Strict non può contenere metadati di array dinamici
//   -> intervalli di spill registrati tramite la parte dei metadati

Fallire rumorosamente è il compromesso giusto qui. Un progetto VBA scartato silenziosamente trasforma una cartella di lavoro funzionante in una rotta che comunque si apre, e la segnalazione del problema arriva da un utente settimane dopo. Un'eccezione indica la funzionalità e la proprietà da modificare mentre il codice chiamante sa ancora cosa stava esportando. La preservazione di macro e collegamenti esterni sul percorso transitional è trattata in preservare progetti VBA e collegamenti esterni

Due famiglie di estensioni vengono gestite diversamente, ed è utile sapere perché. Barre dei dati, sparkline e funzionalità simili risiedono nei vocabolari x14 e xm, e le varianti SVG delle immagini risiedono in c15. Si tratta di contenuto di extension list i cui namespace sono autodescrittivi, i parser generici di fogli di calcolo li tollerano, e non esiste un equivalente ISO in cui tradurli. HotXLS li mantiene anziché scartare contenuto dell'utente. Se un validatore nella tua pipeline è rigoroso anche sulle estensioni oltre che sui namespace, rimuovi quelle funzionalità dalla cartella di lavoro sorgente prima dell'esportazione

La traduzione deve raggiungere parti che normalmente nessuno riscrive

Il problema ingegneristico interessante nell'output strict non è l'XML del foglio di lavoro. Sono le parti che uno scrittore veloce preferirebbe copiare letteralmente. HotXLS preserva temi, connessioni, collegamenti esterni, grafici e blob delle tabelle pivot copiando direttamente i loro byte compressi originali, il che è esattamente la cosa giusta da fare per la fedeltà ed esattamente la cosa sbagliata per l'output strict, perché i byte copiati portano namespace transitional

Sotto StrictOOXML quei cinque percorsi preservati passano alla ricostruzione o a una riproduzione traducente, bypassando il percorso rapido di copia dei byte. Tutto l'XML passa attraverso un'unica routine di traduzione, che si ancora ai valori di attributo tra doppi apici, così una stringa che sembra un URI dentro una cella non può mai essere riscritta per errore. Il testo di cella che contiene lo stesso URI viene sfuggito come entità nell'XML, quindi la sostituzione ancorata non può vederlo. Lo scrittore in streaming traduce prima il proprio scheletro e poi si divide a sheetData, poiché i blocchi di riga non contengono affatto URI di vocabolario. Le meccaniche correlate per il percorso di preservazione sono trattate in round-trip lossless di temi, extension list e calcChain

Leggere file che Excel ha salvato come strict

L'output è solo metà della storia. Excel offre "Foglio di calcolo Strict Open XML" come opzione di salvataggio, e i file prodotti in quel modo devono aprirsi correttamente. HotXLS normalizza i tipi di relazione in ogni punto di parsing delle relazioni nel pacchetto, la radice, i collegamenti esterni, i fogli di lavoro, i disegni e le tabelle pivot, così un tipo di relazione strict corrisponde alla stessa costante interna della sua controparte transitional

La controparte lato lettura è la normalizzazione dei prefissi di namespace, che permette a prefissi arbitrari e a entrambi i vocabolari di risolversi in un'unica tabella di nomi canonica. Questo lavoro avvantaggia sia i file ordinari sia quelli strict, poiché i generatori di terze parti associano i prefissi liberamente, ed è lo stesso meccanismo descritto in risoluzione delle relazioni OPC nei pacchetti XLSX

Una breve checklist prima di distribuire output strict

Verifica con il pacchetto, non con Excel. Excel apre volentieri entrambe le forme, quindi un'apertura riuscita non prova nulla sulla conformità. Decomprimi il risultato e conferma che xl/workbook.xml dichiara il namespace purl, che nessuna parte contiene schemas.openxmlformats.org/spreadsheetml, e che i tipi di relazione in _rels/.rels e xl/_rels/workbook.xml.rels usano le forme strict

Poi riapri il file tramite HotXLS e confronta valori, formule, formati e collegamenti ipertestuali rispetto alla sorgente. Un test di rilettura è l'unico modo economico per dimostrare che la traduzione non ha danneggiato il contenuto, e mette alla prova contemporaneamente la normalizzazione lato lettura. Se le tue cartelle di lavoro contengono grafici, controlla anche quelli, poiché la parte del grafico è una delle parti preservate che passa a un percorso ricostruito in modalità strict

Output strict, lettura tollerante e preservazione lossless fanno tutti parte dello stesso motore OOXML per Delphi e C++Builder; l'elenco completo delle funzionalità si trova nella pagina del componente foglio di calcolo Delphi HotXLS