© Thomas Mailund 2019
T. MailundIntroducing Markdown and Pandochttps://doi.org/10.1007/978-1-4842-5149-2_9

9. Using Templates

Thomas Mailund1 
(1)
Aarhus N, Denmark
 

When Pandoc creates a standalone document, it uses a template for the output. A template is essentially a document with some placeholder variables, where metadata and your processed Markdown text will be inserted. Which metadata will be used in a template depends on the output format; you can get a full list of variables for your output in the Pandoc manual.1 Pandoc automatically sets some metadata, described in the manual, but you can specify other metadata in the header.

Unless you specify another template explicitly, Pandoc will use a default for the output format. You can get Pandoc to show you the template it uses for a specific output by running the
pandoc -D <format>
command, for example, to see what it will use if you generate a PDF file—which it does by generating a LaTeX document and then compiling it—you can write
pandoc -D latex

You can also get a full list of default templates and what they look like at https://github.com/jgm/pandoc-templates .

If you don’t know LaTeX, the template you get by running
pandoc -D latex
might not make much sense, so let us look at
pandoc -D html

instead. The output is rather long, and I won’t replicate it all here but highlight a few parts of it.

Remember the title we discussed in Chapter 8. It was empty before we provided metadata for the title. Let us see what it looks like in the template. There you will find a line that looks like this:
<title>
  $if(title-prefix)$
    $title-prefix$ -
  $endif$
  $pagetitle$
</title>

The stuff in dollar signs specifies placeholders and code for how the template should be processed. Inside the title tags in the HTML template, you have two metadata variables that can be inserted, title-prefix and pagetitle. The title prefix will only be inserted if it exists; that is what the $if(title-prefix)$ code checks. Strictly speaking, pagetitle will also only be inserted if it exists. Otherwise, we get an empty string. But because the title prefix should be followed by a dash, there is an explicit test to see if anything should be inserted.

We never provided metadata for title-prefix and pagetitle, so it is hard to see how they relate to the title metadata we provided. We could have provided those two explicitly, but Pandoc creates them based on our title. It directly uses title variable elsewhere in the template, where the template contains:
<h1 class="title">$title$</h1>

Pandoc and filters can access metadata and create new metadata, which is what it does for the title-prefix and pagetitle. The title placeholder is just inserted directly as the text you specified in the metadata.

I am not aware of any documentation for precisely what metadata manipulations you can expect for each output format, and I am not sure you should rely on any as it might not be stable across different versions of Pandoc and filters. If you don’t work with derived metadata and stick to explicitly defined metadata, however, how the data is used is relatively straightforward. If you have a simple placeholder like $title$, then the string you specified in the metadata will just be inserted there in the output file.

As we saw for title-prefix , metadata can also be inserted conditionally on it being defined. To insert some text only if a metavariable variable is defined, a template can contain this construction:
$if(variable)$ some text $endif$
There is also an if-else construction that looks like this:
$if(variable)$
some text
$else$
some other text
$endif$
Finally, there is a loop construction. In the HTML template, you can find this piece of text:
$for(author)$
<p class="author">$author$</p>
$endfor$

This runs through the authors specified in the metadata and inserts each of them. If author is not a list, it will still work; it will just be considered a list of length one, but if we did have a list of authors, we would get a level-two header for each of them.

Remember that metadata can be structured with values containing lists of key-value bindings. Take this example:
author:
- name: Thomas Mailund
  affiliation: Unseen University
- name: Karsken Baelg
  affiliation: Brakebills University
Here, authors are not simple strings, but a list of key-value structures, each with a name and an affiliation. Inside a template, these fields can be accessed using “dot-notation,” so a template might contain code like this:
$for(author)$
 $if(author.name)$
   $author.name$
   $if(author.affiliation)$
     ($author.affiliation$)
   $endif$
 $else$
   $author$
 $endif$
$endfor$

This code iterates through the author list and inserts authors’ names (if they have a name, which they probably should have). If they have an affiliation, the affiliation is added after the name. If the list of authors contains items that are not structured with a name and an affiliation, the template inserts the list item (see the $else$ part of the $if(author.name)$ test).

The most important part of the output, of course, is the processed Markdown from the input text. In the template, this is inserted at the hardly noticeable $body$ placeholder . It doesn’t look like much, but this is where all your Markdown will be inserted once it is processed to the output format.

Writing Your Own Templates

Templates are another of those features that are nice to have when you need them, but you don’t have to worry about when you don’t. You can use Pandoc without ever having to worry about templates, but if you have to format your documents in a specific way, you don’t have to abandon Pandoc to write your text; you can create a template to take care of the formatting. For example, if you are an academic like me, and have to use different formats for different journals, you can make templates to match the journals. Journals often provide LaTeX templates for papers, and you can take one of those templates and put in Pandoc placeholders, and presto you have a Pandoc template and you can write the paper in Markdown and still have it formatted according to the journal standard.

You can get inspiration for writing your own templates from Pandoc’s user-contributed templates.2 I find that the easiest way to create a new template is to take one of Pandoc’s existing templates and modify it or by taking an existing HTML or LaTeX file and put in metadata and $body$ placeholders.

