Structure des fichiers OpenXML

Dans cet article, je vous propose de faire connaissance avec l'organisation interne des fichiers OpenXML, le nouveau format de document Office de Microsoft.

Article lu   fois.

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

Avant propos

OpenXML est le nouveau format de fichier adopté par les documents de la suite Office, à partir de la version 2007. Ce format, fruit de la collaboration de Microsoft, d'Intel et d'Apple, entre autres, est totalement libre de royalties, et sa pérennité et son indépendance vis-à-vis de tout éditeur sont garanties par son élévation au rang de norme par l'ECMA (le standard ISO devrait bientôt suivre).

OpenXML rompt radicalement avec les formats binaires propriétaires des précédentes versions d'Office (jusqu'à la version 2003, qui a amorcé le tournant), en adoptant XML, langage ouvert, comme format de stockage. Il sera désormais possible aux développeurs de lire, créer, modifier, afficher sur différents médias des documents Office, sans dépendre d'applications Microsoft, en utilisant des outils comme XSLT, SAX ou DOM, directement ou par l'intermédiaire de librairies OpenXML qui ne devraient pas tarder à apparaître.

OpenXML est une norme très riche, dont le corpus s'élève à plusieurs milliers de pages. Nous nous limiterons dans cet article d'initiation à l'étude de la section traitant de l'organisation du contenu des fichiers OpenXML intitulée Open Packaging Conventions (OPC), et plus précisément de l'application de ces conventions aux documents Office.

1. Anatomie d'un fichier OpenXML

1.1. Structure interne d'un fichier OpenXML

Les documents Office OpenXML sont des fichiers compressés selon le format Zip. On peut donc visualiser leur contenu en les décompressant à l'aide de n'importe quel utilitaire reconnaissant le format Zip.

Un fichier Word 2007 "dézippé" présente la structure typique suivante(1) :

Image non disponible
Contenu d'un fichier OpenXML Office (Word)

Une fois décompressé, un fichier OpenXML révèle une kyrielle d'autres fichiers ; l'ensemble de ces fichiers est appelé, dans la terminologie OpenXML, un paquet (package). Ce paquet regroupe une collection de fichiers appelés parties (parts) répartis dans une arborescence dont ils constituent les feuilles. Cette structure éclatée tranche avec le format monolithique employé par Office 2003, dans lequel l'intégralité du document se retrouvait au sein du seul et même fichier XML. Ici, nous avons affaire à une structure modulaire, chaque partie ou répertoire contenant des parties étant un élément du fichier ZIP.

1.2. Les parties

OpenXML attribue à chaque partie un nom unique, coomposé du chemin logique menant de la racine du paquet au fichier constituant la partie proprement dite. Ainsi, de notre exemple de document nous pouvons tirer cette liste (partielle) de noms de parties :

  • /[Content_Types].xml
  • /_rels/.rels
  • /word/document.xml
  • /word/styles.xml
  • /word/_rels/document.xml.rels
  • /docProps/core.xml
  • /word/media/image1.png
  • ...

Les parties qui composent un fichier document OpenXML peuvent être réparties entre deux catégories :

  1. Les parties qui contiennent les données (texte, images, sons, vidéos, etc.) qui constituent le document lui-même. Ces parties peuvent contenir des données définis dans OpenXML (du WordprocessingML dans notre exemple), d'autres données XML dont le schéma ne fait pas partie des spécifications OpenXML, des données binaires (objets OLE, images JPEG ou PNG, des vidéos AVI, etc.), du texte simple...
  2. Les parties qui contiennent des informations concernant la structure interne du paquet, notamment le type de contenu des autres parties, et les liens logiques qu'elles ont entre elles ; ces parties contiennent des données XML dont le schéma est défini par la norme OpenXML (par les Open Packaging Conventions plus précisément)

