Article technique

Écrire des fichiers XLSX ISO 29500 Strict depuis Delphi

HotXLS écrit des classeurs Open XML ISO/IEC 29500 Strict depuis Delphi et C++Builder en définissant une seule propriété, StrictOOXML, avant l'enregistrement. Chaque partie du package, de xl/workbook.xml jusqu'aux fichiers de relations et aux types de contenu, est écrite avec les vocabulaires stricts purl.oclc.org plutôt qu'avec les vocabulaires transitoires schemas.openxmlformats.org, et les fonctionnalités que Strict n'autorise pas sont rejetées par une exception explicite plutôt qu'écrites malgré tout

La plupart des développeurs rencontrent cette exigence via un document d'appel d'offres. Les marchés publics de plusieurs juridictions demandent la forme normalisée ISO d'Open XML, et non la forme transitoire qu'Office écrit par défaut, et une archive qui impose ISO 29500 Strict rejettera un .xlsx normal même si Excel l'ouvre parfaitement. Les espaces de noms transitoires existent pour accommoder le comportement binaire hérité ; les espaces stricts sont la norme proprement dite

Que change réellement entre Strict et Transitional ?

La différence visible est le vocabulaire. Une partie de classeur strict déclare http://purl.oclc.org/ooxml/spreadsheetml/main comme espace de noms racine et http://purl.oclc.org/ooxml/officeDocument/relationships pour les références de relations, et aucun espace de noms transitoire ne peut subsister où que ce soit dans le package. Les types de relations changent avec, de sorte que la partie racine des relations nomme .../ooxml/officeDocument/relationships/officeDocument plutôt que l'équivalent familier openxmlformats, et le type des propriétés étendues est en camelCase, extendedProperties

La différence invisible est le périmètre. Strict omet délibérément les parties du schéma transitoire qui n'existaient que pour faire des allers-retours avec les fichiers binaires hérités, ainsi que les extensions vendeur ajoutées ensuite par Office. C'est pourquoi la conversion n'est pas une simple recherche-remplacement de chaînes : certaines fonctionnalités n'ont tout simplement aucune écriture stricte et ne doivent pas être écrites du tout

Activer le mode

Le code d'écriture ordinaire ne change pas. Construisez le classeur comme d'habitude, positionnez l'indicateur, et enregistrez :

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

L'indicateur est réinitialisé au début de chaque opération d'enregistrement et réaffecté à partir de la propriété du classeur, de sorte qu'une exception pendant un enregistrement ne peut pas laisser fuir le mode strict vers le suivant. Ce détail compte dans les processus serveur où un seul objet classeur sert plusieurs demandes d'export

Pourquoi un enregistrement strict peut-il refuser de s'exécuter ?

Quatre familles de fonctionnalités sont des extensions Microsoft sans équivalent ISO 29500 Strict, et HotXLS déclenche une exception au moment de l'enregistrement plutôt que d'émettre un package qui prétend à la conformité stricte sans l'être :

// La sortie Strict ne peut pas intégrer de projet VBA
//   -> enregistrez les classeurs avec macros en .xlsm transitoire
// La sortie Strict ne peut pas porter de contrôles de formulaire
//   -> boutons, cases à cocher, listes déroulantes et leurs ctrlProps
// La sortie Strict ne peut pas porter de commentaires en fil de discussion
//   -> le modèle moderne persons/threads, pas les notes classiques
// La sortie Strict ne peut pas porter de métadonnées de tableau dynamique
//   -> plages de débordement enregistrées via la partie de métadonnées

Échouer bruyamment est le bon compromis ici. Un projet VBA supprimé silencieusement transforme un classeur fonctionnel en un classeur cassé qui s'ouvre quand même, et le rapport de l'échec arrive d'un utilisateur des semaines plus tard. Une exception nomme la fonctionnalité et la propriété à modifier pendant que le code appelant sait encore ce qu'il exportait. La préservation des macros et des liens externes sur le chemin transitoire est traitée dans la préservation des projets VBA et des liens externes

