クラス 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 ピクセル超の画像になってしまった。ブラウザーの画面幅に収まらない図表は使い物にならないので、ボツにした。