The reason that the default templates are lengthy and complicated is that they need to set up a long list of things, such as configuring math or source code highlighting. If you need all the features that Pandoc provides, I suggest that you copy one of the existing templates and modify it. For this chapter, I will write simpler templates, aiming for clarity rather than completeness. The Markdown input is correspondently simple. If you need more features, you can find the necessary code in the default template. It is usually not hard to find.

Template Examples

Consider this text. Most of it is metadata since that is what we are interested in here. As you can see, there are three variables in the YAML header: title, subtitle, and author. The first two holds a single value and the last is a list of simple values.
---
title:
  A terrible novel
subtitle:
  Seriously, one of the worst!
author:
  - Thomas Mailund
  - Karsken Baelg
---
It was a dark and stormy night
If we write the following HTML template, we add a title and a subtitle in the HTML header and the level-one header in the main document. If there are any authors in the metadata, then we insert a div element to right-align the list of authors, and we get the said list by iterating over them. The $sep$ variable is not a metavariable as such but a way to tag the following token. If you use $sep$, then the token—word or comma, for example—will be put between all the elements you iterate over but will not follow the last element. Try removing it and you will see.
<html>
  <header>
    <title>
      $title$$if(subtitle)$: $subtitle$$endif$
    </title>
  </header>
  <body>
    <h1>
      $title$$if(subtitle)$: $subtitle$$endif$
    </h1>
    $if(author)$
      <div align="right">
        By
        $for(author)$$author$$sep$and $endfor$
      </div>
    $endif$
    $body$
  </body>
</html>
If we format our text with this template, we get the following HTML:
<html>
  <header>
    <title>
      A terrible novel: Seriously, one of the worst!
    </title>
  </header>
  <body>
    <h1>
      A terrible novel: Seriously, one of the worst!
    </h1>
          <div align="right">
        By
        Thomas Mailund and Karsken Baelg
      </div>
      <p>It was a dark and stormy night</p>
  </body>
</html>
For PDF/LaTeX output , this template does the same as the preceding HTML template.
documentclass{book}
usepackage{hyperref}
itle{$title$$if(subtitle)$: $subtitle$ $endif$}
author{$for(author)$$author$$sep$and $endfor$}
egin{document}
maketitle
end{document}

(The inclusion of hyperref is not relevant for the example, but it is one of those packages that Pandoc expects to be included. At the time I am writing this, it is the only one you need for this particular example).

Applying the template to our document gives us this:
documentclass{book}
usepackage{hyperref}
itle{A terrible novel: Seriously, one of the worst! }
author{Thomas Mailund and Karsken Baelg}
egin{document}
maketitle
end{document}
You can “dot” yourself into nested information in metadata, so if your data looks like this
---
title:
  A terrible novel
subtitle:
  Seriously, one of the worst!
author:
    - name: "Thomas Mailund"
      affiliation: "Unseen University"
    - name: "Karsken Baelg"
      affiliation: "Brakebills University"
---
and your template looks like this
documentclass{book}
usepackage{hyperref}
itle{$title$$if(subtitle)$: $subtitle$ $endif$}
author{$for(author)$$author.name$
   from $author.affiliation$
   $sep$ and
   $endfor$}
egin{document}
maketitle
$body$
end{document}
then progressing the document will generate this output:
documentclass{book}
usepackage{hyperref}
itle{A terrible novel: Seriously, one of the worst! }
author{Thomas Mailund from Unseen University
        and Karsken Baelg from Brakebills University}
egin{document}
maketitle
It was a dark and stormy night
end{document}
You need to get the name and affiliation for each author using $author.name$ and $author.affiliation$. You cannot simply use $author$ any more. You can still check if a value is set; just dot yourself into it. For example, if some authors do not have an affiliation, you can test for it and only insert it when it exists.
documentclass{book}
usepackage{hyperref}
itle{$title$$if(subtitle)$: $subtitle$ $endif$}
author{
$for(author)$ $author.name$
  $if(author.affiliation)$
     from $author.affiliation$
  $endif$
  $sep$ and $endfor$
}
egin{document}
maketitle
$body$
end{document}

If you have a LaTeX template as the preceding one (or for any other output format), you want it to apply to as many documents as possible. You don’t want to have to update it every few documents you write. There are often a few tweaks necessary for each document, though. For example, in LaTeX you might need to import one special package or you want to define some commands. You don’t want those modifications in your actual template, and you do not want to have many copies of the template lying around either. It is easy, however, to use metavariables to make your template adaptable.

Considering the case of LaTeX files as I just described, we can add packages and definitions to the template like this3:
documentclass{book}
usepackage{hyperref}
$for(packages)$
usepackage{$packages$}
$endfor$
$if(definitions)$
  $definitions$
