Aller au contenu

Approfondir Pandoc : modèles (Bonus)

Dans le guide, nous avons abordé brièvement la manière d'obtenir le résultat d'une conversion avec Pandoc vers un logiciel de traitement de texte comme LibreOffice. Je propose ici d'aller un peu plus loin. Je précise de nouveau qu'il ne s'agit pas de produire un document destiné à être publié (ce n'est pas un travail éditorial que nous faisons), mais de produire un document que vous exploiterez vous-même par la suite, ou que vous pouvez diffuser sans directives particulières.

Généralités

Lorsqu'on convertit avec Pandoc, le logiciel repère les différentes variables, expressions et styles. C'est pour cela que Pandoc ne convertit pas seulement vers les formats docx ou odt mais il les reconstruit.

Or, il faut savoir qu'historiquement, le format docx est beaucoup plus riche et beaucoup plus testé par la communauté d'utilisateurs de Pandoc. Cela va très certainement s'améliorer, mais il faut reconnaître que les flux de travail académiques sont davantage noyautés par ce format.

Faites cette simple expérience : écrivez un document markdown (document.md) avec tous les entêtes que vous voulez, notamment un résumé (abstract). Puis faites une conversion simple avec Pandoc vers le format odt et une autre vers le format docx. Comparez les résultats.

Heureusement, ouvrir et travailler un docx avec LibreOffice ne pose pas de problème. Il faut toutefois reconnaître qu'il peut être assez frustrant qu'un format ouvert ne soit pas aussi complet. En revanche, si le format odt est moins expressif, il est aussi plus robuste et ne se noie pas dans un fatras de styles. Par exemple, il délègue souvent les styles aux styles par défaut de LibreOffice, mais d'un autre côté cela laisse ouverte la possibilité d'en construire sur-mesure.

C'est là qu'interviennent deux possibilités de Pandoc : l'utilisation des template et des documents de référence. Pour tous les formats de sortie, Pandoc utilise des modèles qui reprennent les différentes variables présentes dans le document. Selon votre installation de Pandoc, ils se trouvent dans le dossier /usr/share/pandoc/data/templates (ou quelque chose d'approchant). Localisez le fichier default.opendocument, faites-en une copie, placez cette copie et nommez-la montemplate.opendocument dans votre dossier de travail, puis ouvrez ce fichier avec un éditeur de texte. Regardez sa construction.

Ce qui va suivre est valable pour tous les formats de sortie que vous voulez, dans la mesure où vous pouvez modifier les modèles que vous utilisez. Nous avons déjà parlé de l'utilisation des styles .css pour travailler avec le format HTML. Nous allons travailler dans le même esprit.

Manipuler les fichiers

Attention : je pars ici du principe que tous les fichiers que nous utilisons se situent dans le même répertoire de travail. Si ce n'est pas le cas, il vous faut adapter les lignes de commande en indiquant les chemins de vos fichiers.

Dans le manuel Pandoc,

  • la syntaxe des templates est expliquée ici
  • les variables sont listées ici
  • l'utilisation de l'option reference-doc est expliquée ici

Faire un modèle et l'utiliser

Le fichier montemplate.opendocument n'est pas long. Vous y trouvez des lignes comme celles-ci :

$if(date)$
<text:p text:style-name="Date">$date$</text:p>
$endif$
$if(abstract)$
$abstract$
$endif$

La traduction est très simple : s'il y a une variable nommée date, alors tu l'affiches dans un paragraphe dont le style est nommé Date. S'il y a une variable nommée abstract alors, heu… tu mets l'abstract… enfin, tu le prends en compte…

Et pourtant : ouvrez le document odt que vous avez produit : il y a bien un style Abstract par défaut dans LibreOffice. Alors, pourquoi n'affiche-t-il pas l'abstract ? Parce qu'on ne lui demande pas.

Regardons de près l'entête Yaml d'un document Markdown :

