Docutilsのインラインマークアップを自作する

以前、Docutilsのディレクティブを自作する - saito’s blogでreStructuredTextのディレクティブを自作する方法を紹介しました。サンプルプログラムでは、はてな記法のリンク作成支援に似た機能をreStructuredTextに追加しました。しかし、ディレクティブはインラインで書くことが出来ないので、前回のサンプルでは、

* google記法    : |google記法|
* amazon記法    : |amazon記法|
* wikipedia記法 : |wikipedia記法|
* isbn記法      : |isbn記法|

.. |google記法| google:: はてな

.. |amazon記法| amazon:: はてな

.. |wikipedia記法| wikipedia:: はてな_(企業)

.. |isbn記法| isbn:: 4798110523 近藤(2006)

のように、わざわざ置換を用いて文中にリンクを挿入していました。

Docutilsではインラインマークアップを自分で定義することができ、前回のサンプルのような用法の場合インラインマークアップを使うべきだということが分かったので、改めてそちらの方法を紹介します。

Docutilsでインラインマークアップを定義する方法はこちらのページで紹介されています。

インラインマークアップを定義するには、まず、次のようなシグネチャを持つ関数を定義します。

def role_fn(name, rawtext, text, lineno, inliner,
            options={}, content=[]):
    code...

この関数で2つの戻り値を返すようにします。1つ目はdocutils.nodes.Nodeのサブクラスのインスタンスのリストで、2つ目はシステムメッセージ(おそらくエラー処理などの目的に使う)のリストです。各戻り値は空のリストにすることもできます。関数を定義したら、docutils.parsers.rst.roles.register_local_roleを使って関数を登録します。

次のサンプルプログラムでは、Google検索へのリンクを作成するための記法をreStructuredTextに追加します。

import urllib
from docutils.core import publish_parts
from docutils import nodes
from docutils.parsers.rst import roles

def google(role, rawtext, text, lineno, inliner, options={}, content=[]):
  q = text
  title = u"google:%s" % q
  refuri = "http://www.google.com/search?q=%s" % urllib.quote_plus(q.encode("utf-8"))
  ref_node = nodes.reference(refuri=refuri, name=title)
  ref_node += nodes.Text(title)
  return [ref_node], []
roles.register_local_role("google", google)

if __name__ == '__main__':
  value = ":google:`はてな`"
  parts = publish_parts(source=value, writer_name="html4css1")
  html = parts["fragment"]
  print html.encode("utf-8")

このプログラムを実行すると、次のようなHTMLが出力されます。

<p><a class="reference external" href="http://www.google.com/search?q=%E3%81%AF%E3%81%A6%E3%81%AA">google:はてな</a></p>