pandoc の使い方メモ — 相互参照について

やりたいことは「元の文章を markdown で複数のファイルに分割して書き、それをウェブで公開するために個々に HTML に変換したい。もう一方では印刷できるような一括した PDF を LaTeX 経由で作りたい。ついでに EPUB も作りたい」です。割とありがちなケースだと思うので、もっとすっきりした方法があるように思うのですが、うまく見つけられませんでした。

相互参照とは、HTML では id 属性と a タグで実現されるもの、LaTeX では \label{}\ref{} で表現されるものです。

索引は、LaTeX では後で処理するために \index{} で印を付けておくものです。HTML と EPUB では使いません。

例を挙げます。

a.md

はじめに {#hajimeni}
========

...

用意するもの
============

...

道具 {#dougu}
----

* 包丁
* まな板
* ...

これらは[「下ごしらえ」](b.html#shita)で使います。

* 大きな鍋\index{おおきななべ@大きな鍋}
* ...

これらは[「調理」](b.html#chouri)で使います。

材料 {#zairyo}
----

...

b.md

手順
====

下ごしらえ {#shita}
----------

ここで使う材料は[「材料」](a.html#zairyo)にまとめてあります。
...

調理 {#chouri}
----

...
大きな鍋\index{おおきななべ@大きな鍋}([「道具」](a.html#dougu)を参照のこと)を使います。
...

盛り付け {#moritsuke}
--------

おわりに
========

...


という文書が元になります。

HTML

a.md → a.html, b.md → b.html のように個々のページを独立して生成することにします。それを見越して、md ではリンクの書式のところにこれらのファイル名を入れておきます。

md を pandoc

pandoc -o a.html a.md
pandoc -o b.html b.md

と処理すると

a.html
<h1 id="hajimeni">はじめに</h1>
<p>...</p>
<h1 id="用意するもの">用意するもの</h1>
<p>...</p>
<h2 id="dougu">道具</h2>
<ul>
<li>包丁</li>
<li>まな板</li>
<li>...</li>
</ul>
<p>これらは<a href="b.html#shita">「下ごしらえ」</a>で使います。</p>
<ul>
<li>大きな鍋</li>
<li>...</li>
</ul>
<p>これらは<a href="b.html#chouri">「調理」</a>で使います。</p>
<h2 id="zairyo">材料</h2>
<p>...</p>
b.html
<h1 id="手順">手順</h1>
<h2 id="shita">下ごしらえ</h2>
<p>ここで使う材料は<a href="a.html#zairyo">「材料」</a>にまとめてあります。 ...</p>
<h2 id="chouri">調理</h2>
<p>... 大きな鍋(<a href="a.html#dougu">「道具」</a>を参照のこと)を使います。 ...</p>
<h2 id="moritsuke">盛り付け</h2>
<h1 id="おわりに">おわりに</h1>
<p>...</p>

ができます。LaTeX の索引のために挿入しておいた \index{} は無視されるので、特に気にすることはありません。

LaTeX 経由 PDF

ソースは複数ファイルに分割されていても最終的な成果物はひとつであってほしいため、main.tex を用意しておき、

main.tex
\documentclass[a5paper]{jarticle}
\usepackage[dvipdfmx]{hyperref}
\usepackage{makeidx}
\makeindex
\begin{document}
\tableofcontents
%
\input{a}
\input{b}
%
\printindex
\end{document}

これから dvi を作り、さらにそれから pdf を作ることにします(pandoc から PDF を出力させることもできるようですが、日本語のとおる環境を設定したり次に述べる処理を挟んだりするのがやりにくいので、こういうやり方にします)。

さて、ここで読み込まれる a.tex, b.tex を md から pandoc で生成するのですが、単純にやるだけでは、HTML 向けに書いていたリンクのところが

これらは\href{b.html\#shita}{「下ごしらえ」}で使います。

のようになってしまいます。これではよろしくないので、

sed 's/\(\[[^\]*\]\)[\(][^#]*\(#[^\)]*\)[\)]/\1(\2)/g' a.md \
| pandoc -t latex \
| sed 's/\(\\hyperref\[\([^\]*\)\]\)[\{][^\}]*[\}]/\1\{\\ref\{\2\}\}/g' \
> a.tex

のようにします。バックスラッシュと括弧だらけでわかりにくいですが、前段の sed

[「下ごしらえ」](b.html#shita)

[「下ごしらえ」](#shita)

のように、丸カッコ内のファイル名相当の部分を削除します。これで生成物の当該部分は

\hyperref[shita]{「下ごしらえ」}

となるので、後段の sed でこれを

\hyperref[shita]{\ref{shita}}

のように書き換えます。

これにより、生成物は

a.tex
\section{はじめに}\label{hajimeni}

\ldots{}

\section{用意するもの}\label{ux7528ux610fux3059ux308bux3082ux306e}

\ldots{}

\subsection{道具}\label{dougu}

\begin{itemize}
\itemsep1pt\parskip0pt\parsep0pt
\item
  包丁
\item
  まな板
\item
  \ldots{}
\end{itemize}

これらは\hyperref[shita]{\ref{shita}}で使います。

\begin{itemize}
\itemsep1pt\parskip0pt\parsep0pt
\item
  大きな鍋\index{おおきななべ@大きな鍋}
\item
  \ldots{}
\end{itemize}

これらは\hyperref[chouri]{\ref{chouri}}で使います。

\subsection{材料}\label{zairyo}

\ldots{}
b.tex
\section{手順}\label{ux624bux9806}

\subsection{下ごしらえ}\label{shita}

ここで使う材料は\hyperref[zairyo]{\ref{zairyo}}にまとめてあります。 \ldots{}

\subsection{調理}\label{chouri}

\ldots{}
大きな鍋\index{おおきななべ@大きな鍋}(\hyperref[dougu]{\ref{dougu}}を参照のこと)を使います。
\ldots{}

\subsection{盛り付け}\label{moritsuke}

\section{おわりに}\label{ux304aux308fux308aux306b}

\ldots{}

となります。

これで相互参照が正しくなった中間ソース a.tex, b.tex ができましたので、main.tex を

platex main
platex main
mendex main
platex main
dvipdfmx main

と処理して、最終的に main.pdf を得ることができます。

EPUB

pandoc は EPUB 形式を出力することもできます。

ソースは複数ファイルに分割されていても成果物はひとつにまとまっていたほうがいいので cat でつなぎます。また、HTML 向けに付けていたリンクの書き方を変更して(LaTeX の場合の前処理と同じです)、pandoc にかけます。

cat a.md b.md \
| sed 's/\(\[[^\]*\]\)[\(][^#]*\(#[^\)]*\)[\)]/\1(\2)/g' \
| pandoc --self-contained -o main.epub

これで最終成果物の main.epub ができます。LaTeX の索引のために挿入しておいた \index{} は無視されるので、特に気にすることはありません。

HTML や LaTeX、EPUB を出力する際には、もっと適切な pandoc のオプションを付けたり、テンプレートを用意したほうがいいのですが、ここでは相互参照に絞って説明するため、これらを割愛しました。