OpenXML ne définit pas quels doivent être les noms des parties de la première catégorie, celles qui contiennent les données du document. Chaque application générant des fichiers OpenXML pouvant définir ses propres noms pour les parties, comment une application censée les lire peut-elle accéder à des parties dont elle ignore a priori le nom et le contenu ?

Cela est rendu possible grâce aux parties de la deuxième catégorie, qui contiennent les informations qui vont permettre de connaître précisément le rôle de chacune des autres parties du paquet, ainsi que les liens qui les unissent entre elles. Ces parties "spéciales" sont de deux types, le fichier des types de contenu et les fichiers de relations (relationships parts). Ces deux types de fichiers étant la clé de l'accès aux données du document OpenXML, nous allons les étudier en détail.

1.3. Le fichier des types de contenu

Le fichier des types de contenu d'un document Office OpenXML est la partie nommée /[Content_Types].xml.
Elle est placée à la racine du paquet et son nom est invariablement le même d'une instance de document OpenXML à l'autre, car défini par la norme.

Ce fichier contient un document XML qui recense toutes les parties qui constituent le paquet, et associe à chacune un type MIME. Voici un extrait du contenu de ce fichier tiré de notre exemple de document :

Contenu de [Content_Types].xml
Sélectionnez
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
	<Override PartName="/word/footnotes.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml"/>
	<Default Extension="png" ContentType="image/png"/>
	<Default Extension="emz" ContentType="image/x-emz"/>
	<Default Extension="xls" ContentType="application/vnd.ms-excel"/>
	<Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"/>
	<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
	<Default Extension="xml" ContentType="application/xml"/>
	<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
	<Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/>
	<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
	<Override PartName="/word/endnotes.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml"/>
	...
</Types>

Le schéma de ce document XML est composé de l'élément principal Types et de ses deux éléments fils, Default et Override.

Default définit un type MIME par défaut, désigné par la valeur de l'attribut ContentType, pour les parties dont le nom se termine par l'extension contenue dans l'attribut Extension. Ainsi, dans notre exemple, toutes les parties dont le nom se termine par ".png" seront du type MIME "image/png", et celles se terminant par ".xml" seront du type MIME "application/xml".

L'élément Override signale qu'une partie a un type MIME autre que celui défini par défaut pour les parties ayant la même extension. Le nom de la partie bénéficiant de ce type MIME spécifique est contenu dans l'attribut PartName. Ainsi, par exemple, la partie nommée /word/document.xml est du type MIME application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml, et non application/xml. Ce type MIME, ainsi que tous ceux des parties contenant du WordprocessingML, ont été définies spécifiquement par Microsoft pour les documents OpenXML issus d'Office.

Grâce à ce fichier de types de contenu, une application cliente peut déterminer de façon précise le contenu de chaque partie, sans avoir à faire de déduction hasardeuse à partir de son extension ou en recherchant dans son contenu une valeur "magique" indicatrice de la nature du fichier.

1.4. Les fichiers de relations

Ce sont des documents XML contenant un ensemble de relations, une relation étant un mappage entre une partie, la partie source, toujours implicite, et une autre partie du paquet (la partie cible). Les fichiers de relation constituent l'ossature du paquet.

L'emplacement de ces fichiers dans le paquet ainsi que leur nommage suivent plusieurs règles définies dans la spécification OpenXML. La première précise que le fichier de relation associé à une partie source doit se trouver dans un répertoire fils de celui qui contient la partie en question, et que ce répertoire doit impérativement se nommer _rels. La deuxième règle stipule que la fin du nom du fichier de relation doit être le même que celui de la partie associée, additionné de l'extension .rels.

Par exemple, le fichier de relation associé à la partie /word/document.xml sera localisé dans le paquet à l'emplacement /word/_rels, et se nommera /word/_rels/document.xml.rels.

1.4.1. Contenu d'un fichier de relation

Examinons le contenu d'un fichier de relation, par exemple /word/_rels/document.xml.rels :