---
title: "L'archéologie Schtroumpf au Pays Magique"
subtitle: "Essai de méthodologie complète"
author: "Marcel Dupont"
lang: fr-FR
institute: "SLIP  Sciences, Langues, Information et Philosophie"
date: "2026-01-01"
abstract-title: "Un résumé"
abstract: "Cet article présente les résultats de fouilles menées au village Schtroumpf. L’analyse stratigraphique des champignons-habitats et du mobilier révèle une organisation sociale complexe, une chronologie cohérente et des pratiques rituelles inédites."
description: "Texte préparatoire avant publication dans la Revue du SLIP"
keywords: 
  - Schtroumpf
  - article
  - archéologie
---

Votre premier objectif est de générer un document odt reprenant les variables que vous voulez (celles présentes dans votre entête yaml). Dans ce cas, il vous faut modifier montemplate.opendocument en fonction de vos désirs.

Je vous propose de modifier ainsi en ajoutant les lignes suivantes, répondant à cette interprétation : « s'il y a une variable nommée variable, tu l'affiches dans un paragraphe en appliquant le style Style. »

On peut ajouter la prise en compte de la description du document. Elle a pour objectif de figurer dans les métadonnées du document odt que l'on produira et pourra être exploitée :

$if(description)$
<text:p text:style-name="Description">$description$</text:p>
$endif$

Lorsqu'on produit un article, il peut être nécessaire de préciser son institut ou université d'appartenance :

$if(institute)$
<text:p text:style-name="Institute">$institute$</text:p>
$endif$

Nous avons vu dans le guide l'importance des mots-clés pour lier vos documents Markdown et construire une cartographie de vos connaissances. Si vous produisez un document odt ou un pdf, il peut être intéressant de les mettre aussi dans les métadonnées de votre document et aussi les exploiter :

$if(keywords)$
<text:p text:style-name="Keywords">
$for(keywords)$#$keywords$$sep$ $endfor$
</text:p>
$endif$

