Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
FORUMS .NET FAQs .NET TUTORIELS .NET SOURCES .NET LIVRES .NET OUTILS .NET BLOG .NET DOTNET TV

Créer un fichier Word OpenXML avec .Net

OpenXML

Date de publication : 05/02/2007 , Date de mise à jour : 06/06/2007

Par Florian Casabianca (mon site)
 

Avec l'arrivée de la nouvelle version de Microsoft Office 2007, Microsoft introduit le nouveau format de document Office Open XML pour Word, Excel et PowerPoint et qui succèdent aux formats de fichier binaires d'Office (.doc, .xls et .ppt) apparus avec la sortie d'Office 97.
Cet article présente les bases pour la création d'un fichier Word OpenXML en .Net.

               Version PDF (Miroir)

I. Introduction
II. Rappel sur la structure d'un document WordProcessingML
III. Pré requis nécessaires
IV. Création d'un premier document WordprocessingML
IV-A. Analyse du code
IV-B. Analyse du fichier généré
V. La Part principale du document
VI. Paragraphes et formatage
VI-A. Les paragraphes
VI-B. Les runs
VII. Les styles
VII-A. La Part styles
VII-B. Définition d'un style
VII-C. Styles s'appliquant à un paragraphe
VII-D. Styles s'appliquant à un run
VII-E. Les propriétés par défaut
VII-F. Ordre d'application des styles
VII-G. Un peu de code
VIII. Les fichiers de propriétés
IX. Ajouter une image au document
IX-A. DrawingML
IX-B. Le code
X. Pour aller plus loin
XI. Conclusion
Liens
Remerciements
Contact


I. Introduction

Avec l'arrivée de la nouvelle version de Microsoft Office 2007, Microsoft introduit le nouveau format de document Office Open XML pour Word, Excel et PowerPoint et qui succèdent aux formats de fichier binaires d'Office (.doc, .xls et .ppt) apparus avec la sortie d'Office 97.

Grâce à ce nouveau format récemment standardisé à l'ECMA, les fichiers Word deviennent de simples packages zip contenant des fichiers XML. Ainsi, il n'est plus nécessaire de posséder Microsoft Word pour créer ou visualiser des fichiers, un simple éditeur de texte ou une application « maison » suffit.

Dans cet article nous allons tout d'abord découvrir le code de base nécessaire pour créer un document Word au format Open XML contenant un simple texte. Nous étofferons ensuite ce code pour modifier l'apparence (police, couleur, font) du texte. Enfin, nous verrons comment ajouter n'importe quel objet (textuel ou binaire) à notre document (dans notre cas ce sera une image).


II. Rappel sur la structure d'un document WordProcessingML

WordprocessingML est un ensemble de conventions pour représenter un document Word au format Open XML. Pour les documents Excel il existe SpreadsheetML et pour les documents PowerPoint il s'agit de PresentationML.

Cet article n'a pas pour but de vous présenter l'architecture et la structure d'un document au format Open XML. Vous devez en avoir pris connaissance avant de lire cet article. Si tel n'est pas le cas, je vous conseille d'aller visiter ces quelques liens : les livres blancs et Structure d'un document Open XML. Cependant, nous allons tout de même faire un petit rappel sur la structure d'un document (ou package) Open XML de type WordprocessingML que vous pouvez visualiser notamment en ajoutant l'extension .zip à un fichier .docx et en l'ouvrant avec votre lecteur de fichiers zip.

images/image1.gif Les trois principaux composants du nouveau format sont :

Les parts : chaque fichier contenu dans l'arborescence est une Part. La plupart sont des fichiers XML mais il peut aussi y avoir des fichiers binaires (images, vidéos, objets OLE etc.) ou même d'autres fichiers Open XML multimédia si le document Word en contient.

Les éléments type de contenu : ce sont des métadonnées contenues dans le fichier [Content_Types].xml et permettant de décrire le type de contenu stocké dans une Part (fichier jpeg, fichier de styles, fichier de relations, etc.). On peut ainsi savoir quelle méthode de lecture employer pour lire une Part.

