本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

魅力的なPython: Python用XMLツールの再考

ツールとコードに関する最新情報

David Mertz, Ph.D (mertz@gnosis.cx), Author, Gnosis Software, Inc.
Photo of David Mertz
David Mertz氏は多くの分野で活躍しています。ソフトウェア開発や、それについて著述もしています。その他、学術政策理念について分野を問わず、関係する雑誌に記事も書いています。かなり以前には、超限集合論、ロジック、モデル理論などを研究していました。その後、労働組合組織者として活動していました。そして、David Mertz氏自身は人生の半ばにもまだ達していないと思っているので、これから何かほかの仕事をするかもしれません。

概要: David Mertzによる「魅力的なPython」 の第1回と第2回で、PythonにおけるXML処理の概要を説明しました。しかし、当初の記事から1年経過する間に、Python用XMLツールの状況は大きく進歩しました。残念ながら、こうした進歩のほとんどには下位互換性がありません。今回の特別号の記事で、著者はXMLツールに関する以前の説明を再考し、最新のコード例を紹介しています。

日付:  2001年 6月 01日
レベル:  中級 この記事の原文:  英語
アクティビティー: 1943 ビュー
お気軽にご意見・ご感想をお寄せください: 


Pythonは、多くの点でXML文書処理用の理想的言語と言えます。Perl、REBOL、REXX、TCLのように、強力なテキスト操作機能を備えた柔軟なスクリプト言語です。しかも、XML文書にコード化されるデータ構造は通常、ほとんどのタイプのテキスト・ファイル(またはストリーム)より大規模で複雑です。

Python 2.0におけるXMLサポートのメインテナンス

一般に、「何行か読み取ってそれを正規の表現と比較する」というおなじみのスタイルのテキスト処理は、XMLを適切に構文解析して処理するのにはあまり適していません。Pythonは、幸いにも(他の一般的言語と比べると)、複雑なデータ構造(通常はクラスと属性を有する)を簡単に処理する手段と、XMLの構文解析、処理、および生成に役立つ一連のXML関連モジュールを兼ね備えています。

Python用各種XMLツールのメインテナンス作業は、その大半がXML-SIG(Special Interest Group)のメンバーによって行われています。XML-SIGは、他のPython Special Interest Group同様、メーリング・リスト、リスト・アーカイブ、役に立つリファレンス、ドキュメンテーション、標準パッケージその他リソース(この記事末尾の参考文献 を参照)のメインテナンスを行っています。

Python 2.0から、Python標準ディストリビューションにはXML-SIGプロジェクトのほとんどが含まれるようになりました。最新XML-SIGパッケージには、Python標準ディストリビューションに含まれていない「最先端」機能の一部が含まれているかもしれませんが、Python 2.0におけるXMLサポートは、この記事の考察を始めとする大部分の目的に対して、読者の皆さんが関心を抱いているものと言えそうです。幸いなことに、Python 2.0+は、旧バージョンのPythonにおけるxmllib の基本サポートより大きく前進しています。最近では、PythonユーザーがDOMSAXおよびexpat の各XML処理技法からかなり自由に選べるようになっています(他のプログラミング言語の使用経験があるXML開発者なら、これら技法についてすべてご存じでしょう)。


モジュール:xmllib

xmllib は妥当性検査をしない低水準パーサーです。xmllib は、アプリケーション・プログラマーがクラスXMLParserをオーバーライドすることによって動作し、固有タグか汎用タグ、または文字エンティティーなどの文書エレメントを処理するメソッドを提供します。Python 2.0+での xmllib の使用法は、Python 1.5xでの使用法と変わっていません。ストリーム指向ですが、言語間でも開発者間でもより標準的であることから、ほとんどの場合はSAX技法を使用する方がよいでしょう。