Contenu de /word/_rels/document.xml.rels
Sélectionnez
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
	<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>
	<Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/image1.png"/>
	<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
	<Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Target="footnotes.xml"/>
	<Relationship Id="rId15" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/>
	...
</Relationships>

Le schéma de ce document comprend l'élément principal Relationships et ses éléments fils Relationship.

Chaque élément Relationship définit une relation entretenue entre la partie source (ici document.xml) et une autre partie du paquet. Les caractéristiques de la relation sont réparties entre les différents attributs de cet élément :

  • L'attribut Type indique la nature de la relation. Elle se présente sous la forme d'une URI, dont la sémantique est propre à l'application à l'origine du document. Chaque éditeur implémentant OpenXML définit son propre jeu d'URI, en l'occurrence celles employées par les documents Office OpenXML sont toutes dotées du préfixe "http://schemas.openxmlformats.org/officeDocument/2006/relationships/"
  • L'attribut Target indique la partie (ou la ressource) ciblée par la relation, sous la forme d'une URI toujours relative à la partie source
  • L'attribut Id est l'identifiant unique de la relation ; il sera utilisé à l'intérieur de document.xml pour faire référence à cette relation, et au travers d'elle à la partie qu'elle cible
  • L'attribut optionnel TargetMode indique si la cible de la relation est une partie située dans le paquet, ou bien, s'il est égal à "external", si la cible est une ressource externe au paquet ; en l'absence de cet attribut, la cible de la relation est interne au paquet

Pour formuler en langage naturel un exemple d'une de ces relations, la partie /word/document.xml a une relation nommée rId2 avec la partie /word/styles.xml, une relation dont le type est l'URI "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles". La lecture de la spécification OpenXML nous informe que cette URI indique que la ressource ciblée contient la définition des styles de caractères, de paragraphes et autres, de la partie source. Nous aurions pu nous en douter au vu du nom de la partie ciblée, mais l'URI nous le confirme de manière formelle et non ambiguë.

1.4.2. Le fichier de relation principal

Parmi les fichiers de relation que peut contenir un paquet, il en est un peu spécial puisqu'il n'est pas associé à une partie source, mais à la racine du paquet lui-même. Ce fichier de relation a la même structure que celle vue précédemment, et se nomme invariablement /_rels/.rels (notez que le nom de ce fichier suit les mêmes conventions que les autres fichiers de relation).
Ce fichier de relation

Examinons le contenu de ce fichier pour notre exemple de document :

Contenu de /_rels/.rels
Sélectionnez
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
	<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
	<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
	<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
</Relationships>

Parmi toutes les relations que peut contenir le fichier de relation principal, nous ne nous intéresserons dans ce tutoriel qu'à trois relations parmi les plus importantes :

URI du type de la relation Obligatoire Description
http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument Oui La cible de cette relation est la partie principale du document, celle qui contient le corps du document (word/document dans notre exemple)
http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties Non La partie ciblée par cette relation contient les métadonnées communes à tous les documents Office, telles que la date de création, le titre, la description, le créateur, etc. (Dublin Core)
http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties Non La partie ciblée par cette relation contient des propriétés spécifiques au type de document Office représenté par la partie principale du document ; s'il s'agit de WordprocessingML, les propriétés seront le nombre de pages, de caractères, de mots, de paragraphes, etc. S'il s'agit de SpreadsheetML, le nombre de feuilles de calculs, etc.

Le fichier de relation principal est donc le point d'entrée privilégié pour accéder à n'importe quelle partie du paquet, puisqu'à partir de la partie contenant le corps du document il est possible d'accéder aux parties annexes grâce à son fichier de relations. Si une partie annexe dispose elle-même d'un fichier de relations, on peut accéder encore à d'autres relations, et ainsi de suite, jusqu'à parcourir l'intégralité de l'arborescence du paquet.

1.5. Structure minimale d'un fichier OpenXML

