20.7. xml.dom.minidom
--- 最小限の DOM の実装¶
ソースコード: Lib/xml/dom/minidom.py
xml.dom.minidom
は、 Document Object Model インタフェースの最小の実装です。他言語の実装と似た API を持ちます。このモジュールは、完全な DOM に比べて単純で、非常に小さくなるように意図されています。 DOM について既に熟知しているユーザを除き、 XML 処理には代わりに xml.etree.ElementTree
モジュールを使うことを検討すべきです。
警告
xml.dom.minidom
モジュールは悪意を持って作成されたデータに対して安全ではありません。信頼できないデータや認証されていないデータをパースする必要がある場合は XML の脆弱性 を参照してください。
DOM アプリケーションは通常、XML を DOM に解析 (parse) することで開始します。 xml.dom.minidom
では、以下のような解析用の関数を介して行います:
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>')
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 パーザを、何らかの SAX パーザからくる解析イベント (parse event) を受け取って DOM ツリーに変換できるような "DOM ビルダ (DOM builder)" に結合することです。関数は誤解を招くような名前になっているかもしれませんが、インタフェースについて学んでいるときには理解しやすいでしょう。文書の解析はこれらの関数が戻るより前に完結します; 要するに、これらの関数自体はパーザ実装を提供しないということです。
"DOM 実装" オブジェクトのメソッドを呼び出して Document
を生成することもできます。このオブジェクトは、 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()
は、 DOM API に対する xml.dom.minidom
特有の拡張です。ノードに対して unlink()
を呼び出した後は、ノードとその下位ノードは本質的には無意味なものとなります。このメソッドを呼び出さなくても、 Python のガベージコレクタがいつかはツリーのオブジェクトを後片付けします。
参考
- Document Object Model (DOM) Level 1 Specification
xml.dom.minidom
でサポートされている W3C の DOM に関する勧告。
20.7.1. DOM オブジェクト¶
Python の DOM API 定義は xml.dom
モジュールドキュメントの一部として与えられています。この節では、 xml.dom
の API と xml.dom.minidom
との違いについて列挙します。
-
Node.
unlink
()¶ DOM との内部的な参照を破壊して、循環参照ガベージコレクションを持たないバージョンの Python でもガベージコレクションされるようにします。循環参照ガベージコレクションが利用できる場合でも、このメソッドを使えば大量のメモリをすぐに使えるようにできるため、不要になったらすぐに DOM オブジェクトに対してこのメソッドを呼ぶのが良い習慣です。このメソッドは
Document
オブジェクトに対して呼び出すだけでよいのですが、あるノードの子ノードを破棄するために子ノードに対して呼び出してもかまいません。with
文を使用することで、このメソッドを明示的に呼ばないようにできます。with
ブロックから出る時に自動的に次のコードが dom を unlink します:with xml.dom.minidom.parse(datasource) as dom: ... # Work with dom.
-
Node.
writexml
(writer, indent="", addindent="", newl="")¶ XML を writer オブジェクトに書き込みます。 writer は、ファイルオブジェクトインタフェースの
write()
に該当するメソッドを持たなければなりません。 indent 引数には現在のノードのインデントを指定します。 addindent 引数には現在のノードの下にサブノードを追加する際のインデント増分を指定します。 newl には、改行時に行末を終端する文字列を指定します。Document
ノードでは、追加のキーワード引数 encoding を使って XML ヘッダの encoding フィールドを指定することができます。
20.7.2. 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("<title>%s</title>" % getText(title.childNodes))
def handleSlideTitle(title):
print("<h2>%s</h2>" % getText(title.childNodes))
def handlePoints(points):
print("<ul>")
for point in points:
handlePoint(point)
print("</ul>")
def handlePoint(point):
print("<li>%s</li>" % getText(point.childNodes))
def handleToc(slides):
for slide in slides:
title = slide.getElementsByTagName("title")[0]
print("<p>%s</p>" % getText(title.childNodes))
handleSlideshow(dom)
20.7.3. 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 整数オブジェクトに対応付けられます。DOMString
型は Python 文字列型に対応付けられます。xml.dom.minidom
ではバイト列か文字列のどちらかに対応づけられますが、通常文字列を生成します。DOMString
型の値は、W3C の DOM 仕様で、IDLnull
値になってもよいとされている場所ではNone
になることもあります。const
宣言を行うと、 (xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE
のように) 対応するスコープ内の変数に対応付けを行います; これらは変更してはなりません。DOMException
は現状ではxml.dom.minidom
でサポートされていません。その代わり、xml.dom.minidom
は、TypeError
やAttributeError
といった標準の Python 例外を使います。NodeList
オブジェクトは Python の組み込みのリスト型を使って実装されています。これらのオブジェクトは DOM 仕様で定義されたインタフェースを提供していますが、以前のバージョンの Python では、公式の API をサポートしていません。しかしながら、これらの API は W3C 勧告で定義されたインタフェースよりも "Python 的な" ものになっています。
以下のインタフェースは xml.dom.minidom
では全く実装されていません:
DOMTimeStamp
DocumentType
DOMImplementation
CharacterData
CDATASection
Notation
Entity
EntityReference
DocumentFragment
これらの大部分は、ほとんどの DOM のユーザにとって一般的な用途として有用とはならないような XML 文書内の情報を反映しています。
脚注
[1] | XML 出力に含まれるエンコード名は適切な規格に従っていなければなりません。例えば "UTF-8" は有効ですが、 "UTF8" は XML 文書の宣言では有効ではありません。後者はエンコード名として Python に認められるとしてもです。https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncodingDecl と https://www.iana.org/assignments/character-sets/character-sets.xhtml を参照してください。 |