この記事で紹介する例は最初のコラムと同じファイルで、quotations.dtd というDTDと、このDTDのsample.xml という文書です (この記事で言及するファイルのアーカイブについては参考文献 を参照)。以下のコードは、sample.xml に含まれる各引用の最初の数行を表示し、未知のタグとエンティティーのごく単純なASCII標識を生成します。構文解析されたテキストは、順次ストリームとして処理されます。タグ内の文字ストリング(#PCDATA)、検出されたタグのリスト/ディクショナリーなど、どのようなアキュムレーターを使用するかはプログラマーの仕事になります。


リスト1: try_xmllib.py
                
                
import xmllib, string
class
                 QuotationParser(xmllib.XMLParser):
"""Crude xmllib extractor for quotations.dtd document"""
def
                 __init__(self):
xmllib.XMLParser.__init__(self)
self.thisquote = '' # quotation accumulator
def
                 handle_data(self, data):
self.thisquote = self.thisquote + data
def
                 syntax_error(self, message):
pass
                def
                 start_quotations(self, attrs): # top level tag
print '--- Begin Document ---'
def
                 start_quotation(self, attrs):
print 'QUOTATION:'
def
                 end_quotation(self):
print string.join(string.split(self.thisquote[:230]))+ '...',
print '('+str(len(self.thisquote))+ ' bytes)\n'
self.thisquote = ''
def
                 unknown_starttag(self, tag, attrs):
self.thisquote = self.thisquote + '{'
def
                 unknown_endtag(self, tag):
self.thisquote = self.thisquote + '}'
def
                 unknown_charref(self, ref):
self.thisquote = self.thisquote + '?'
def
                 unknown_entityref(self, ref):
self.thisquote = self.thisquote + '#'
if __name__ == '__main__':
parser = QuotationParser()
for c in open( "sample.xml").read():
parser.feed(c)
parser.close()


妥当性検査

標準のXMLサポートを超えるものが求められる理由の1つとして、構文解析と同時に妥当性検査の実行が必要な場合が挙げられます。残念ながら、標準Python 2.0 XMLパッケージには妥当性検査実行パーサーは含まれていません。

xmlproc は、ほぼ完全な妥当性検査を実行するPythonネイティブ・パーサーです。妥当性検査を実行するパーサーが必要な場合は、現在のところ xmlproc がPythonにおける唯一の選択肢です。さらに、xmlproc は他のパーサーが提供していない各種高水準検査用インターフェースを提供しています。


パーサーの選択

Simple API for XML(SAX)を使用する場合(他のほとんどのツールがSAXをベースに作成されていることから、何か高度なものを求めるなら当然これを使用すべきですが)、パーサーから得られるデータの分類作業の多くをプログラマーに代わって実行させることができます。モジュールxml.sax には、「最適」パーサーを自動選択する機能があります。Python 2.0の標準インストールで選択できるパーサーは、C言語で記述された高速エクステンションexpatだけです。ただし、$PYTHONLIB/xml/parsers に別のパーサーをインストールすれば、それを選択対象にできます。パーサーのセットアップは、次のように簡単です。


リスト2: 最適パーサー選択のPythonコード行
                
                
import xml.sax
parser = xml.sax.make_parser()

引数を渡して特定パーサーを選択することもできますが、移植性を持たせるために、いずれ登場するさらに優れたパーサーに対する上位互換性を維持するうえでも、おそらくmake_parser() に任せるのが最善の方法と思われます。

xml.parsers.expat は直接インポートすることができます。その場合、SAXインターフェースでは提供されないいくつかの特殊技法が提供されます。この意味で、xml.parsers.expat はSAXと比べてやや「低水準」です。しかし、SAX技法はきわめて標準的なもので、ストリーム指向処理に最適です。ほとんどの場合、操作レベルとしてはSAXが最適です。make_parser() 関数は、一般的にexpat が実現しているパフォーマンスをどうにか達成できるため、現実の速度差はほとんど無視できる程度と思われます。


SAXとは

基本に戻りますが、そもそもSAXとは何でしょうか。適切な答えは以下のとおりです。

SAX(Simple API for XML)は、XMLパーサーの共通パーサー・インターフェースです。これによってアプリケーション作成者は、どのパーサーを現実に使用するかに関係なく、XMLパーサーを使用するアプリケーションを作成することができます(XML用のJDBCと考える)。? Lars Marius Garshol氏の「SAX for Python」より

SAXは、APIを提供するパーサー・モジュール同様、本質的にはXML文書の順次処理プログラムです。SAXの使用法はxmllib の例とほぼ同様ですが、抽象度のレベルはいくぶん高くなります。アプリケーション・プログラマーは、パーサー・クラスを定義する代わりに、使用するすべてのパーサーに登録するハンドラー ・クラスを定義します。DocumentHandler、DTDHandler、EntityResolverおよびErrorHandlerの4つのSAXインターフェース(それぞれいくつかメソッドがある)を定義する必要があります。また、パーサーを作成すると、オーバーライドしない限りデフォルトのインターフェースが接続されます。以下に、xmllib の例と同じタスクを実行するコードを示します。


リスト3: try_sax.py
                
"Simple SAX example, updated for Python 2.0+"
import string
import xml.sax
from xml.sax.handler import *
class
                 QuotationHandler(ContentHandler):
"""Crude extractor for quotations.dtd compliant XML document"""
def
                 __init__(self):
self.in_quote = 0
self.thisquote = ''
def
                 startDocument(self):
print '--- Begin Document ---'
def
                 startElement(self, name, attrs):
if name == 'quotation':
print 'QUOTATION:'
self.in_quote = 1
else:
self.thisquote = self.thisquote + '{'
def
                 endElement(self, name):
if name == 'quotation':
print string.join(string.split(self.thisquote[:230]))+ '...',
print '('+str(len(self.thisquote))+ ' bytes)\n'
self.thisquote = ''
self.in_quote = 0
else:
self.thisquote = self.thisquote + '}'
def
                 characters(self, ch):
if self.in_quote:
self.thisquote = self.thisquote + ch
if __name__ == '__main__':
parser = xml.sax.make_parser()
handler = QuotationHandler()
parser.setContentHandler(handler)
parser.parse( "sample.xml")

上記例ではxmllib と若干異なる点が2つあることに注意してください。1つは、.parse() メソッドがストリーム/ストリングをすべて処理するため、パーサーにデータを渡すループを作成する必要がないという点です。もう1つは、.parse() がファイル名でも、ファイル・オブジェクトでも、ほとんどのファイル系オブジェクト(.read() メソッドを備えたもの)でも受け入れるほど柔軟であるという点です。


パッケージ:DOM

DOMは、XML文書ツリー・ベースの高水準表現です。このモデルはPython固有のものではなく、一般XMLモデルです(詳細については参考文献 を参照)。PythonのDOMパッケージはSAXをベースに作成されたもので、Python 2.0の標準XMLサポートに含まれています。誌面の都合上、この記事でコード例を紹介することはできませんが、その概要はXML-SIGの「Python/XML HOWTO」に次のようにわかりやすく説明されています。

文書オブジェクト・モデル(DOM)とは、XML文書のツリー・ベース表現を規定するものです。最上位文書インスタンスがツリーのルートとなり、その下に最上位エレメント・インスタンスである単一の子エレメントがあります。この子エレメントには、コンテンツおよび他のサブエレメントを表す子ノードがあります。それにはさらに子がある場合があり、これが繰り返されます。結果のツリーを好みの方法で検討したり、エレメントや属性値にアクセスしたり、ノードの挿入や削除を行ったり、ツリーをXMLに変換し直したりする機能が定義されています。
文書オブジェクト・モデル(DOM)とは、XML文書のツリー・ベース表現を規定するものです。最上位文書インスタンスがツリーのルートとなり、その下に最上位エレメント・インスタンスである単一の子エレメントがあります。この子エレメントには、コンテンツおよび他のサブエレメントを表す子ノードがあります。それにはさらに子がある場合があり、これが繰り返されます。結果のツリーを好みの方法で検討したり、エレメントや属性値にアクセスしたり、ノードの挿入や削除を行ったり、ツリーをXMLに変換し直したりする機能が定義されています。

モジュールxml.dom を使用する構文は、以前の記事から若干変わっています。Python 2.0に付属するDOMの実装はxml.dom.minidomと呼ばれ、DOMの小型・軽量版です。確かに、xml.dom.minidomはXML-SIGのDOMの完全版からいくつかの検査用機能を削除したものですが、その違いに気づく人はほとんどいないはずです。

DOMオブジェクトの生成は、次のコードを使用するだけで簡単にできます。


リスト4:XMLファイルからのPython DOMオブジェクトの作成
                
from xml.dom.minidom import parse, parseString
dom1 = parse( 'mydata.xml') # parse an XML file by name


DOMオブジェクト操作は、かなり簡単なOOPスタイルの作業です。ただし、すぐに見分けがつかない多くのリスト状の属性が階層内に含まれる傾向があります(ループ内の列挙を除く)。例として、ごく一般的なDOM Pythonコードの一部分を示します。


リスト5:Python DOMノード・オブジェクトによる繰返し
                
                
for node in dom_node.childNodes:
if node.nodeName == '#text': # PCDATA is a kind of node,
PCDATA = node.nodeValue # but not a new subtag
elif node.nodeName == 'spam':
spam_node_list.append(node) # Create list of <spam> nodes

Python標準ドキュメンテーションには、さらに詳しいDOMの例がいくつか記載されています。以前の記事で紹介したDOMオブジェクトの操作例(参考文献を参照)は、今もなお正しい方向を示していますが、その後一部メソッドと属性名が変更されているため、Pythonドキュメンテーションを確認してください。


モジュール:pyxie

pyxie モジュールは、Pythonの標準XMLサポートをベースに作成されており、XML文書に対する追加の高水準インターフェースを提供するものです。pyxie の基本的機能は次の2つです。1つはXML文書を、さらに構文解析しやすい行指向形式に変換すること、もう1つはXML文書を、追跡できるツリーとして扱うメソッドを提供することです。pyxie で使用される行指向PYX形式は言語には依存せず、いくつかの言語ツールを使用することができます。一般に、grep、sed、awk、bash、perlのようなおなじみの行指向テキスト処理ツール、あるいはstringre などの標準Pythonモジュールを使用して文書のPYX表現を処理する方が、XML表現を処理するよりもはるかに簡単です。ダウンストリーム次第では、XMLからPYXに変換することによって多くの作業が省ける場合もあります。

XML文書をツリー状に扱うというpyxieの概念は、DOMの概念とよく似ています。DOM標準は数多くのプログラム言語にわたって幅広い支持を集めつつあるため、XML文書のツリー表現が必要な場合、ほとんどのプログラマーは pyxie よりもDOM標準に目を向けた方がよいでしょう。


その他モジュール: xml_pickle と xml_objectify

私も、xml_picklexml_objectifyという、XML処理用の独自高水準モジュールを作成しています。これらについては、他の場所(参考文献を参照)でも十分に説明しているため、ここでは詳しく述べません。しかし、「XMLで考える」のではなく「Pythonで考える」必要がある場合は、これらモジュールが有効なことがよくあります。特に、xml_objectify はXML自体のほぼすべての痕跡を隠してPythonプログラマーに見えないようにし、プログラム内で完全に「ネイティブ」Pythonオブジェクトを扱えるようにします。基礎をなす実際のXMLデータ・フォーマットは、ほぼ不可視というところまで抽象化されます。同様に、xml_pickle を使用すれば、Pythonプログラマーは、データ・ソースに関係なく「ネイティブ」Pythonオブジェクトから取りかかり、他のユーザーがダウンストリームとして望むXMLフォーマットにダンプ(シリアル化)することができます。


参考文献

著者について

Photo of David Mertz

David Mertz氏は多くの分野で活躍しています。ソフトウェア開発や、それについて著述もしています。その他、学術政策理念について分野を問わず、関係する雑誌に記事も書いています。かなり以前には、超限集合論、ロジック、モデル理論などを研究していました。その後、労働組合組織者として活動していました。そして、David Mertz氏自身は人生の半ばにもまだ達していないと思っているので、これから何かほかの仕事をするかもしれません。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux, XML
ArticleID=239847
ArticleTitle=魅力的なPython: Python用XMLツールの再考
publish-date=06012001
author1-email=mertz@gnosis.cx
author1-email-cc=dwxed@us.ibm.com

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。