LoginSignup
26

More than 5 years have passed since last update.

PythonでPandocのフィルターを書く

Last updated at Posted at 2015-06-06

PythonでPandocのフィルターを書く

私は汎用ドキュメントフォーマット変換ツールpandocを愛用している。Pandocについて詳しくは日本語版ユーザーズガイドなどを参照されたい。

ところが、場合によっては変換時に微妙にドキュメントに手を加えたいことがある。例えば、マークダウンで書いたドキュメントをHTMLに変換する際リンクのURLを一斉に置換したいかもしれない。
正規表現で変換するのが簡単だが、実はpandocにはフィルター機能が提供されている。フィルターを使えば、パースされたドキュメントのシンタックスツリーを利用できる。フィルターはpandoc本体と同様にHaskellで書くこともできるが、仕組み的には何言語でも書くことができ、Pythonも公式でサポートされている。

以下のようにpandocがパースしたドキュメントの構文木をJSONフォーマットに変換し、標準入出力を介してフィルターに渡す仕組みだ(図はマニュアルより)。

                         source format
                              ↓
                           (pandoc)
                              ↓
                      JSON-formatted AST
                              ↓
                           (filter)
                              ↓
                      JSON-formatted AST
                              ↓
                           (pandoc)
                              ↓
                        target format

これを使えばインテリジェントなフィルターを書くことができる。まず、公式で提供されているpandocfiltersをインストールしよう。

pip install pandocfilters

これを使って早速ドキュメント中のリンクURLを変更するフィルターを書こう。

convertlink.py
from pandocfilters import toJSONFilter, Link


def myfilter(key, value, format_, meta):
    if key == 'Link':
        value[1][0] = "prefix/" + value[1][0]
        return Link(*value)


if __name__ == "__main__":
    toJSONFilter(myfilter)

実行するには、pandoc実行時にfilterオプションを指定する。カレントディレクトリのスクリプトを指定するには、"./convertlink.py"と書かなければならないので気をつけて。

sample.txt
## sample document
text text text

[link](path/to/otherpage)
$ pandoc --filter=./convertlink.py -t markdown sample.txt
sample document
---------------

text text text

[link](prefix/path/to/otherpage)

その他のTips

pandocが使用する構文木(pandoc AST)のサンプルはpandocで出力することができる。jsonを指定するとJSON、nativeを指定するとHaskellフォーマットで確認できる。


$ pandoc -t json sample.txt 
[{"unMeta":{}},[{"t":"Header","c":[2,["sample-document",[],[]],[{"t":"Str","c":"sample"},{"t":"Space","c":[]},{"t":"Str","c":"document"}]]},{"t":"Para","c":[{"t":"Str","c":"text"},{"t":"Space","c":[]},{"t":"Str","c":"text"},{"t":"Space","c":[]},{"t":"Str","c":"text"}]},{"t":"Para","c":[{"t":"Link","c":[[{"t":"Str","c":"link"}],["path/to/otherpage",""]]}]}]]
$ pandoc -t native sample.txt
[Header 2 ("sample-document",[],[]) [Str "sample",Space,Str "document"]
,Para [Str "text",Space,Str "text",Space,Str "text"]
,Para [Link [Str "link"] ("path/to/otherpage","")]]

フォーマットの詳細はText.Pandoc.Definitionのドキュメントにある。

またフィルターオプションの指定は以下のコマンドパイプラインと等価なので、デバッグ中はこれを利用できる。


$ pandoc -t json sample.txt | python ./convertlink.py | pandoc -f json -t markdown

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26