xml.dom.minidom --- 最小限の DOM の実装¶
ソースコード: Lib/xml/dom/minidom.py
xml.dom.minidom は Document Object Model インターフェースの最小限の実装で、他の言語の実装と同様の API を備えています。
完全な DOM より単純で、大幅に小さい実装を目指しています。
DOM にまだ習熟していない場合は、XML の処理に xml.etree.ElementTree モジュールを使うことを検討してください。
注釈
信頼できないデータや、認証されていないデータを解析する場合は、XML のセキュリティ を参照してください。
DOM アプリケーションは通常、XML を解析して DOM を作成するところから始まります。
xml.dom.minidom では、解析用の関数でこれを行います。
from xml.dom.minidom import parse, parseString
dom1 = parse('c:\\temp\\mydata.xml') # ファイル名を指定して XML ファイルを解析する
datasource = open('c:\\temp\\mydata.xml')
dom2 = parse(datasource) # 開いているファイルを解析する
dom3 = parseString('<myxml>Some data<empty/> some more data</myxml>')
parse() 関数はファイル名か、開かれたファイルオブジェクトを引数にとることができます。
- xml.dom.minidom.parse(filename_or_file, parser=None, bufsize=None)¶
与えられた入力から
Documentを返します。 filename_or_file はファイル名でもファイルオブジェクトでもかまいません。 parser を指定する場合、SAX2 パーザオブジェクトでなければなりません。この関数はパーザの文書ハンドラを変更し、名前空間サポートを有効にします; (エンティティリゾルバ (entity resolver) のような) 他のパーザ設定は前もっておこなわなければなりません。
XML データを文字列で持っている場合、 parseString() を代わりに使うことができます:
- xml.dom.minidom.parseString(string, parser=None)¶
string を表わす
Documentを返します。このメソッドは、文字列に対するio.StringIOオブジェクトを作成し、それをparse()に渡します。
これらの関数は両方とも、文書の内容を表現する Document オブジェクトを返します。
parse() 関数と parseString() 関数は、XML パーザを「DOM ビルダー」に接続します。
このビルダーは SAX パーザから解析イベントを受け取り、DOM ツリーに変換できます。
関数名は誤解を招くかもしれませんが、インターフェースを学ぶ際にはわかりやすい名前です。
関数から戻る前に文書の解析は完了します。
これらの関数自体がパーザを実装しているわけではない、というだけです。
「DOM 実装」オブジェクトのメソッドを呼び出して Document を作成することもできます。
DOM 実装オブジェクトは、xml.dom パッケージまたは xml.dom.minidom モジュールの getDOMImplementation() 関数を呼び出すと取得できます。
Document を取得したら、子ノードを追加して DOM を構築できます。
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)
DOM 文書オブジェクトを取得すると、そのプロパティとメソッドを使って XML 文書の各部分にアクセスできます。
これらのプロパティは DOM 仕様で定義されています。
文書オブジェクトの主要なプロパティは documentElement です。
このプロパティは、XML 文書の他のすべての要素を含む主要な要素を返します。
プログラム例を示します。
dom3 = parseString("<myxml>Some data</myxml>")
assert dom3.documentElement.tagName == "myxml"
DOM ツリーを使い終えたら、unlink() メソッドを呼び出して、不要になったオブジェクトの早期解放を促すことができます。
unlink() は xml.dom.minidom 固有の DOM API 拡張で、呼び出すとそのノードと子孫は実質的に使えなくなります。
呼び出さない場合も、Python のガベージコレクタがいずれツリー内のオブジェクトを処理します。
参考
- Document Object Model (DOM) Level 1 Specification
xml.dom.minidomがサポートする DOM に関する W3C 勧告です。
DOM オブジェクト¶
Python 向けの DOM API の定義は、xml.dom モジュールのドキュメントの一部として記載されています。
この節では、その API と xml.dom.minidom の違いを挙げます。
- Node.unlink()¶
DOM との内部的な参照を破壊して、循環参照ガベージコレクションを持たないバージョンの Python でもガベージコレクションされるようにします。循環参照ガベージコレクションが利用できる場合でも、このメソッドを使えば大量のメモリをすぐに使えるようにできるため、不要になったらすぐに DOM オブジェクトに対してこのメソッドを呼ぶのが良い習慣です。このメソッドは
Documentオブジェクトに対して呼び出すだけでよいのですが、あるノードの子ノードを破棄するために子ノードに対して呼び出してもかまいません。withステートメントを使用することで、このメソッドを明示的に呼ばないようにできます。withブロックから出る時に自動的に次のコードが dom を unlink します:with xml.dom.minidom.parse(datasource) as dom: ... # dom を使って処理する。
- Node.writexml(writer, indent='', addindent='', newl='', encoding=None, standalone=None)¶
XML を writer オブジェクトに書き込みます。 writer は入力としてテキストは受け付けますが、バイト列は受け付けません。 writer はファイルオブジェクトインターフェースの
write()に該当するメソッドを持たなければなりません。 indent 引数には現在のノードのインデントを指定します。 addindent 引数には現在のノードの下にサブノードを追加する際のインデント増分を指定します。 newl には、改行時に行末を終端する文字列を指定します。Documentノードでは、追加のキーワード引数 encoding を使って XML ヘッダの encoding フィールドを指定することができます。同様に、standalone 引数を明示的に指定すると、スタンドアロン文書宣言がXMLのプロローグに追加されます。値が
Trueの場合、standalone="yes"が追加され、それ以外の場合"no"が設定されます。引数を指定しない場合は文書から宣言が省略されます。バージョン 3.8 で変更:
writexml()メソッドはユーザーが指定した属性の順序を保持するようになりました。バージョン 3.9 で変更: standalone パラメータが追加されました。
- Node.toxml(encoding=None, standalone=None)¶
DOM ノードによって表わされる XML を含んだ文字列またはバイト文字列を返します。
明示的に encoding [1] 引数を渡すと、結果は指定されたエンコードのバイト文字列になります。encoding 引数なしだと、結果は unicode 文字列です。また、結果として生じる文字列の中の XML 宣言はエンコーディングを指定しません。XML のデフォルトエンコーディングは UTF-8 なので、この文字列を UTF-8 以外でエンコードすることはおそらく正しくありません。
standalone 引数は
writexml()と全く同じ動作をします。バージョン 3.8 で変更:
toxml()メソッドはユーザーが指定した属性の順序を保持するようになりました。バージョン 3.9 で変更: standalone パラメータが追加されました。
- Node.toprettyxml(indent='\t', newl='\n', encoding=None, standalone=None)¶
文書の整形されたバージョンを返します。 indent はインデントを行うための文字で、デフォルトはタブです; newl には行末で出力される文字列を指定し、デフォルトは
\nです。encoding 引数は
toxml()の対応する引数と同様に振る舞います。standalone 引数は
writexml()と全く同じ動作をします。バージョン 3.8 で変更:
toprettyxml()メソッドはユーザーが指定した属性の順序を保持するようになりました。バージョン 3.9 で変更: standalone パラメータが追加されました。
DOM の例¶
以下のプログラム例は、単純なプログラムのかなり現実的な例です。特にこの例に関しては、DOM の柔軟性をあまり活用してはいません。
import xml.dom.minidom
document = """\
<slideshow>
<title>Demo slideshow</title>
<slide><title>Slide title</title>
<point>This is a demo</point>
<point>Of a program for processing slides</point>
</slide>
<slide><title>Another demo slide</title>
<point>It is important</point>
<point>To have more than</point>
<point>one slide</point>
</slide>
</slideshow>
"""
dom = xml.dom.minidom.parseString(document)
def getText(nodelist):
rc = []
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
rc.append(node.data)
return ''.join(rc)
def handleSlideshow(slideshow):
print("<html>")
handleSlideshowTitle(slideshow.getElementsByTagName("title")[0])
slides = slideshow.getElementsByTagName("slide")
handleToc(slides)
handleSlides(slides)
print("</html>")
def handleSlides(slides):
for slide in slides:
handleSlide(slide)
def handleSlide(slide):
handleSlideTitle(slide.getElementsByTagName("title")[0])
handlePoints(slide.getElementsByTagName("point"))
def handleSlideshowTitle(title):
print(f"<title>{getText(title.childNodes)}</title>")
def handleSlideTitle(title):
print(f"<h2>{getText(title.childNodes)}</h2>")
def handlePoints(points):
print("<ul>")
for point in points:
handlePoint(point)
print("</ul>")
def handlePoint(point):
print(f"<li>{getText(point.childNodes)}</li>")
def handleToc(slides):
for slide in slides:
title = slide.getElementsByTagName("title")[0]
print(f"<p>{getText(title.childNodes)}</p>")
handleSlideshow(dom)
minidom と DOM 標準¶
xml.dom.minidom モジュールは、基本的には DOM 1.0 に準拠した DOM で、DOM 2 の機能の一部 (主に名前空間の機能) を備えています。
Python における DOM インターフェースは率直なものです。以下の対応付け規則が適用されます:
インターフェースはインスタンスオブジェクトを介してアクセスされます。アプリケーション自身から、クラスをインスタンス化してはなりません;
Documentオブジェクト上で利用可能な生成関数 (creator function) を使わなければなりません。派生インターフェースでは基底インターフェースの全ての演算 (および属性) に加え、新たな演算をサポートします。演算はメソッドとして使われます。DOM では
inパラメタのみを使うので、引数は通常の順番 (左から右へ) で渡されます。オプション引数はありません。void演算はNoneを返します。IDL 属性はインスタンス属性に対応付けられます。OMG IDL 言語における Python への対応付けとの互換性のために、属性
fooはアクセサメソッド_get_foo()および_set_foo()でもアクセスできます。readonly属性は変更してはなりません; とはいえ、これは実行時には強制されません。short int、unsigned int、unsigned long long、およびboolean型は、全て Python 整数オブジェクトに対応付けられます。The type
DOMStringmaps to Python strings.xml.dom.minidomsupports either bytes or strings, but will normally produce strings. Values of typeDOMStringmay also beNonewhere allowed to have the IDLnullvalue by the DOM specification from the W3C.const宣言を行うと、 (xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODEのように) 対応するスコープ内の変数に対応付けを行います; これらは変更してはなりません。DOMExceptionis currently not supported inxml.dom.minidom. Instead,xml.dom.minidomuses standard Python exceptions such asTypeErrorandAttributeError.NodeListとNamedNodeMapの各インターフェースには 2 種類の実装があり、追加のメソッドと操作を提供します。childNodesはlistのサブクラスです。 子を持てないノードではtupleのサブクラスです。 イテレーション、連結、インデックス指定、スライスをサポートしています。attributesは、len()、in演算子、名前または(namespaceURI, localName)タプルによる添字アクセス、代入と削除、 およびget()、keys()、keysNS()、values()、items()、itemsNS()の各メソッドをサポートしています。entitiesとnotationsは読み取り専用で、len()と名前による添字アクセスだけをサポートしています。strictErrorCheckingとspecifiedは常にFalseです。removeAttribute()とremoveAttributeNS()は、該当する属性がない場合にNotFoundErrを送出します。 一方、DOM 仕様では、この場合は何もしないことになっています。
xml.dom.minidom には以下のインターフェースの実装がありません。
DOMTimeStampEntityReference
これらの大部分は、ほとんどの DOM のユーザにとって一般的な用途として有用とはならないような XML 文書内の情報を反映しています。
脚注