\section{\module{xml.dom.minidom} ---
         軽量な DOM 実装}

\declaremodule{standard}{xml.dom.minidom}
\modulesynopsis{軽量な文書オブジェクトモデルの実装。}
\moduleauthor{Paul Prescod}{paul@prescod.net}
\sectionauthor{Paul Prescod}{paul@prescod.net}
\sectionauthor{Martin v. L\"owis}{loewis@informatik.hu-berlin.de}

\versionadded{2.0}

\module{xml.dom.minidom} は、軽量な文書オブジェクトモデルインタフェース
の実装です。この実装では、完全な DOM よりも
単純で、かつ十分に小さくなるよう意図しています。

DOM アプリケーションは典型的に、XML を DOM に解析 (parse) することで
開始します。\module{xml.dom.minidom} では、以下のような解析用の関数
を介して行います:

\begin{verbatim}
from xml.dom.minidom import parse, parseString

dom1 = parse('c:\\temp\\mydata.xml') # parse an XML file by name

datasource = open('c:\\temp\\mydata.xml')
dom2 = parse(datasource)   # parse an open file

dom3 = parseString('<myxml>Some data<empty/> some more data</myxml>')
\end{verbatim}

\function{parse()} 関数はファイル名か、開かれたファイルオブジェクト
を引数にとることができます。

\begin{funcdesc}{parse}{filename_or_file{, parser}}
与えられた入力から \class{Document} を返します。 \var{filename_or_file}
はファイル名でもファイルオブジェクトでもかまいません。\var{parser}
を指定する場合、SAX2 パーザオブジェクトでなければなりません。
この関数はパーザの文書ハンドラを変更し、名前空間サポートを有効に
します; (エンティティリゾルバ (entity resolver) のような) 他のパーザ設定
は前もっておこなわなければなりません。
\end{funcdesc}

XML データを文字列で持っている場合、\function{parseString()} を
代わりに使うことができます:

\begin{funcdesc}{parseString}{string\optional{, parser}}
\var{string} を表現する \class{Document} を返します。このメソッドは
文字列に対する \class{StringIO} オブジェクトを生成して、その
オブジェクトを \function{parse} に渡します。
\end{funcdesc}

これらの関数は両方とも、文書の内容を表現する \class{Document} オブジェクトを
返します。

\function{parse()} や \function{parseString()} といった関数が行うのは、
XML パーザを、何らかの SAX パーザからくる解析イベント (parse event) 
を受け取って DOM ツリーに変換できるような ``DOM ビルダ (DOM builder)'' 
に結合することです。関数は誤解を招くような名前になっているかも
しれませんが、インタフェースについて学んでいるときには理解しやすい
でしょう。文書の解析はこれらの関数が戻るより前に完結します; 要するに、
これらの関数自体はパーザ実装を提供しないということです。

``DOM 実装'' オブジェクトのメソッドを呼び出して \class{Document} を
生成することもできます。このオブジェクトは、\refmodule{xml.dom} 
パッケージ、または\module{xml.dom.minidom} モジュールの 
\function{getDOMImplementation()} 関数を呼び出して取得できます。
\module{xml.dom.minidom} モジュールの実装を使うと、常に
minidom 実装の \class{Document} インスタンスを返します。一方、
\refmodule{xml.dom} 版の関数では、別の実装によるインスタンスを
返すかもれません (\ulink{PyXML package}{http://pyxml.sourceforge.net/} 
がインストールされているとそうなるでしょう)。\class{Document}
を取得したら、DOM を構成するために子ノードを追加していくことができます:

\begin{verbatim}
from xml.dom.minidom import getDOMImplementation

impl = getDOMImplementation()

newdoc = impl.createDocument(None, "some_tag", None)
top_element = newdoc.documentElement
text = newdoc.createTextNode('Some textual content.')
top_element.appendChild(text)
\end{verbatim}

DOM 文書オブジェクトを手にしたら、XML 文書のプロパティやメソッドを
使って、文書の一部にアクセスすることができます。これらのプロパティは
DOM 仕様で定義されています。文書オブジェクトの主要なプロパティは
\member{documentElement} プロパティです。このプロパティは
XML 文書の主要な要素: 他の全ての要素を保持する要素、を与えます。
以下にプログラム例を示します:

\begin{verbatim}
dom3 = parseString("<myxml>Some data</myxml>")
assert dom3.documentElement.tagName == "myxml"
\end{verbatim}

DOM を使い終えたら、後片付けを行わなければなりません。
Python のバージョンによっては、循環的に互いを参照するオブジェクト
に対するガベージコレクションをサポートしていないため、この操作が
必要となります。この制限が全てのバージョンの Python から除去される
までは、循環参照オブジェクトが消去されないものとしてコードを
書くのが無難です。

DOM を片付けるには、 \method{unlink()} メソッドを呼び出します:

\begin{verbatim}
dom1.unlink()
dom2.unlink()
dom3.unlink()
\end{verbatim}

\method{unlink()} は、 DOM API に対する \module{xml.dom.minidom} 
特有の拡張です。ノードに対して \method{unlink()} を呼び出した後は、
ノードとその下位ノードは本質的には無意味なものとなります。

\begin{seealso}
  \seetitle[http://www.w3.org/TR/REC-DOM-Level-1/]{Document Object
            Model (DOM) Level 1 Specification}
           {\module{xml.dom.minidom} でサポートされている DOM の W3C 勧告。}
\end{seealso}


\subsection{DOM オブジェクト \label{dom-objects}}

Python の DOM API 定義は \refmodule{xml.dom} モジュールドキュメント
の一部として与えられています。この節では、\refmodule{xml.dom} の
API と \refmodule{xml.dom.minidom} との違いについて列挙します。


\begin{methoddesc}[Node]{unlink}{}
DOM との内部的な参照を破壊して、循環参照ガベージコレクションを
持たないバージョンの Python でもガベージコレクションされるように
します。循環参照ガベージコレクションが利用できても、このメソッドを
使えば、大量のメモリをすぐに使えるようにできるため、必要なくなったら
すぐにこのメソッドを DOM オブジェクトに対して呼ぶのが良い習慣です。
このメソッドは \class{Document} オブジェクトに対してだけ呼び出せば
よいのですが、あるノードの子ノードを放棄するために子ノードに対して
呼び出してもかまいません。
\end{methoddesc}

\begin{methoddesc}[Node]{writexml}{writer\optional{,indent=""\optional{,addindent=""\optional{,newl=""}}}}
XML を \var{writer} オブジェクトに書き込みます。 \var{writer}
は、ファイルオブジェクトインタフェースの \method{write()} に該当する
メソッドを持たなければなりません。
\var{indent} パラメタには現在のノードのインデントを指定します。
\var{addindent} パラメタには現在のノードの下にサブノードを
追加する際のインデント増分を指定します。
\var{newl} には、改行時に行末を終端する文字列を指定します。

\versionchanged[美しい出力をサポートするため、新たなキーワード引数
\var{indent}、\var{addindent}、および \var{newl} が追加されました]{2.1}

\versionchanged[\class{Document} ノードに対して、追加のキーワード引数
\var{encoding} を使って、XML ヘッダの encoding フィールドを指定できるように
なりました]{2.3}
\end{methoddesc}

\begin{methoddesc}[Node]{toxml}{\optional{encoding}}
DOM が表現している XML を文字列にして返します。

引数がなければ、 XML ヘッダは encoding を指定せず、
文書内の全ての文字をデフォルトエンコード方式で表示できない場合、
結果は Unicode 文字列となります。この文字列を UTF-8 以外の
エンコード方式でエンコードするのは不正であり、なぜなら UTF-8 が
XML のデフォルトエンコード方式だからです。

明示的な \var{encoding} 引数があると、結果は指定されたエンコード
方式によるバイト文字列となります。引数を常に指定するよう推奨します。
表現不可能なテキストデータの場合に \exception{UnicodeError} が送出されるのを
避けるため、encoding 引数は "utf-8" に指定するべきです。

\versionchanged[\var{encoding} が追加されました]{2.3}
\end{methoddesc}

\begin{methoddesc}[Node]{toprettyxml}{\optional{indent\optional{, newl}}}
美しく出力されたバージョンの文書を返します。\var{indent} は
インデントを行うための文字で、デフォルトはタブです; \var{newl} 
には行末で出力される文字列を指定し、デフォルトは \code{\e n} です。

\versionadded{2.1}
\versionchanged[encoding 引数の追加; \method{toxml} を参照]{2.3}
\end{methoddesc}

以下の標準 DOM メソッドは、\refmodule{xml.dom.minidom} では特別な
注意をする必要があります:

\begin{methoddesc}[Node]{cloneNode}{deep}
このメソッドは Python 2.0 にパッケージされているバージョンの
\refmodule{xml.dom.minidom} にはありましたが、これには深刻な
障害があります。以降のリリースでは修正されています。
\end{methoddesc}


\subsection{DOM の例 \label{dom-example}}

以下のプログラム例は、かなり現実的な単純なプログラムの例です。
特にこの例に関しては、DOM の柔軟性をあまり活用してはいません。

\verbatiminput{minidom-example.py}


\subsection{minidom と DOM 標準 \label{minidom-and-dom}}

\refmodule{xml.dom.minidom} モジュールは、本質的には
DOM 1.0 互換の DOM に、いくつかの DOM 2 機能 (主に名前空間
機能) を追加したものです。

Python における DOM インタフェースは率直なものです。以下の
対応付け規則が適用されます:


\begin{itemize}
\item インタフェースはインスタンスオブジェクトを介してアクセスされます。
アプリケーション自身から、クラスをインスタンス化してはなりません;
\class{Document} オブジェクト上で利用可能な生成関数 (creator function)
を使わなければなりません。導出インタフェースでは基底インタフェースの
全ての演算 (および属性) に加え、新たな演算をサポートします。

\item 演算はメソッドとして使われます。DOM では \keyword{in} パラメタ
のみを使うので、引数は通常の順番 (左から右へ) で渡されます。
オプション引数はありません。\keyword{void} 演算は\code{None}
を返します。

\item IDL 属性はインスタンス属性に対応付けられます。OMG IDL 言語
における Python への対応付けとの互換性のために、属性 \code{foo}
はアクセサメソッド \method{_get_foo()} および \method{_set_foo()}
でもアクセスできます。 \keyword{readonly} 属性は変更しては
なりません; とはいえ、これは実行時には強制されません。

\item \code{short int} 、 \code{unsigned int} 、 \code{unsigned
      long long} 、および \code{boolean} 型は、全て Python 整数
オブジェクトに対応付けられます。

\item \code{DOMString} 型は Python 文字列型に対応付けられます。
\refmodule{xml.dom.minidom} ではバイト文字列 (byte string) および
Unicode 文字列のどちらかに対応づけられますが、通常 Unicode 文字列
を生成します。\code{DOMString} 型の値は、W3C の DOM 仕様で、IDL
 \code{null} 値になってもよいとされている場所では \code{None} に
なることもあります。

\item \keyword{const} 宣言を行うと、
(\code{xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE} のように)
対応するスコープ内の変数に対応付けを行います;
これらは変更してはなりません。

\item \code{DOMException} は現状では \refmodule{xml.dom.minidom}
でサポートされていません。その代わり、\refmodule{xml.dom.minidom} 
は、\exception{TypeError} や \exception{AttributeError} といった
標準の Python 例外を使います。

\item \class{NodeList} オブジェクトは Python の組み込みリスト型を
使って実装されています。 Python 2.2 からは、これらのオブジェクトは
DOM 仕様で定義されたインタフェースを提供していますが、それ以前の
バージョンの Python では、公式の API をサポートしていません。
しかしながら、これらの API は W3C 勧告で定義されたインタフェース
よりも ``Python 的な'' ものになっています。
\end{itemize}


以下のインタフェースは \refmodule{xml.dom.minidom} では全く実装
されていません:

\begin{itemize}
\item \class{DOMTimeStamp}

\item \class{DocumentType} (added in Python 2.1)

\item \class{DOMImplementation} (added in Python 2.1)

\item \class{CharacterData}

\item \class{CDATASection}

\item \class{Notation}

\item \class{Entity}

\item \class{EntityReference}

\item \class{DocumentFragment}
\end{itemize}

これらの大部分は、ほとんどの DOM のユーザにとって一般的な用途として有用
とはならないような XML 文書内の情報を反映しています。