Notez ci-dessus la manière d'agir avec une boucle qui permet de présenter les mots-clés en les faisant précéder d'un croisillon (#) puis les séparer par une espace.

Si votre entête yaml précise bien la langue avec lang: fr-FR, le titre de votre abstract sera Résumé. Mais après tout, vous pouvez l'appeler différemment. Cela se joue avec la variable abstract-title. Mais on peut convenir que la présence d'un résumé implique un titre par défaut, qu'on va appeler Résumé si on n'utilise pas la variable abstract-title (vous noterez qu'en produisant le .docx, le titre par défaut est Abstract).

$if(abstract-title)$
<text:p text:style-name="Abstract-title">$abstract-title$</text:p>
$endif$
$if(abstract)$
$if(abstract-title)$
$else$
<text:p text:style-name="Abstract-title">Résumé</text:p>
$endif$
<text:p text:style-name="Abstract">$abstract$</text:p>
$endif$

Modèle à recopier

Pour vous simplifier les choses, je vous propose à la fin de ce chapitre un exemple de modèle que vous pourrez recopier et enregistrer dans un fichier nommé montemplate.opendocument.

Une fois que nous avons un modèle comment l'utiliser ? Le principe dans la ligne de commande Pandoc est assez simple, il faut utiliser l'option --template=montemplate.opendocument. De cette manière :

pandoc document.md --template=montemplate.opendocument -o sortie.odt

Utiliser un document de référence

Si vous procédez de la manière expliquée ci-dessus, vous constaterez que les différentes variables que nous avons choisi d'afficher rendent du texte exprimé avec des styles ou sans style. En effet, parmi les styles par défaut de LibreOffice, certains existent comme le style de Titre principal ou le style Date, mais d'autres n'y sont pas, comme celui que nous voulons associer à la variable institute par exemple.

Notre objectif, ici, est de créer un document odt qui défini tous les styles dont nous avons besoin. Sachez qu'il est possible de demander à Pandoc de nous sortir un tel document de référence qui contient les styles par défaut. Pour cela, lancez cette commande :

pandoc -o custom-reference.odt --print-default-data-file reference.odt

Cela produira un fichier reference.odt où vous pourrez modifier les styles. L'ennui, c'est que ce document ne contient pas de texte. Il faudrait donc produire du texte, puis définir des styles. Par ailleurs, ce document présent par défaut ne contient pas les éléments liés aux variables que nous avons définies plus haut avec, déjà, des noms de styles.

Ma préférence consiste à produire un document à partir du fichier Markdown dont nous avons écrit l'en-tête et qui reprend aussi du contenu qu'on a l'habitude de produire.

Donc, rédigez votre document Markdown en reprenant le modèle d'entête yaml transcrit ci-dessus et rédigez quelque chose contenant a minima des paragraphes, des citations, un tableau, des notes de bas de page, des listes… En gros, prenez un document que vous avez déjà rédigé, ce sera plus simple.

Convertissez ce document en odt et nommez-le messtyles.odt. Là, vous définissez vos styles. Pensez aux éléments suivants :

  • les styles que vous devez créer (Description, Institute, Keywords) doivent être nommés scrupuleusement, sinon ils ne seront pas appliqués puisqu'ils sont appelés ainsi dans montemplate.opendocument (ou alors, renommez-les).
  • les styles existants peuvent être modifiés selon vos exigences typographiques : pensez par exemple à l'interlignage du format de paragraphe par défaut, la présentation de citations, le format de page A4, les notes de bas de page, etc. Ne vous contentez pas de la couleur des titres. Notez aussi que même en produisant le format docx par défaut, il vaut mieux utiliser un tel document de référence, car les éléments typographiques à la française ne sont pas au rendez-vous.

Document de référence à télécharger

Pour vous simplifier les choses, je vous propose de télécharger ce document de référence nommé messtyles.odt. Il comprend des styles que j'estime être suffisants pour un document dont le but est simplement d'être affiché, imprimé, diffusé ou classé.

Une fois que nous avons un tel document pour les styles, comment l'utiliser ? Le principe dans la ligne de commande Pandoc est assez simple, il faut utiliser l'option --reference-doc=messtyles.odt. De cette manière :

pandoc document.md --template=montemplate.opendocument --reference-doc=messtyles.odt -o sortie.odt

Ici, nous utilisons en premier le modèle à appliquer et ensuite les styles à adopter dans la construction du document.

Des longues lignes

Si on ajoute à cela les différents éléments que nous avons vus dans notre guide, les lignes commencent à devenir assez longues.

Avec une bibliographie :

pandoc document.md --citeproc --bibliography=mabiblio.bib --csl=iso690-author-date-fr-no-abstract.csl --template=montemplate.opendocument --reference-doc=messtyles.odt -o sortie.odt

Ajouter une transformation en PDF sans avoir à ouvrir LibreOffice (souvenez-vous, nous en avons déjà parlé dans le guide) :

pandoc document.md --citeproc --bibliography=mabiblio.bib --csl=iso690-author-date-fr-no-abstract.csl --template=montemplate.opendocument --reference-doc=messtyles.odt -o sortie.odt && libreoffice --headless --convert-to pdf sortie.odt

Avec Zettlr

Heureusement, il n'y a pas toujours besoin d'ouvrir le terminal et taper des lignes aussi longues. D'abord, une bonne méthode consiste à vous fabriquer un fichier .sh qui contiendra déjà les éléments. Mais il y a encore plus simple, qui consiste à ne pas sortir de votre logiciel. Voici comment faire avec Zettlr qui propose justement la possibilité d'utiliser des commandes personnalisées.

Placez vos fichiers montemplate.opendocument et messtyles.odt dans un sous-dossier de votre dossier de travail, par exemple dependances/.

Si vous utilisez de la bibliographie, notez l'emplacement de vos fichiers CSL et bib (ou json) qui constituent vos fichiers de styles de bibliographie et votre fichier de bibliographie, comme nous l'avons vu dans le guide (ce que nous avons renseigné dans Zettlr avec Préférences > Citations). L'idéal serait de les placer, eux aussi, dans ce dossier dependances/. En effet, comme il s'agit d'une commande personnalisée, même si nous avons indiqué ces fichiers dans les options de Zettlr, il va falloir les indiquer de nouveau (ou en indiquer d'autres si vous le souhaitez).

Dans Zettlr, allez dans Préférences > Importer et exporter. En bas, vous pouvez entrer une commande personnalisée en lui donnant un nom. Cette commande aura pour particularité qu'il n'y a pas besoin d'entrer le nom du fichier qu'on veut exporter (c'est indiqué). Dès lors, entrez une commande de cette manière :

pandoc --citeproc --bibliography=/chemin/vers/ma/biblio.bib --csl=/chemin/vers/mon/fichier.csl --template=/chemin/vers/montemplate.opendocument --reference-doc=/chemin/vers/messtyles.odt -o sortie.odt

Par exemple :

pandoc --citeproc --bibliography=/home/moi/Documents/travail/dependances/biblio.bib --csl=/home/moi/Documents/travail/dependances/iso690-author-date-fr.csl --template=/home/moi/Documents/travail/dependances/montemplate.opendocument --reference-doc=/home/moi/Documents/travail/dependances/messtyles.odt -o sortie.odt

Puis, lorsque vous souhaitez exporter, cliquez sur l'icône d'export, sélectionnez le nom de votre commande, et exportez le document selon les options ainsi choisies.

Annexe

Voici un exemple de modèle que vous pourrez recopier et enregistrer dans un fichier nommé montemplate.opendocument.

<?xml version="1.0" encoding="utf-8" ?>
<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.3">
  <office:font-face-decls>
    <style:font-face style:name="Courier New" style:font-family-generic="modern" style:font-pitch="fixed" svg:font-family="'Courier New'" />
  </office:font-face-decls>
  <office:automatic-styles>
    $automatic-styles$
  </office:automatic-styles>
$for(header-includes)$
  $header-includes$
$endfor$
<office:body>
<office:text>
$if(description)$
<text:p text:style-name="Description">$description$</text:p>
$endif$
$if(keywords)$
<text:p text:style-name="Keywords">
$for(keywords)$#$keywords$$sep$ $endfor$
</text:p>
$endif$
$if(date)$
<text:p text:style-name="Date">$date$</text:p>
$endif$
$if(title)$
<text:p text:style-name="Title">$title$</text:p>
$endif$
$if(subtitle)$
<text:p text:style-name="Subtitle">$subtitle$</text:p>
$endif$
$for(author)$
<text:p text:style-name="Author">$author$</text:p>
$endfor$
$if(institute)$
<text:p text:style-name="Institute">$institute$</text:p>
$endif$
$if(abstract-title)$
<text:p text:style-name="Abstract-title">$abstract-title$</text:p>
$endif$
$if(abstract)$
$if(abstract-title)$
$else$
<text:p text:style-name="Abstract-title">Résumé</text:p>
$endif$
<text:p text:style-name="Abstract">$abstract$</text:p>
$endif$
$for(include-before)$
$include-before$
$endfor$
$if(toc)$
<text:table-of-content>
  <text:table-of-content-source text:outline-level="$toc-depth$">
    <text:index-title-template text:style-name="Contents_20_Heading">$toc-title$</text:index-title-template>
    <text:table-of-content-entry-template text:outline-level="1"
    text:style-name="Contents_20_1">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="2"
    text:style-name="Contents_20_2">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="3"
    text:style-name="Contents_20_3">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="4"
    text:style-name="Contents_20_4">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="5"
    text:style-name="Contents_20_5">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="6"
    text:style-name="Contents_20_6">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="7"
    text:style-name="Contents_20_7">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="8"
    text:style-name="Contents_20_8">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="9"
    text:style-name="Contents_20_9">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
    <text:table-of-content-entry-template text:outline-level="10"
    text:style-name="Contents_20_10">
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-chapter />
      <text:index-entry-text />
      <text:index-entry-link-end />
      <text:index-entry-tab-stop style:type="right"
      style:leader-char="." />
      <text:index-entry-link-start text:style-name="Internet_20_link" />
      <text:index-entry-page-number />
      <text:index-entry-link-end />
    </text:table-of-content-entry-template>
  </text:table-of-content-source>
</text:table-of-content>
$endif$
$body$
$for(include-after)$
$include-after$
$endfor$
</office:text>
</office:body>
</office:document-content>
.