Nous avons vu que les parties contenant les propriétés étendues et les métadonnées du document sont optionnelles, qu'en est-il des autres parties ? En fait, il en est de même de la majorité des autres parties qui figurent dans l'arborescence de notre document exemple ; ainsi, un document ne comprenant pas d'entête ni de pied de page n'aura pas de parties nommées /word/footer.xml et /word/header.xml. Quelles sont alors les parties qu'un fichier OpenXML Office devra comprendre a minima pour être lisible par les applications Office ? Elles sont au nombre de 3 :

  • Le fichiers des types de contenu /[Content_Types].xml
  • Le fichier de relation principal /_rels/.rels
  • La partie contenant le corps du document (/word/document.xml pour un document Word)

2. Scénario de lecture d'un fichier Office OpenXML

Maintenant que nous avons examiné comment était structuré un fichier OpenXML, nous pouvons à présent établir l'enchaînement des tâches que devra effectuer une application pour accéder au contenu du document.

Ce processus se déroule en 4 phases :

  1. Ouvrir le fichier de relation principal (_rels/.rels) et extraire la cible de la relation "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
  2. Ouvrir la partie [Content_Types].xml et se servir de la valeur obtenue précédemment comme clé pour rechercher le type MIME de la partie principale du document
  3. (Optionnel) Lire les propriétés du document, les générales et les spécifiques, en ouvrant les parties correspondantes ciblées dans le fichier de relation principal ; les propriétés spécifiques seront interprétées conformément au type de document détecté à la phase 2
  4. Lire la partie principale du document (le corps du document) identifié à la phase 1, et accéder aux autres parties constituantes du document grâce au fichier de relation de cette partie

Vous pourriez vous étonner que les deux premières phases soient nécessaires pour connaître le type de document Office auquel l'on a affaire, ne pourrait-on se baser pour cela sur l'extension du fichier, par exemple .docx pour un document Word ?
C'est effectivement possible, si vous maîtrisez totalement la production du document (c'est vous - votre application - qui le générez par exemple) et avez la garantie que l'extension correspond bien à son type. Si ce n'est pas le cas, si ce document vous provient par exemple d'un tiers sur lequel vous n'avez aucun contrôle, la consultation du fichier de relation principal et l'identification du type MIME constituent la méthode la plus robuste et la plus fiable pour connaître le type de document et le manipuler en conséquence.

D'autre part, vous pourriez avoir la tentation de vous passer des fichiers de relations pour atteindre les différentes parties du document, en partant du postulat que leur sont attribuées toujours les mêmes URI. Ainsi, word/document.xml contiendrait toujours le corps du document, word/styles.xml les styles employés dans le document, etc. Encore une fois, cela ne se vérifiera que si vous maîtrisez totalement la génération de ces documents. Si ces documents sont générés par un processus hors de votre atteinte, ou même directement à partir d'Office, vous ne pouvez être absolument certain que cette nomenclature sera toujours la même. Plutôt que de faire des suppositions hasardeuses sur le rôle de chacune des parties du paquet, il est infiniment plus sage de se reposer sur les fichiers de relation pour reconstituer le puzzle et identifier les parties.

Conclusion

Les choix technologiques retenus par Microsoft pour son format OpenXML, XML et Zip, ouvrent la voie à pratiquement toutes les plateformes actuelles de développement pour sa manipulation. A présent, il ne vous reste plus qu'à mettre à profit toutes ces informations pour manipuler les fichiers OpenXML avec votre langage favori !

Quelques liens utiles :

Lecture des fichiers OpenXML avec PHP 5Lecture des fichiers OpenXML avec PHP 5
Créer un fichier Word OpenXML (2007) avec .NET
Les spécifications OpenXML à l'ECMA
OpenXML Developer


Le dossier nommé "Office Open XML sample.docx" ne fait pas partie du fichier zip, il n'apparaît sur cette illustration que pour symboliser la racine du paquet

  

Copyright © 2006 Eric Grimois. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.