Les éléments relation : ils permettent de définir les associations entre une Part source et une partie cible. Les relations spécifient comment les parts se mêlent pour former un document. Les relations sont définies dans les fichiers .rels.
Le dossier docProps contient les fichiers de propriétés du document.
Le fichier document.xml est la Part principale d'un document WordprocessingML et contient le texte du corps du document.


III. Pré requis nécessaires

Pour nous faciliter la tâche, le Framework 3.0 de Microsoft .NET inclut la nouvelle API de packaging fournie dans l'assembly WindowsBase.dll. Les classes qui constituent l'API packaging sont contenues dans l'espace de noms System.IO.Package.

Vous aurez donc besoin du Framework 3.0 et de son SDK.

Pour ajouter une référence à votre projet sous Visual Studio : dans le menu projet, cliquez sur ajouter une référence. Si la dll WindowsBase ne se trouve pas dans l'onglet .Net, choisissez l'onglet Parcourir et aller la chercher dans \Program Files\Reference Assemblies\Microsoft\Framework\v3.0.

references
Vous devrez aussi référencer les espaces de noms System.IO et System.Xml dans votre projet :
using System.IO;
using System.Xml;
using System.IO.Packaging;

IV. Création d'un premier document WordprocessingML

Le but de cette première étape est de créer un premier document docx dont le contenu du fichier document.xml (voir l'arborescence) sera le suivant :
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:body>
    <w:p>
      <w:r>
        <w:t>Salut !</w:t>
      </w:r>
    </w:p>
  </w:body>
</w:document>
Nous avons ici le contenu minimum que doit avoir le fichier document.xml. Les explications concernant les différentes balises seront évoquées plus tard.


IV-A. Analyse du code

Au niveau du code C#, rien de vraiment compliqué. En effet, il suffit pour l'instant de créer un objet XmlDocument et de le remplir avec les noeuds nécessaires afin d'obtenir l'arborescence souhaitée (de la manipulation standard de XML en somme):
    // Utilisation du NameSpace WordprocessingML:
    string WordprocessingML = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";

    // Création du WordML
    XmlDocument xmlStartPart = new XmlDocument();
    XmlElement tagDocument = xmlStartPart.CreateElement("w:document", WordprocessingML);
    xmlStartPart.AppendChild(tagDocument);
    XmlElement tagBody = xmlStartPart.CreateElement("w:body", WordprocessingML);
    tagDocument.AppendChild(tagBody);
    XmlElement tagParagraph = xmlStartPart.CreateElement("w:p", WordprocessingML);
    tagBody.AppendChild(tagParagraph);
    XmlElement tagRun = xmlStartPart.CreateElement("w:r", WordprocessingML);
    tagParagraph.AppendChild(tagRun);
    XmlElement tagText = xmlStartPart.CreateElement("w:t", WordprocessingML);
    tagRun.AppendChild(tagText);

    // Insertion du texte
    XmlNode nodeText = xmlStartPart.CreateNode(XmlNodeType.Text, "w:t", WordprocessingML);
    nodeText.Value = "Salut !";
    tagText.AppendChild(nodeText);
C'est maintenant que l'espace de noms System.IO.Packaging va nous servir. Il contient en effet la classe Package qui présente une méthode static Open permettant de créer de nouveaux packages et d'ouvrir des packages existants. Attention, l'appel de la méthode Open devra se faire suivre par un appel à la méthode Close. Nous passons ici en paramètre le nom de notre fichier, le fait que s'il existe déjà on le supprime et le fait qu'on y accède en lecture/écriture :

    // Création d'un nouveau package
    Package pkgOutputDoc = null;
    pkgOutputDoc = Package.Open("monFichier.docx", FileMode.Create, FileAccess.ReadWrite);
Une fois le package créé, nous allons maintenant créer une Part (souvenez-vous, c'est l'une des trois composantes que nous avons évoqué lors du rappel sur la structure d'un fichier docx). Cette Part sera le document document.xml contenu dans le répertoire word. Pour cela, nous avons la méthode CreatPart qui attend en paramètre un Uri permettant de spécifier où doit se localiser le fichier document.xml dans le package et un string spécifiant le type de contenu du fichier. Nous spécifions ici "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" qui signifie que cette Part contient l'information principale de notre document docx (c'est-à-dire là où sera stocké le texte contenu dans le document Word, dans notre cas :  "salut !").
   // Création d'une part
   Uri uri = new Uri("/word/document.xml", UriKind.Relative);
   PackagePart partDocumentXML = pkgOutputDoc.CreatePart(uri, 
   		"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml");
Pour finir cette étape, il reste à sérialiser le contenu de la Part dans le package :
StreamWriter streamStartPart = new StreamWriter(partDocumentXML.GetStream(FileMode.Create, FileAccess.Write));
  xmlStartPart.Save(streamStartPart);
  streamStartPart.Close();
L'écriture de notre fichier document.xml est maintenant terminée. Mais il reste encore une dernière étape pour finir la création de notre document WordprocessingML. En effet, si nous reprenons les trois principaux composants que nous avons évoqué au début, nous en avons oublié un : l'élément relation. Insérer le fichier document.xml dans le package ne suffit pas, il faut aussi le lier au package. Pour cela, nous disposons de la méthode CreateRelationship que l'on appelle depuis notre objet Package. Nous lui passons en premier paramètre l'objet Uri construit précédemment qui représente la cible de la relation. Le deuxième paramètre permet de spécifier si cette cible se situe à l'intérieur ou à l'extérieur du package. Le troisième paramètre définit le type de relation. Ici nous mettons une relation de type officeDocument car c'est le type de relation qui correspond à la Part principale du package (document.docx). Enfin, le dernier paramètre sert à donner un identifiant à cette relation.
  // Création de la RelationShip
  pkgOutputDoc.CreateRelationship(uri, TargetMode.Internal,
     "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument","rId1");
  pkgOutputDoc.Flush();

  // Fermeture du package
  pkgOutputDoc.Close();
Voilà, la création de notre premier document Word est terminée. Si vous exécutez ce code vous obtiendrez un document monFichier.docx dont voici la visualisation dans Word 2007 :

docx

IV-B. Analyse du fichier généré

Jetons un coup d'oeil sur les fichiers créés. Si vous extrayez le contenu du document monFichier.docx vous aller retrouver l'arborescence décrite au début (même si elle est pour le moment pas mal allégée).

A la racine vous allez retrouver le fichier [Content_Types].xml qui décrit les types de contenu des différentes parts du package :
<?xml version="1.0" encoding="utf-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
   <Default Extension="xml" ContentType="application/vnd.openxmlformats-   officedocument.wordprocessingml.document.main+xml" />
   <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />
</Types>
Vous pouvez voir ici le type de contenu "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" que nous avons défini précédemment dans le code C#.

Vous trouverez également un répertoire _rels qui contient le fichier .rels contenant les éléments relation :
<?xml version="1.0" encoding="utf-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
    <Relationship
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" 
    Target="/word/document.xml" Id="rId1" />
</Relationships>
On y retrouve bien la relation rId1 que nous avions définie dans le code C# ayant pour cible le fichier document.xml.


V. La Part principale du document

Avant de pouvoir étoffer notre texte (ajout de paragraphes, de couleurs, etc.) il nous faut d'abord comprendre la structure de la Part principale d'un document Open XML : le fichier document.xml. Comme vous pouvez vous en douter, les différents changements que nous souhaitons apporter à notre texte se feront grâce à l'ajout de balises XML dans le fichier documents.xml. L'ajout de ces balises supplémentaires ne posera pas de réelles difficultés (il suffit en effet de modifier le code C# vu précédemment et plus particulièrement l'objet XmlDocument afin de lui rajouter les balises souhaitées, le reste du code restant identique). Le problème réside plutôt dans le fait de savoir quelles balises ajouter et où les insérer.

Voyons la structure de base de la Part principale d'un document Open XML:
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:background w:color="CEB966"/>
  <w:body>
    <w:p>
      <w:r>
        <w:t>Salut !</w:t>
      </w:r>
    </w:p>
  </w:body>
</w:document>
La balise document est l'élément root du document. Il spécifie le contenu de la Part principale d'un document Open XML. Cet élément ne peut avoir que 2 éléments enfants : l'élément body et l'élément background.

L'élément background indique les informations concernant le fond d'un document WordprocessingML (par exemple la couleur de fond).

La balise body indique le contenu du corps du document. Elle peut contenir un certain nombre de types d'éléments dont tbl (tableau) et p (paragraphe).


VI. Paragraphes et formatage


VI-A. Les paragraphes

Le paragraphe (qui est défini avec l'élément p) est l'unité la plus fondamentale pour stocker un bloc de contenu dans un document WordprocessingML. Un paragraphe définit une division distincte du contenu qui commence avec une nouvelle ligne. Un paragraphe peut contenir trois types d'informations : les propriétés du paragraphe (facultatives), le contenu du paragraphe (typiquement une balise run ), et un ensemble d'identifications facultatives de révision utilisées pour comparer le contenu de deux documents.

Nous pouvons évidemment mettre plusieurs paragraphes dans un document. Ainsi, si l'on veut que notre texte contienne deux paragraphes, le fichier document.xml devra ressembler à ceci : 
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:background w:color="CEB966"/>
  <w:body>
    <w:p>
      <w:r>
        <w:t>Paragraphe 1</w:t>
      </w:r>
    </w:p>
    <w:p>
      <w:r>
        <w:t>Paragraphe 2</w:t>
      </w:r>
    </w:p>
  </w:body>
</w:document>
Il est possible de spécifier un ensemble de propriétés qui s'appliqueront à tout le paragraphe. Ces propriétés doivent être déclarées dans un élément pPr au sein de l'élément p .

Par exemple :

L'élément jc permet de spécifier l'alignement du texte. La valeur "both" correspond à un alignement justifié (il existe aussi "right", "left" et "center").

L'élément pageBreakBefore permet d'insérer un saut de page juste avant le paragraphe concerné.

Ainsi, un paragraphe dont l'alignement du texte est justifié et qui commence sur une nouvelle page se déclarera de cette façon :
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
  <w:background w:color="CEB966"/>
  <w:body>
    <w:p>
      <w:pPr>
        <w:jc w:val="both"/>
        <w:pageBreakBefore/>
      </w:pPr>
      <w:r>
        <w:t>Salut !</w:t>
      </w:r>
    </w:p>
  </w:body>
</w:document>
Le code C# pour réaliser ceci n'est pas compliqué. Il suffit en effet simplement de modifier notre objet XmlDocument que nous avions déclaré plus haut. Le reste du code (création du package, des relations, etc.) demeure strictement identique. Voici le code pour créer deux paragraphes et déclarer les propriétés justifié et saut de page au deuxième paragraphe :
    // Utilisation du NameSpace WordprocessingML:
    string WordprocessingML = 
"http://schemas.openxmlformats.org/wordprocessingml/2006/main";

    // Création du WordML
    XmlDocument xmlStartPart = new XmlDocument();
    XmlElement tagDocument = xmlStartPart.CreateElement("w:document",     
       WordprocessingML);
    xmlStartPart.AppendChild(tagDocument);
    XmlElement tagBody = xmlStartPart.CreateElement("w:body", WordprocessingML);
    tagDocument.AppendChild(tagBody);

    // déclaration du paragraphe 1
    XmlElement tagParagraph = xmlStartPart.CreateElement("w:p", WordprocessingML);
    tagBody.AppendChild(tagParagraph);
    XmlElement tagRun = xmlStartPart.CreateElement("w:r", WordprocessingML);
    tagParagraph.AppendChild(tagRun);
    XmlElement tagText = xmlStartPart.CreateElement("w:t", WordprocessingML);
    tagRun.AppendChild(tagText);
    // Insertion du texte
    XmlNode nodeText = xmlStartPart.CreateNode(XmlNodeType.Text, "w:t", WordprocessingML);
    nodeText.Value = "Salut !";
    tagText.AppendChild(nodeText);
    // déclaration du paragraphe 2
    tagParagraph = xmlStartPart.CreateElement("w:p", WordprocessingML);
    tagBody.AppendChild(tagParagraph);

    // déclaration des propriétés du paragraphe
    XmlElement tagParagraphProp = xmlStartPart.CreateElement("w:pPr", WordprocessingML);
    tagParagraph.AppendChild(tagParagraphProp);

    //propriété alignement
    XmlElement tagAlignement = xmlStartPart.CreateElement("w:jc", WordprocessingML);
    //attribut du noeud w:jc
    XmlAttribute attribut1 = xmlStartPart.CreateAttribute("w:val", WordprocessingML);
    attribut1.InnerText = "both";
    tagAlignement.SetAttributeNode(attribut1);
    tagParagraphProp.AppendChild(tagAlignement);

    //propriété saut de page
    XmlElement tagBreak = xmlStartPart.CreateElement("w:pageBreakBefore", WordprocessingML);
    tagParagraphProp.AppendChild(tagBreak);

    tagRun = xmlStartPart.CreateElement("w:r", WordprocessingML);
    tagParagraph.AppendChild(tagRun);
    tagText = xmlStartPart.CreateElement("w:t", WordprocessingML);
    tagRun.AppendChild(tagText);
    nodeText = xmlStartPart.CreateNode(XmlNodeType.Text, "w:t", WordprocessingML);
    nodeText.Value = "Salut !";
    tagText.AppendChild(nodeText);
    
    //reste du code...

VI-B. Les runs

Un run (balise r ) est une région de textes ayant un ensemble commun de propriétés. Un élément r permet de combiner des styles ou des propriétés de formatage, s'appliquant de la même façon à toutes parties du run. Le texte dans un document WordprocessingML doit être contenu dans un ou plusieurs runs. Un paragraphe est une collection d'un ou plusieurs runs. Un run doit être contenu dans un paragraphe. Le texte à l'intérieur d'un run s'écrit dans une balise t.

De même qu'un paragraphe peut avoir des propriétés, un run peut en avoir aussi. Tous les éléments à l'intérieur d'un élément r ont leurs propriétés contrôlées par un élément rPr facultatif et qui doit être le premier enfant de l'élément r. En d'autres termes, l'élément rPr est un conteneur pour un ensemble d'éléments de propriété qui sont appliqués au reste des enfants de l'élément r. Les éléments de propriété à l'intérieur de l'élément conteneur rPr permettent de contrôler si le texte dans les éléments t suivants est en gras, souligné ou en italique, par exemple. Quelques exemples de propriétés : gras, bordure, style de caractère, couleur, police, taille de police, italique, direction du texte ou encore soulignement.

Le contenu le plus commun du run est l'élément t (mais il en existe d'autres !), qui est le conteneur pour le texte qui compose le contenu du document. Un élément t peut contenir une quantité arbitraire de texte, allant même jusquà pouvoir contenir le contenu entier du document. Un élément t doit être inclus dans un élément r . Un élément r peut contenir de multiples éléments t, entremêlés avec d'autres éléments.

Ainsi, la phrase suivante : « Open XML avec .NET c'est facile. » qui contient du texte en rouge, en gras et surligné sera décomposé ainsi :

<w:r>
  <w:rPr>
    <w:color w:val="FF0000"/>
  </w:rPr>
  <w:t>Open XML</w:t>
</w:r>
<w:r>
  <w:t xml:space="preserve"> avec </w:t>
</w:r>
<w:r>
  <w:rPr>
    <w:b/>
  </w:rPr>
  <w:t>.NET</w:t>
</w:r>
<w:r>
  <w:t xml:space="preserve"> c'est </w:t>
</w:r>
<w:r>
  <w:rPr>
    <w:highlight w:val="yellow"/>
  </w:rPr>
  <w:t>facile</w:t>
</w:r>
Notez l'utilisation de la propriété xml:space="preserve" qui permet de conserver les espaces se trouvant dans le texte à l'intérieur de la balise t .

Voici un peu de code pour agrémenter tout cela. Notez ici que je ne mets que le code pour la création du premier run. En effet, il vous suffit simplement de répéter l'opération pour les autres, vous savez faire maintenant, c'est de la simple manipulation d'XML.
    // Utilisation du NameSpace WordprocessingML:
    string WordprocessingML = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";

    // Création du WordML
    XmlDocument xmlStartPart = new XmlDocument();
    XmlElement tagDocument = xmlStartPart.CreateElement("w:document",     
       WordprocessingML);
    xmlStartPart.AppendChild(tagDocument);
    XmlElement tagBody = xmlStartPart.CreateElement("w:body", WordprocessingML);
    tagDocument.AppendChild(tagBody);

    // déclaration du paragraphe
    XmlElement tagParagraph = xmlStartPart.CreateElement("w:p", WordprocessingML);
    tagBody.AppendChild(tagParagraph);

    //création du premier run
    XmlElement tagRun = xmlStartPart.CreateElement("w:r", WordprocessingML);
    tagParagraph.AppendChild(tagRun);

    //Elément de propriétés du premier run 
    XmlElement tagRunProp = xmlStartPart.CreateElement("w:rPr", WordprocessingML);
    tagRun.AppendChild(tagRunProp);
    //propriété couleur
    XmlElement tagCouleur = xmlStartPart.CreateElement("w:color", WordprocessingML);
    //attribut de l'élément w:color
    XmlAttribute valeurCouleur = xmlStartPart.CreateAttribute("w:val", WordprocessingML);
    valeurCouleur.InnerText = "FF0000";
    tagCouleur.SetAttributeNode(valeurCouleur);
    tagRunProp.AppendChild(tagCouleur);            
            
    //création de l'élément t
    XmlElement tagText = xmlStartPart.CreateElement("w:t", WordprocessingML);
    tagRun.AppendChild(tagText);            
    tagText.InnerText= "Open XML";

    //reste du code...

VII. Les styles

Après avoir vu notamment comment définir un paragraphe et des propriétés de formatage pouvant lui être appliquées, peut-être vous posez vous la question suivante : Est-il possible, à l'instar des feuilles de styles CSS en programmation Web, de pouvoir séparer le contenu de sa présentation ? Question pertinente à laquelle on peut heureusement répondre par l'affirmative grâce à l'utilisation des styles.

Dans un document WordprocessingML, les styles sont des ensembles prédéfinis de propriétés qui peuvent être appliquées au texte dans le document. Ceci permet aux propriétés de formatage d'être stockées et gérées indépendamment du contenu, permettant à la présentation du contenu du document d'être changé à un seul endroit (plutôt que de changer les propriétés de chaque paragraphes un à un).


VII-A. La Part styles

A l'instar du contenu d'un document WordprocessingML qui est stocké dans la Part principale (document.xml), les styles seront aussi stockés dans une Part : le fichier styles.xml situé au même niveau que le fichier document.xml. Comme pour la création de la Part principale, la création de la Part contenant les styles nécessitera de définir son type de contenu (application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml) dans le fichier [Content_Types].xml et de créer un élément relation (http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles) pour la lier au package.

Voici la structure du fichier styles.xml :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:styles xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
          xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">

  <w:docDefaults></w:docDefaults>
  <w:latentStyles></w:latentStyles>
  <w:style></w:style>
  <w:style></w:style>
</w:styles>
Elle se compose d'au plus un élément docDefauts (facultatif), d'au plus un élément latentStyles (facultatif) et d'autant d'éléments style que voulus.


VII-B. Définition d'un style

Un style est défini en utilisant un élément style. La définition d'un style peut se découper en trois segments :

  • Un ensemble de propriétés communes à tous les styles
  • Le type du style
  • Les propriétés spécifiques au style (liées au type de style)
Les propriétés communes à tous les styles sont un ensemble de propriétés qui peuvent être employées indépendamment du type de style ; par exemple, le nom du style, l'identifiant du style, si le style est caché, si le style est verrouillé, etc.

Le type du style permet de définir à quel type de bloc va s'appliquer le style. WordprocessingML contient six types de style:

  • Les styles s'appliquant à un paragraphe
  • Les styles s'appliquant à un run
  • Les styles liés (paragraphe + texte)
  • Les styles s'appliquant à un tableau
  • Les styles s'appliquant à une énumération
  • Les propriétés par défaut pour les paragraphes et le texte

Voici à quoi peut ressembler la définition d'un style (sans les propriétés spécifiques au style) :

<w:style w:type="paragraph" w:default="1" w:styleId="MonStyle1">
  <w:name w:val="mon style 1"/>
  <w:basedOn w:val="MonStyleDeBase"/>
  <w:next w:val="MonStyle2"/>
  ...
</w:style>
On voit ici la déclaration de quelques propriétés communes à tous les styles telles que l'identifiant ("MonStyle1"), le nom ("mon style 1") ou encore le style de base (héritage) à partir duquel est construit ce style ("MonStyleDeBase"). Le type du style est défini grâce à l'attribut type ; ici il s'agit d'un style s'appliquant à un paragraphe. Notez l'attribut default qui permet de spécifier que ce style sera le style s'appliquant par défaut à tous les paragraphes ne faisant pas référence à un style particulier.

Voyons maintenant les propriétés spécifiques au style. Elles dépendent bien entendu du type de style déclaré. Nous n'étudierons ici que les styles s'appliquant aux paragraphes et au texte.


VII-C. Styles s'appliquant à un paragraphe

Ces types de style s'appliquent à un paragraphe en entier. Cela implique que le style peut définir à la fois des propriétés de texte (propriétés qui s'appliquent au texte dans le document) et des propriétés de paragraphe (les propriétés qui s'appliquent au positionnement et à l'aspect du paragraphe). Les styles s'appliquant à un paragraphe (élément p ) ne peuvent pas être référencés par des éléments run dans un document. Ces styles doivent être référencés par l'élément pStyle dans l'élément pPr d'un paragraphe.

Consideront le style suivant :
<w:style w:type="paragraph" w:styleId="MonStyle1">
  <w:name w:val="mon style 1"/>
  <w:pPr>
    <w:spacing w:line="480" w:lineRule="auto"/>
    <w:ind w:firstLine="1440"/>
  </w:pPr>
  <w:rPr>
    <w:rFonts w:ascii="Algerian" w:hAnsi="Algerian"/>
    <w:color w:val="ED1C24"/>
    <w:sz w:val="40"/>
  </w:rPr>
</w:style>
Ce style définit des propriétés qui vont s'appliquer au paragraphe grâce à l'élément pPr et des propriétés qui vont s'appliquer à l'élément run contenu dans ce paragraphe grâce à l'élément rPr .

Ce style sera référencé ainsi par un paragraphe :
    <w:p>
      <w:pPr>
        <w:pStyle w:val="MonStyle1"/>
      </w:pPr>
      <w:r>
        <w:t>Open XML avec .Net c'est facile</w:t>
      </w:r>
    </w:p>p>
Le style est référencé grâce à l'élément pStyle à l'intérieur de l'élément pPr du paragraphe qui, rappelons-le, définit les propriétés s'appliquant à un paragraphe

Voici le résultat produit :

openXML

VII-D. Styles s'appliquant à un run

Ces styles ne peuvent s'appliquer qu'à des runs à l'intérieur d'un document et non à un paragraphe. Cela implique donc qu'ils ne peuvent définir que des propriétés s'appliquant au texte à l'intérieur d'un paragraphe. Ces styles sont référencés par l'élément rStyle à l'intérieur de l'élément de propriété du run ( rPr ).

Considerons le style suivant (de type character) :
  <w:style w:type="character" w:styleId="monStyledeRun">
    <w:name w:val="Style pour run"/>
    <w:priority w:val="99"/>
    <w:rPr>
      <w:rFonts w:ascii="Courier New" w:hAnsi="Courier New"/>
      <w:color w:val="FFF200"/>
      <w:u w:val="single"/>
    </w:rPr>
  </w:style>
Vous noterez l'utilisation de l'élément rPr pour définir les propriétés qui vont s'appliquer.

Ce style sera référencé ainsi par un paragraphe :
    <w:p>
      <w:r>
      <w:rPr>
        <w:rStyle w:val="monStyledeRun"/>
      </w:rPr>
        <w:t>Un style est appliqué à ce texte</w:t>
      </w:r>
    </w:p>
Le style "monStyledeRun" est référencé grâce à l'élément rStyle à l'intérieur de l'élément de propriétés rPp du run.


VII-E. Les propriétés par défaut

Bien qu'on ne puisse par vraiment parler de style au sens strict du terme (ces propriétés ne pouvant être directement appliquées à du texte), elles permettent de définir les propriétés de formatage qui seront appliquées par défaut à tous les paragraphes et runs du document. Pour cela, on n'utilise pas la balise style mais un nouvel élément : docDefaults . Ce dernier peut contenir deux élément enfants : pPrDefault qui définit les propriétés par défaut pour les paragraphes et rPrDefault qui définit les propriétés par défaut pour les runs.

Voici un exemple de définition pour l'élément docDefaults :
  <w:docDefaults>
    <w:pPrDefault>
      <w:pPr>
        <w:jc w:val="center"/>
      </w:pPr>
    </w:pPrDefault>
    <w:rPrDefault>
      <w:rPr>
        <w:b/>
      </w:rPr>
    </w:rPrDefault>
  </w:docDefaults>
Plus d'explications seraient superflues, il suffit simplement de définir l'élément pPr dans pPrDefault et l'élément rPr dans rPrDefault puis d'y déclarer les propriétés voulues.


VII-F. Ordre d'application des styles

Avec les différents types de styles existant, il est possible d'appliquer plusieurs styles différents à un même contenu. Considérons l'extrait suivant :
    <w:p>
      <w:pPr>
        <w:pStyle w:val="MonStyle1"/>
      </w:pPr>
      <w:r>
      <w:rPr>
        <w:rStyle w:val="monStyledeRun"/>
        <w:color w:val="FF0000"/>
      </w:rPr>
        <w:t>Un style est appliqué à ce texte</w:t>
      </w:r>
    </w:p>
Dans cet exemple un premier style "MonStyle1" est appliqué au paragraphe. Un second style "monStyleDeRun" est ensuite appliqué à un run contenu dans ce même paragraphe. Enfin, une couleur non déclarée dans un style est appliqué au texte. Supposons que "MonStyle1" et "monStyleDeRun" définissent chacun une autre couleur pour le texte : de quelle couleur sera finalement le texte ? Pour résoudre ce problème, les différents styles sont appliqués dans un ordre précis et résumé dans le tableau suivant :

stylesOrder
Ce tableau peut être décrit de la façon suivante :

  • Tout d'abord, les styles par défaut sont appliqués à tous les paragraphes et runs du document.
  • Ensuite, les styles spécifiques aux tableaux sont appliqués à tous les tableaux du document.
  • Ensuite, on applique les styles définis pour les énumérations
  • Puis, les styles s'appliquant aux paragraphes (et au runs contenus dans ces paragraphes) sont appelés.
  • Puis, les styles spécifiques aux runs sont appliqués.
  • Et pour finir, on applique les propriétés de formatage directes (non contenues dans des styles).
Ainsi, si l'on reprend notre exemple précédent, c'est finalement la couleur définie directement (FF0000) qui aura le dernier mot.


VII-G. Un peu de code

Après avoir vu les bases concernant les styles, mettons tout cela en application. Nous allons créer un document Open XML qui contiendra un paragraphe (avec du texte) auquel nous appliqueront un style. Celui-ci sera de type "paragraph", c'est-à-dire définissant des propriétés s'appliquant à un paragraphe (ici le paragraphe sera centré) mais aussi au texte contenu dans ce paragraphe (ici la couleur).

Voici le code XML de ce style (contenu dans le fichier styles.xml):
  <?xml version="1.0" encoding="utf-8"?>
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main