Créer un fichier Word OpenXML avec .Net
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.
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.
 |
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.
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.
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):
string WordprocessingML = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
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);
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 :
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 !").
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.
pkgOutputDoc.CreateRelationship(uri, TargetMode.Internal,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument","rId1");
pkgOutputDoc.Flush();
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 :
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 :
string WordprocessingML =
"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
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);
XmlNode nodeText = xmlStartPart.CreateNode(XmlNodeType.Text, "w:t", WordprocessingML);
nodeText.Value = "Salut !";
tagText.AppendChild(nodeText);
tagParagraph = xmlStartPart.CreateElement("w:p", WordprocessingML);
tagBody.AppendChild(tagParagraph);
XmlElement tagParagraphProp = xmlStartPart.CreateElement("w:pPr", WordprocessingML);
tagParagraph.AppendChild(tagParagraphProp);
XmlElement tagAlignement = xmlStartPart.CreateElement("w:jc", WordprocessingML);
XmlAttribute attribut1 = xmlStartPart.CreateAttribute("w:val", WordprocessingML);
attribut1.InnerText = "both";
tagAlignement.SetAttributeNode(attribut1);
tagParagraphProp.AppendChild(tagAlignement);
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);
|
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.
string WordprocessingML = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
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 tagRunProp = xmlStartPart.CreateElement("w:rPr", WordprocessingML);
tagRun.AppendChild(tagRunProp);
XmlElement tagCouleur = xmlStartPart.CreateElement("w:color", WordprocessingML);
XmlAttribute valeurCouleur = xmlStartPart.CreateAttribute("w:val", WordprocessingML);
valeurCouleur.InnerText = "FF0000";
tagCouleur.SetAttributeNode(valeurCouleur);
tagRunProp.AppendChild(tagCouleur);
XmlElement tagText = xmlStartPart.CreateElement("w:t", WordprocessingML);
tagRun.AppendChild(tagText);
tagText.InnerText= "Open XML";
|
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 :
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 :
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
|