$endif$
itle{$title$$if(subtitle)$: $subtitle$ $endif$}
author{
  $for(author)$
    $author.name$
    $if(author.affiliation)$
      from $author.affiliation$
    $endif$
    $sep$ and
  $endfor$
}
egin{document}
maketitle
$body$
end{document}
We iterate over packages to insert each of them in a usepackage command . We just insert the definitions here. With this input
---
title:
  A terrible novel
subtitle:
  Seriously, one of the worst!
author:
  - name: "Thomas Mailund"
    affiliation: "Unseen University"
  - name: "Karsken Baelg"
    affiliation: "Brakebills University"
packages:
  - amssymb
  - amsmath
  - booktabs
  - xspace
definitions: |
   ewcommand{TMRCA}%
    {ensuremath{T_ extrm{MRCA}}xspace}
   ewcommand{ AC}%
    {ensuremath{ au_{AC}}xspace}
   ewcommand{ BC}%
    {ensuremath{ au_{BC}}xspace}
   ewcommand{ ABC}%
    {ensuremath{ au_{ABC}}xspace}
   ewcommand{ admix}%
    {ensuremath{ au_ ext{admix}}xspace}
---
It was a dark and stormy night
we get
documentclass{book}
usepackage{hyperref}
usepackage{amssymb}
usepackage{amsmath}
usepackage{booktabs}
usepackage{xspace}
   ewcommand{TMRCA}%
    {ensuremath{T_ extrm{MRCA}}xspace}
   ewcommand{ AC}%
    {ensuremath{ au_{AC}}xspace}
   ewcommand{ BC}%
    {ensuremath{ au_{BC}}xspace}
   ewcommand{ ABC}%
    {ensuremath{ au_{ABC}}xspace}
   ewcommand{ admix}%
    {ensuremath{ au_ ext{admix}}xspace}
itle{A terrible novel: Seriously, one of the worst! }
author{
      Thomas Mailund
    from Unseen University
     and
      Karsken Baelg
    from Brakebills University
    }
egin{document}
maketitle
It was a dark and stormy night
end{document}

If you do not want this LaTeX-specific code to turn up in HTML output, then simply do not include it in the template. If you want separate header configurations in HTML and PDF documents, you can use two different metavariables. For LaTeX macros (unlike the package inclusion), you do not need to modify a template. Pandoc understands the definition of macros and will apply a macro you invoke when producing output. If you call a macro inside math, Pandoc will produce the result of calling the macro in the math format the output needs. Outside of math, the result of calling the macro will be included in LaTeX and Markdown output but left out in other formats.

In case you are interested, the template I have used to format this book evolved over several books but currently looks like the following. I have not listed all the code that Pandoc has in its template but show, in a comment, where you can insert it.
documentclass[11pt, openright,
               twoside, onecolumn, final]{memoir}
%% Setting up the paper size
setstocksize{9in}{6in}
settrimmedsize{stockheight}{stockwidth}{∗}
usepackage{canoniclayout}
onzeroparskip
setlength{parindent}{0pt}
%% Setting up the font
usepackage[T1]{fontenc}
usepackage{baskervillef}
usepackage[scale=.95,type1]{cabin}
usepackage[baskerville,vvarbb]{newtxmath}
usepackage[cal=boondoxo]{mathalfa}
%% Disable hypertext (annoying in output)
usepackage{nohyperref}
usepackage{url}
%% Setup chapter heading
enewcommand* mdefault{dayrom}
chapterstyle{madsen}
%%%%%%%%%%%%
%% A long list of commands taken from
%% the default template
%%%%%%%%%%%%
egin{document}
frontmatter
%% Title page
egingroup
hispagestyle{empty}
{fseriessffamily oindent
$if(series)$ {large $series$}\[50pt]$endif$
% Book title
{huge $title$}\[35pt]
% Authors
{Large $for(author)$$author$$sep$\$endfor$}
vfill
endgroup
%% Copyright page
ewpage
~vfill
hispagestyle{empty}
% Book title
{Large $title$}\[15pt]
% Authors
oindent Copyright
    $year$
    $for(author)$$author$$sep$, $endfor$\
clearpage
%% Table of contents
$if(toc)$
setcounter{tocdepth}{1}
pagestyle{empty}
ableofcontents
cleardoublepage
$endif$
%% Document body
mainmatter
counterwithout{figure}{chapter}
pagestyle{plain}
$body$
end{document}
The metavariables I have set for this book are
---
title:
  "The Beginner's Guide to Markdown and Pandoc"
author:
  - Thomas Mailund
year: 2019
---

There is no good reason that author is a list here. I have only coauthored one book, and it has been a list since, but for one author, it might as well have been a scalar value.

I admit that there is slightly more work involved with creating templates than just writing Markdown documents, but I do not believe that it is much harder to make a template than it would be to write the document in LaTeX or HTML in the first place. Plus, you have put all the complicated formatting in one document while you can focus on the content in another. If you reuse the same template multiple times, you amortize the time spent on creating it over many writing projects, and very quickly you will have saved time compared to writing in LaTeX or HTML directly in cases where you need more than one output format. And you can share your templates with friends and colleagues for gold or glory.

Exercises

Write your own templates; write one for HTML and one for LaTeX.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset