概要
ここではPython-Markdownモジュールの拡張機能である「toc(Table of Contents)」について実装する。
以下のような方の記事
目次をドキュメント内ではなく他の部分に挿入したい。
拡張機能の構成を設定するextension_configsについて
目次にタイトルを付けたい。
設定項目のslugifyで独自のスラッグを当てはめる
などなど...
実行環境 |
---|
Windows Subsystem for Linux |
Python 3.6.9 |
pip 9.0.1 |
Jupyter Notebook |
使用ライブラリ | ライセンス |
---|---|
Markdown==3.1.1 | BSD |
目次拡張機能を追加することによってドキュメント内に「[TOC]」と打てば以下の図の左側のようにHTMLの<h>...</h>
タグをリストとした目次に変換してくれます。
今回は以下のようにドキュメント内だけではなくサイドバーや他の場所に目次を配置させたいといった実装になります。
通常マークダウンされた文字列のテキストをHTMLに変換する際は以下のようにする。
import markdown
# from markdown.extensions.toc import TocExtension
text = """
[TOC]
# header 1
○○
## header 1-2
××
# header 2
"""
# tocは目次拡張機能
html = markdown.markdown(text, extensions=['toc'])
# or
# html = markdown.markdown(text, extensions=[TocExtension()])
print(html)
"""
<div class="toc">
<ul>
<li><a href="#header-1">header 1</a><ul>
<li><a href="#header-1-2">header 1-2</a></li>
</ul>
</li>
<li><a href="#header-2">header 2</a></li>
</ul>
</div>
<h1 id="header-1">header 1</h1>
<p>○○</p>
<h2 id="header-1-2">header 1-2</h2>
<p>××</p>
<h1 id="header-2">header 2</h1>
"""
上記のようにmarkdown
関数にアクセスすることによりマークダウンをHTMLに変換することができました。
今回のように目次の部分だけ取り出すような細かい操作を行いたい場合はMarkdown
クラスを使います。
import markdown
# オブジェクトを作成
md = markdown.Markdown(extensions=['toc'])
# インスタンスを生成
html = md.convert(text)
print('目次の部分')
print(md.toc)
print('ドキュメント')
print(html)
"""
目次の部分
<div class="toc">
<ul>
<li><a href="#header-1">header 1</a><ul>
<li><a href="#header-1-2">header 1-2</a></li>
</ul>
</li>
<li><a href="#header-2">header 2</a></li>
</ul>
</div>
ドキュメント
<div class="toc">
<ul>
<li><a href="#header-1">header 1</a><ul>
<li><a href="#header-1-2">header 1-2</a></li>
</ul>
</li>
<li><a href="#header-2">header 2</a></li>
</ul>
</div>
<h1 id="header-1">header 1</h1>
<p>○○</p>
<h2 id="header-1-2">header 1-2</h2>
<p>××</p>
<h1 id="header-2">header 2</h1>
"""
オブジェクトにテキストが渡された際に、値がmd.toc
属性にアタッチされ目次の部分を取得できるようになります。
md.to_tokens
とすると辞書型に生成された目次のデータも取得できます。
print(md.toc_tokens[0])
"""
{'level': 1, 'id': 'header-1', 'name': 'header 1', 'children': [{'level': 2, 'id': 'header-1-2', 'name': 'header 1-2', 'children': []}]}
"""
Markdown
クラスに目次拡張機能が追加されていれば、ドキュメントに「[TOC]」と打たなくともクラスオブジェクトのtoc
もしくわtoc_tokens
属性にアクセスすることで目次の部分のみ取得できます。
text_2 = """
# header 1
○○
## header 1-2
××
# header 2
"""
# オブジェクトを作成
md = markdown.Markdown(extensions=['toc'])
# インスタンスを生成
html_2 = md.convert(text_2)
print('目次の部分')
print(md.toc)
print('ドキュメント')
print(html_2)
"""
目次の部分
<div class="toc">
<ul>
<li><a href="#header-1">header 1</a><ul>
<li><a href="#header-1-2">header 1-2</a></li>
</ul>
</li>
<li><a href="#header-2">header 2</a></li>
</ul>
</div>
ドキュメント
<h1 id="header-1">header 1</h1>
<p>○○</p>
<h2 id="header-1-2">header 1-2</h2>
<p>××</p>
<h1 id="header-2">header 2</h1>
"""
ブログでよく見かけるイメージとしては以下のような感じになります。
右側にある目次を追随させることで、記事を読み返すのに便利そうです。
拡張機能の構成を変更するには、Markdown
クラスのextension_configs
パラメータに要素を渡すか、extensions
パラメータにTocExtension
クラスを渡してTocExtension
パラメータから構成設定を変えるかです。
例えば目次拡張機能にタイトルを持たせるとするならば以下のように設定します。
extension_configs
パラメータの場合
# 特定のキーに構成を設定した辞書を入れる
extension_configs = {
'toc': {
'title': 'Table of Contents'
}
}
md = markdown.Markdown(
extensions=['toc'],
extension_configs=extension_configs # 要素を渡す
)
TocExtension
パラメータの場合
from markdown.extensions.toc import TocExtension
md = markdown.Markdown(extensions=[
TocExtension(
title='table of contents', # タイトル デフォルトは「None」
)
])
いずれかの方法を使って構成設定を変えると、目次に「table of contents」とタイトルを持たせることができます。
text = """
# header1
## header1-2
# header2
"""
html = md.convert(text)
print('目次の部分')
print(md.toc)
"""
目次の部分
<div class="toc"><span class="toctitle">Table of Contents</span><ul>
<li><a href="#header1">header1</a><ul>
<li><a href="#header1-2">header1-2</a></li>
</ul>
</li>
<li><a href="#header2">header2</a></li>
</ul>
</div>
"""
Key | Value |
---|---|
marker | デフォルト=[TOC]、マークダウンの記法を変更できる(例:[toc]など) |
title | デフォルト=None、目次にタイトルを付けられる |
anchorlink | デフォルト=False、各項目にアンカーリンクを設定 |
anchorlink_class | アンカーリンクのCSSクラス名を変更できるがエラーとなってしまう。 |
permalink | ドフォルト=False、各項目のパーマリンクを設定 |
permalink_class | パーマリンクのCSSクラス名を変更できるがエラーとなってしまう。 |
slugify | デフォルト=markdown.extensions.headerid.slugify (項目名にASCII以外の文字列は番号と記号に置き換えられる)、function(value, separator): の引数を持つ関数を定義して渡すことによって、アンカーリンクの名前を変更することできる。 |
separator | デフォルト=「-」、区切り文字 |
toc_depth | デフォルト=6、目次リストの階層を表示する深さ(子要素のリスト) |
スラッグとはURLの語尾(https://example.com/detail/100#slug)に当たる名前の事で、目次に割り当てられているアンカーリンク(<a href="#slug">
)のことです。
注意
スラッグはSEO対策の一環として英単語にするのが望ましい。
〇:https://example.com/detail/100#slug
✕:https://example.com/detail/100#スラッグ
Markdownのデフォルトでは項目名がそのままスラッグとして割り当てられています。
日本語のような文字コードがASCII以外の項目名を付けると、その文字列は除外されるか、記号と番号によって割り振られます。
スラッグを設定するには、構成設定にある「slugify」に「value」と「separator」の引数を持つ関数を渡す必要があります。
text = """
[TOC]
# header1
## header1-2
# header2
"""
# slugifyキーに渡すための関数
# value=項目名、separator=記号
def my_slugify(value, separator):
return 'slug'
html = markdown.markdown(
text=text,
extensions=['toc'],
extension_configs={
'toc':{
'slugify': my_slugify # スラッグの設定
}
}
)
print(html)
"""
<div class="toc">
<ul>
<li><a href="#slug">header1</a><ul>
<li><a href="#slug_1">header1-2</a></li>
</ul>
</li>
<li><a href="#slug_2">header2</a></li>
</ul>
</div>
<h1 id="slug">header1</h1>
<h2 id="slug_1">header1-2</h2>
<h1 id="slug_2">header2</h1>
"""
アンカータグのhref属性が「#slug」に置き換わりました。
slugify用の関数を使っているので、ついでに「separator」の設定もしてみます。
text = """
[TOC]
# header1
## header1-2
# header2
"""
# valueおよびseparatorも合わせて戻す
def my_slugify(value, separator):
slug = value + separator + 'slug'
return slug
html = markdown.markdown(
text=text,
extensions=['toc'],
extension_configs={
'toc':{
'slugify': my_slugify,
'separator': '/' # 記号を変更
}
}
)
print(html)
"""
<div class="toc">
<ul>
<li><a href="#header1/slug">header1</a><ul>
<li><a href="#header1-2/slug">header1-2</a></li>
</ul>
</li>
<li><a href="#header2/slug">header2</a></li>
</ul>
</div>
<h1 id="header1/slug">header1</h1>
<h2 id="header1-2/slug">header1-2</h2>
<h1 id="header2/slug">header2</h1>
"""
他にもアンカーリンクやパーマリンクも各項目に付与することができまるので非常に便利な設定です。
以上です。
最後までご覧いただきありがとうございました。