Deux familles d'extensions sont traitées différemment, et il vaut la peine de savoir pourquoi. Les barres de données, les mini-graphiques et fonctionnalités similaires résident dans les vocabulaires x14 et xm, et les variantes SVG des images résident dans c15. Il s'agit de contenu de liste d'extensions dont les espaces de noms sont auto-descriptifs, que les analyseurs de tableurs génériques tolèrent, et pour lesquels il n'existe aucun équivalent ISO vers lequel les traduire. HotXLS les conserve plutôt que de perdre le contenu de l'utilisateur en route. Si un validateur de votre pipeline est strict aussi bien sur les extensions que sur les espaces de noms, retirez ces fonctionnalités du classeur source avant l'export

La traduction doit atteindre des parties que personne ne réécrit normalement

Le problème d'ingénierie intéressant dans la sortie stricte n'est pas le XML des feuilles de calcul. Ce sont les parties qu'un écrivain rapide préférerait copier telles quelles. HotXLS préserve les thèmes, les connexions, les liens externes, les graphiques et les blocs de tableaux croisés dynamiques en copiant directement leurs octets compressés d'origine, ce qui est exactement la bonne chose à faire pour la fidélité et exactement la mauvaise chose pour la sortie stricte, car les octets copiés portent des espaces de noms transitoires

Sous StrictOOXML, ces cinq chemins préservés basculent vers une reconstruction ou vers une relecture traduisante, en contournant le chemin rapide de copie d'octets. Tout le XML passe par une seule routine de traduction, qui s'ancre sur les valeurs d'attribut entre guillemets doubles afin qu'une chaîne ressemblant à une URI à l'intérieur d'une cellule ne puisse jamais être réécrite par accident. Le texte de cellule contenant la même URI est échappé sous forme d'entité dans le XML, de sorte que le remplacement ancré ne peut pas le voir. L'écrivain en flux traduit d'abord son squelette puis se scinde au niveau de sheetData, puisque les blocs de lignes ne contiennent aucune URI de vocabulaire. Les mécanismes associés au chemin de préservation sont traités dans les allers-retours sans perte des thèmes, listes d'extensions et calcChain

Lire les fichiers qu'Excel a enregistrés en mode strict

L'écriture n'est que la moitié de l'histoire. Excel propose « Feuille de calcul Open XML stricte » comme option d'enregistrement, et les fichiers produits ainsi doivent s'ouvrir correctement. HotXLS normalise les types de relations à chaque site d'analyse de relations dans le package, la racine, les liens externes, les feuilles de calcul, les dessins et les tableaux croisés dynamiques, de sorte qu'un type de relation strict corresponde à la même constante interne que son équivalent transitoire

L'équivalent côté lecture est la normalisation des préfixes d'espace de noms, qui permet à des préfixes arbitraires et aux deux vocabulaires de se résoudre vers une seule table de noms canonique. Ce travail profite aussi bien aux fichiers ordinaires qu'aux fichiers stricts, puisque les générateurs tiers lient les préfixes librement, et il s'agit du même mécanisme décrit dans la résolution des relations OPC dans les packages XLSX

Une courte liste de vérifications avant de livrer une sortie stricte

Vérifiez avec le package, pas avec Excel. Excel ouvre les deux formes sans problème, donc une ouverture réussie ne prouve rien sur la conformité. Décompressez le résultat et vérifiez que xl/workbook.xml déclare l'espace de noms purl, qu'aucune partie ne contient schemas.openxmlformats.org/spreadsheetml, et que les types de relations dans _rels/.rels et xl/_rels/workbook.xml.rels utilisent les formes strictes

Rouvrez ensuite le fichier via HotXLS et comparez les valeurs, formules, formats et hyperliens à la source. Un test de relecture est le seul moyen économique de prouver que la traduction n'a pas endommagé le contenu, et il exerce en même temps la normalisation côté lecture. Si vos classeurs portent des graphiques, vérifiez-les aussi, car la partie graphique fait partie des parties préservées qui basculent vers un chemin reconstruit en mode strict

La sortie stricte, la lecture tolérante et la préservation sans perte font toutes partie du même moteur OOXML pour Delphi et C++Builder ; la liste complète des fonctionnalités se trouve sur la page du composant tableur Delphi HotXLS