クラス docutils.nodes.Node
¶
Docutils では reStructuredText 形式のデータを処理するために、中間形式として木構造のオブジェクト群を組み立てる。この木のオブジェクトの型を定義する一連のクラスは
Node
というスーパークラスを継承の始点とする。これらのスーパークラスとサブクラスは全てモジュール docutils.nodes
で定義されている。本節ではデータ構造を中心に、ノード群の設計を解読していく。ただし、各具象ノードの構造までは深く立ち入らないで、別の節で検討したい。例えばノードオブジェクトの処理方法については、次節
クラス docutils.nodes.NodeVisitor で解読していく。
クラス図¶
まずは抽象クラス Node
を継承グラフの始点とする簡単なクラス図を示す。ただし、本来は具象クラスが 98 個もあるにもかかわらず、一枚の図に全てを掲載することは紙幅の都合上避ける。また、理解し易さを優先するべく、説明の目的とは外れた関係、属性の記載を省略している。
クラス名が普通なもの (
CamelCase
) は抽象クラスまたは補助クラス。クラス名が小文字ベースなもの (
snake_case
) は対応する名前の XML 要素的なものにマッチする。ノードの位置は抽象クラスにより表現される?
全ての具象ノードクラスの名前はリストオブジェクト
doutils.nodes.node_class_names
で確認可能。クラスNodeVisitor
の宣言直前に書いてある。
クラス Node
¶
クラス Node
はドキュメントツリーの全ノードクラスの抽象クラスだ。
メンバーデータ¶
これらはクラススコープで宣言されているが、実際はむしろオブジェクトデータとして参照されるもよう。
Node.parent
このノードを直下に含むノードへの参照。メソッド
setup_child
を見ると、実体はノードオブジェクトらしい。Node.document
このノードの所属するドキュメントツリーのルートノードということだ。実体はクラス
document
のオブジェクトだ。Node.source
このノードを生成した入力元のファイルパスまたは説明文を示す文字列。
Node.line
このノードに対応する文字列の開始位置が
source
の何行目にあるかを示す正の整数。
メンバーメソッド¶
__bool__(self)
ノードオブジェクトを
if
文に置いた時に真を返すようにしたいので、これがある。メソッドtraverse
を見ればわかる。copy(self)
,deepcopy(self)
オーバーライド専用メソッド。デフォルトの実装はいつもの
raise NotImplementedError
だ。copy
をオーバーライドするのはサブクラスText
,Element
,document
,pending
だけ。deepcopy
をオーバーライドするのはサブクラスText
,Element
だけ。
walk(self, visitor)
,walkabout(self, visitor)
これらは クラス docutils.nodes.NodeVisitor で解説する。
traverse(self, condition=None, include_self=True, descend=True, siblings=False, ascend=False)
このノードツリーに対して、引数で指示したようなノードオブジェクトを含むリストオブジェクトを返す。キーワード引数の意味は、型が
bool
なものはその名前の示すとおり。condition
が特殊。述語関数を渡す場合と、ノードのサブクラスを型として渡す場合がある。いずれにせよ、このメソッドはcondition(n)
が真となるノードn
をかき集める。
next_node(self, condition=None, include_self=False, descend=True, siblings=False, ascend=False)
self.traverse(...)[0]
またはNone
を返す。include_self=False
がデフォルト値なので注意。
サブクラス¶
差し当たり
Text
,Element
,document
が Docutils の設計を読み解くのに特に重要なサブクラスだろう。クラス
Text
はノードツリーの末端オブジェクトになる。子ノードも属性も存在しない。オブジェクトのコピーが可能。クラス
Element
がノードツリーのオブジェクトの基本機能、子ノードと属性値へのアクセスのためのインターフェイスを提供する。オブジェクトのコピーが可能。このクラスそれ自体もいずれ解読したい。
クラス
document
はドキュメントツリーのルートノードのための型だ。これは解読するなら別ページにしたい。
クラス
Element
の下には大量のサブクラスが存在するが、インターフェイスが新規に追加されていることはほぼない。代わりに Visitor がその辺を賄うという設計だ。一般に、ノードオブジェクトを生成するのはクラス
State
のサブクラスのそれぞれのメソッドとなる。入力の reStructuredText データを一行一行構文解析すると同時に、順次オブジェクトを生成する。例えば
doctest_block
オブジェクトを生成するのは、クラスdocutils.parsers.rst.states.Body
のメソッドdoctest
による。生成したオブジェクトをメンバーデータであるオブジェクトparent
に収納する。クラス
Element
の継承グラフの最下層クラス群は名前がsnake_case
になっている。固有のコードが存在しないクラスの多重継承を多用している。
クラス Admonition
¶
直接のスーパークラスは
Body
ひとつ。このクラス固有のコードがない。例外クラスの定義よろしく単に
pass
してあるだけだ。直接のサブクラスは次のものがある:
attention
,caution
,danger
,error
,important
,note
,tip
,hint
,warning
,admonition
以上。これらのサブクラスにも固有のコードがない。
これらのサブクラスにはもう一つだけスーパークラスを持つ。すなわち
Element
だ。
クラス BackLinkable
¶
このクラスにはスーパークラスがない。
このクラス固有のコードがない。
直接のサブクラスは次のものがある:
footnote
,citation
そしてsystem_message
だ。これらのサブクラスは必ず
Element
をもスーパークラスに持つ。クラス
footnote
とcitation
には固有のコードがない。クラス
system_message
は少々特殊な用途があるようだ。
クラス Bibliographic
¶
このクラスにはスーパークラスがない。
固有のコードもない。
直接のサブクラスは次のものがある:
docinfo
,author
,authors
,organization
,address
,contact
,version
,revision
,status
,date
,copyright
以上。いずれのサブクラスも固有のコードがない。
いずれもあと一つスーパークラスを持つ。
Element
,TextElement
またはFixedTextElement
に限る。
クラス Body
¶
このクラスにはスーパークラスがない。
固有のコードもない。
直接のサブクラスは次のものがある:
General
,Sequential
,Admonition
,Special
以上。いずれのサブクラスも固有のコードがない。
いずれのサブクラスも
Body
以外のスーパークラスがない。
クラス Decorative
¶
直接のスーパークラスは
PreBibliographic
ただ一つだ。固有のコードがない。
直接のサブクラスは次のとおり:
decoration
,header
,footer
の三つ。どのサブクラスも、もう一つのスーパークラスとして
Element
を継承する。クラス
decoration
は小文字クラスにしては珍しく固有のメソッドがある。すなわちget_header
とget_footer
だ。どちらも子ノード列の先頭と末尾要素へのアクセスに他ならない。一方、クラスheader
とfooter
には固有のコードがない。
クラス FixedTextElement
¶
クラス FixedTextElement
は書式化済みのテキストを直接含む要素ということだ。
スーパークラスは
TextElement
ただ一つ。サブクラスとしては次のものがある:
address
,literal_block
,doctest_block
,math_block
,comment
,raw
以上。各サブクラスの他のスーパークラスとしては色々なパターンがある。
どのサブクラスにも固有のコードがない。
メンバーとしては
__init__
がオーバーライド定義されていて、常にxml:space
属性値がpreserve
に設定済みになる。
クラス General
¶
スーパークラスは
Body
ただ一つ。固有のコードがない。
サブクラスはかなりのものがある:
paragraph
,compound
,container
,literal_block
,doctest_block
,math_block
,line_block
,block_quote
,footnote
,citation
,figure
,table
,reference
,image
以上。これらのサブクラスは複数のスーパークラスから継承しており、必ず
Element
またはそのサブクラスを派生元リストに含んでいる。
クラス Inline
¶
文書中のインライン要素をマークアップするためのクラス群の共通スーパークラス。
スーパークラスおよび固有のコードがない。
サブクラスが多数ある。
クラス
image
を除いて、いずれもクラスTextElement
からも派生している。クラス
image
を除いて、まともなコードがない。image
にはメソッドastext
がElement
からオーバーライドされている。
クラス Invisible
¶
出力には現れることのない内部要素のためのスーパークラス。
スーパークラスは
PreBibliographic
だ。このクラスには固有のコードがない。
サブクラスは次のとおり:
comment
,substitution_definition
,target
,pending
の以上だ。いずれのサブクラスも複数のスーパークラスから派生している。
pending
を除いてクラスに固有のコードがない。
クラス Labeled
¶
これは最初の要素として label
を含む要素を表すスーパークラスだ。
スーパークラスもコードもない空のクラス。
サブクラスは
footnote
とcitation
の二つ。いずれも同じスーパークラス群から派生しており、固有のコードがないことも共通している。
クラス Part
¶
スーパークラスも固有のコードもない空のクラス。
サブクラスが大量にある。一例を挙げると
list_item
,definition_list_item
,term
,classifier
,definition
,field
,field_name
,field_body
,option
,option_argument
,option_group
,option_list_item
,option_string
,description
,line
,attribution
,label
,caption
,legend
,tgroup
,colspec
,thead
,tbody
,row
,entry
といったところだ。いずれももう一つのスーパークラスから派生している。型は
Element
またはTextElement
に限られている。基本的にはサブクラス固有のコードはないものが多いが、一部
option
系とline
には若干のコードがある。
クラス PreBibliographic
¶
これは Bibliographic
ノードよりも前の位置に出現する文書要素のためのスーパークラスだ。
スーパークラスもコードもない空のクラス。
サブクラスは次のとおり:
Decorative
,Invisible
,title
,subtitle
,system_message
,raw
以上。最初の二つのサブクラスは先述のとおり。
クラス Referential
¶
スーパークラスは
Resolvable
ただ一つ。コードはない。
サブクラスは次の三つ:
reference
,footnote_reference
,citation_reference
以上。いずれもスーパークラス
Inline
とTextElement
から派生している。reference
だけはさらにGeneral
からも派生している。サブクラス固有のコードはない。
クラス Resolvable
¶
スーパークラスはない。
コードとしてはクラス属性
resolved = 0
が定義されているのみ。サブクラスは
Referential
とTargetable
の二つがある。いずれのサブクラスもResolvable
以外のスーパークラスからは派生していない。
クラス Root
¶
これは構文木の根要素のためだけに存在するクラスと言える。
スーパークラスも固有のコードもない。
サブクラスは
document
ただ一つ。document
に関しては別の箇所で詳しく見てきたい。
クラス Sequential
¶
これは配列のような要素を表すためのスーパークラスとして存在する。
スーパークラスは
Body
ただ一つ。クラス固有のコードはない。
サブクラスは次のとおり:
bullet_list
,enumerated_list
,definition_list
,field_list
,option_list
以上。いずれもクラス
Element
からも派生。いずれもクラス固有のコードがない。
クラス Special
¶
何か特別な要素のためのスーパークラスということだろう。
スーパークラスは
Body
ただ一つ。クラス固有のコードはない。
サブクラスは
comment
,substitution_definition
,target
,system_message
,pending
,raw
だ。
クラス Structural
¶
スーパークラスも固有のコードもない。
サブクラスは次のとおり:
document
,section
,topic
,sidebar
,transition
以上。いずれもクラス
Element
からも派生している。document
以外のいずれのサブクラスにもクラス固有のコードがない。せいぜい docstring が書いてあるだけ。
クラス Targetable
¶
直接のスーパークラスは
Resolvable
ただ一つ。クラス属性
referenced
とindirect_reference_name
を定義する。サブクラスは
target
,footnote
,citation
の三つ。複数のスーパークラスがある。
クラス固有のコードはない。
クラス Titular
¶
これは見出しに関係する要素のためのスーパークラスだ。
スーパークラスも固有のコードもない。
サブクラスは
title
,subtitle
,rubric
の三つ。必ず
TextElement
をスーパークラスとする。クラス固有のコードはない。
感想¶
文字列
line
を grep するのがたいへん難しい。メソッド
Node.traverse
系は generator にできるだろうか。クラス
Element
における演算子のオーバーロードは注意したい。もしかするとelem += x
で「要素x
を子要素とする」の意味があるかもしれない。オブジェクト生成は構文解析時になされるので、ノートが本節で完結しない。
実はクラス
Element
以下の継承グラフを DOT で描いてみたのだが、何の省略の工夫もせずにグラフを定義したところ、幅 6000 ピクセル超の画像になってしまった。ブラウザーの画面幅に収まらない図表は使い物にならないので、ボツにした。