XML の論考

Japan
ホーム
製品
サービス
インダストリー
日本IBMについて
ニュース
IBM : developerWorks : XML
XML の論考
XML 文書をオブジェクトとして 'Python 的に' 取り組む
ダウンロード
PDF
Free Acrobat Reader
David Mertz, Ph.D.
Data Masseur, Gnosis Software, Inc.
2000 年 8 月
「XML の論考」コラムの最初の記事で、David Mertz 氏は xml_pickle モジュールを紹介していますが、 こ
コンテンツ
れは、XML と Python を境い目を作らずに統合しようとする彼の継続的な探求の一部でもあります。 この XML とは? Python とは?
記事で、Mertz 氏は、xml_pickle に至った設計上の目標と決定について論じ、 考えられる使い方について
プロジェクトの紹介
説明します。
サンプル Pyobjects.dtd
XML とは? Python とは?
設計の特徴
XML は、Standard Generalized Markup Language (SGML) を単純化した言語です。 読者の多くは、HTML をとおし 想定される使用法
て SGML に精通していることでしょう。 XML および HTML 文書はどちらも、不等号括弧で囲んだマークアップ・タ
グがテキストの中に点在し、 それらのタグによって構造化されています。 しかし XML は、タグを使うことにより、 参考文献
著者について
多くの目的で XML 文書を扱えるので様々なシステムで利用されています。 例えば次のようなものがあります。
●
雑誌の記事およびユーザー文書
●
構造化されたデータのファイル (CSV または EDI ファイルなど)
●
プログラム間のプロセス間通信用のメッセージ
●
建築図面 (CAD 形式など)
XML では、表現したいあらゆる種類の構造化された情報を取り込めるよう、 一式のタグを作成することができます。 このことは、さまざまな情報を表現
するための共通規格として XML が人気を博してきた理由です。
Python は、Guido van Rossum が開発した、 非常に高水準のインタープリター言語であり、無償で入手できます。 この言語は明快な構文と、 強力なオブ
ジェクト指向の意味構造 (オプション) を結合したものです。 Python は広範囲のコンピューター・プラットフォームで利用でき、 プラットフォーム間の
強力な移植性を提供します。
プロジェクトの紹介
Python で XML 文書を扱うには、たくさんの技法とツールがあります。 (参考文献セクションには、 2 つの developerWorks の記事へのリンクがあり、そ
こでは一般的な技法が論じられています。 また、XML/Python トピックに関する他の文書へのリンクもあります。) しかし、ほとんどの既存の
XML/Python ツールに共通なのは、 それらが Python 中心というより XML を中心としていることです。 特定の機能やコーディング技法は、あるプログラ
ミング言語において自然に感じられても、 他の機能やコーディング技法は、別の領域から借りてきたもののように感じることがあります。 しかし理想的
な環境では、すべての機能がそれぞれの領域に直感的に適合し、 各領域は継ぎ目なく組み合わされます。 それが実現すれば、プログラマーは単にプログ
ラムを機能させることにとどまらず、 プログラムの詩人の域に達するまでになれます。
私は XML と Python とのさらに継ぎ目のない自然な統合を創り出すための調査プロジェクトを始めました。 この記事と、この連載の続きの記事で、この
プロジェクトの目標、決定事項、および制限の幾つかについて論じ、 プログラミングの目標に適合する簡単な方法に焦点を合わせた、役立つモジュール
や技法を紹介したいと思います。 プロジェクトの一部として作成されたすべてのツールは、パブリック・ドメインとしてリリースされる予定です。
Pythonは、柔軟なオブジェクト・システムとビルトインのタイプが数多く用意された言語です。 この Python の豊かさは、プロジェクトにとって利点にも
欠点にもなり得ます。 つまり、広範囲のネイティブな機能を Python がもっていることで、XML 構造の広範囲の表記が簡単になる一方、 ネイティブのタ
イプおよび構造の範囲が広いので、 ネイティブの Python オブジェクトを XML でどうやって表記したらよいのかという問題がどんどん出てくるのです。
このような XML と Python の非対称性の結果、 プロジェクトには (少なくとも初期の段階では) 2 つの別個のモジュールが含まれることになりました。 す
なわち、任意の Python オブジェクトを XML で表記する xml_pickle と、 Python オブジェクトとして XML オブジェクトをネイティブに表現する
xml_objectify です。 この記事では、xml_pickle を取り上げることにします。
パート I: xml_pickle
Python の標準 pickle モジュールは、 Python オブジェクトの直列化を行う単純で便利な手段をすでに提供してきました。 これは永続ストレージやネット
ワーク上の伝送に役立ちます。しかし場合によっては、pickle にはないいくつかのプロパティーを持つ フォーマットへの直列化を実行したい場合もあり
ます。 つまり、次のような形式です。
●
人間が判読できるもの
●
構文解析、および操作が行えて、そのオブジェクトが Python 以外の言語でインポートされたもの
●
保管された直列化オブジェクトの妥当性検査をサポートするもの
xml_pickle は、これらの機能を提供する一方で、 pickle とのインターフェース互換性を維持します。 しかし xml_pickle は pickle を汎用的に置き換え
るものではありません。 pickle には、より高速なオペレーション(特に cPickle を介する場合)や、 はるかにコンパクトなオブジェクトの表記など、そ
れ自体幾つかの利点があるからです。
xml_pickle の使用
xml_pickle のインターフェースは pickle とほとんど同じですが、 Python や pickle にあまり精通していない方のために、 xml_pickle の使用法を(極め
て簡単に)例示することにします。
[xml_pickle] を例示する Python コード
import xml_pickle # import the module
# declare some classes to hold some attributes
class MyClass1: pass
class MyClass2: pass
# create a class instance, and add some basic data members to it
o = MyClass1()
o.num = 37
o.str = "Hello World"
o.lst = [1, 3.5, 2, 4+7j]
# create an instance of a different class, add some members
o2 = MyClass2()
o2.tup = ("x", "y", "z")
o2.num = 2+2j
o2.dct = { "this": "that", "spam": "eggs", 3.14: "about PI" }
# add the second instance to the first instance container
o.obj = o2
# print an XML representation of the container instance
xml_string = xml_pickle.XML_Pickler(o).dumps()
print xml_string
最初の行と、最後から 2 番目の行を除くすべての行は、 オブジェクト・インスタンスを使って作業する場合の汎用の Python です。 これはややわざとら
しく単純すぎるように見えますが、インスタンス・データ・メンバー(これには、 コンテナー・データとしてのネスト・インスタンスが含まれており、
これは Python に組み込まれた最も複雑な構造です)で行うことは本質的にすべて上記の例に含まれています。 Python のプログラマーは、 XML としてオ
ブジェクトをエンコードする 1 つのメソッド呼び出しを作成するだけで十分です。
もちろん、いったんオブジェクトを "加工" した後でそれらを "復元" したくなるかもしれません (または他のどこかでそれらを使用することになるかもし
れません)。 上記の少数の行がすでに実行されたと仮定すると、オブジェクト表現の復元は以下のように単純です。
new_object = xml_pickle.XML_Pickler().loads(xml_string)
明らかに、実際の場面で XML 文書を作成する時、 実行時にメモリー内にそれを保持するだけでなく、なにか別の面白いことをしたくなるかもしれませ
ん。 たとえば、XML 文書をディスクに保管したり(おそらく XML_Pickler.dump() メソッドを 使用して)、それを通信チャネルに送信するといったことな
どです。 実際、その例を紙に印刷すれば、それはそれとして耐久性のある保管形式と言えます。
サンプル Pyobjects.dtd 文書
上記のサンプル・コードを実行は、 Python オブジェクトの xml_pickle 表現の機能を例示する、 たいへん良い例です。 しかし、次の例は私が開発した手
作りのテスト・ケースで、 文書型として定義可能なすべての XML 構造、タグ、および属性を含んでいます。 特定のデータは私が作成したものですが、
これらのデータがどんなアプリケーションを想定しているかはすぐにお分かりになるでしょう。
xml_pickle の特徴を示すサンプル
<?xml version="1.0"?>
<!DOCTYPE PyObject SYSTEM "PyObjects.dtd">
<PyObject class="Automobile">
<attr name="doors" type="numeric" value="4" />
<attr name="make" type="string" value="Honda" />
<attr name="tow_hitch" type="None" />
<attr name="prev_owners" type="tuple">
<item type="string" value="Jane Smith" />
<item type="tuple">
<item type="string" value="John Doe" />
<item type="string" value="Betty Doe" />
</item>
<item type="string" value="Charles Ng" />
</attr>
<attr name="repairs" type="list">
<item type="string" value="June 1, 1999: Fixed radiator" />
<item type="PyObject" class="Swindle">
<attr name="date" type="string" value="July 1, 1999" />
<attr name="swindler" type="string" value="Ed's Auto" />
<attr name="purport" type="string" value="Fix A/C" />
</item>
</attr>
<attr name="options" type="dict">
<entry>
<key type="string" value="Cup Holders" />
<val type="numeric" value="4" />
</entry>
<entry>
<key type="string" value="Custom Wheels" />
<val type="string" value="Chrome Spoked" />
</entry>
</attr>
<attr name="engine" type="PyObject" class="Engine">
<attr name="cylinders" type="numeric" value="4" />
<attr name="manufacturer" type="string" value="Ford" />
</attr>
</PyObject>
PyObjects.dtd 文書の構造を調べるのは難しくありません。 (公式の文書型定義 (DTD) は、参考文献より入手できます。) DTD はすぐには明確にならない
問題もすべてはっきりさせます。
サンプル XML 文書を見ると、 xml_pickle の前述の 3 つの設計上の目標に適合していることが分かります。
●
●
●
書式は人が読みやすいものであること。
XML 表現は xml_pickle 以外の手段によって操作されることがあること。 それらは、関連のない Python/XML モジュールか、 他のプログラム言
語の XML ライブラリー、XML 拡張エディターおよびユーティリティー、 または単純なテキスト・エディター (サンプルはこれで作成した) かも
しれません。
Python オブジェクトの XML 表現は、 標準の XML 検証プログラムと PyObjects.dtd を使用して妥当性検査できること。
DTD に従う文書はすべて、 そして DTD に従う文書だけ が、有効な Python オブジェクトの表現ということになります。
設計上の特徴、注意点、および制限
内容モデル
Python と XML の内容モデルには、いくつかの面で相違があります。 重要な相違点の一つは、XML 文書が本質的に順序を持つリニアな形であることで
す。 Python のオブジェクト属性と Python ディクショナリーでは、定義上の順序がありません。 (ただし、インプリメンテーションに入り込むと、ハッ
シュ・キーなどの任意の順序付けが作成されます。) この点で、Python オブジェクト・モデルはリレーショナル・モデルに似ています。 リレーショナル
表の行には「自然の」順序というものがなく、 1 次キーや 2 次キーによって意味上の順序が表に提供されることも、提供されないこともあります。 キー
は常に比較演算子によって順序付けできますが、 この順序はキーのセマンティクスとは無関係の場合もあります。
XML 文書では、常にそのタグ・エレメントを特定の順序で列挙します。 その順序が特定のアプリケーションには意味のないものであっても、 XML 文書
の順序というものは常に存在します。 Python と XML のキー順序の相違の影響として、xml_pickle で生成された XML 文書は、 "加工"/"復元" サイクルを
経たときにエレメントの順序が変わってしまうこともあり得ます。 たとえば、手作業で作成した PyObjects.dtd という XML 文書は、 前述のように、"復
元" されて Python オブジェクトに入れられることがあります。 次いで、結果として生じるオブジェクトを "加工" した場合、 タグの順序は、おそらく元の
文書の順序とは異なったものになります。 これは特徴であってバグではありませんが、知っておくべき事柄です。
制限
現行バージョン (0.2) としての xml_pickle には、いくつかの制限があることが知られています。 潜在的な問題の原因として、 複合 / コンテナー・オブ
ジェクトにおける循環参照をトラップする努力が払われていない、という点があります。 オブジェクト属性がコンテナー・オブジェクトに戻る形で参照
する場合 (あるいは、これが再帰的に行われる場合)、 xml_pickle は Python スタックを使い果たしてしまいます。 循環参照は初期のオブジェクト設計に
おける欠陥を示すものでしたが、 xml_pickle の後期のバージョンでは、より理知的な方法でその問題に対処する試みが見られます。
別の制限として、XML の属性値 (<attr name="123"> における "123" など) のネームスペースが、 有効な Python の変数およびインスタンス・メンバーの
ネームスペースよりも大きい、という点があります。 Python ネームスペースの外部で手作業で作成された属性は、 インスタンスの .__dict__ マジック属
性に存在するという奇妙な状態になります。 しかし、通常の属性構文でそれにアクセスすることはできません (たとえば、"obj.123" は構文エラーになり
ます)。 これは、XML 文書が xml_pickle 自体以外の手段によって作成または修正される場合にのみ、問題になります。 現時点では、私はこの (やや分か
りにくい) 問題にどう対処してよいか善い方法が見つかりません。
3 番目の制限は、 xml_pickle が Python オブジェクトのすべての属性を処理するわけではないという点です。 すべての「通常の」データ・メンバー (スト
リング、数値、ディクショナリーなど) は、 正しく変換されます。 しかし、インスタンス・メソッドや、属性としてのクラスおよび関数オブジェクトは
処理されません。 pickle に関しては、メソッドは変換の際に単に無視されます。 クラスまたは関数オブジェクトが属性として存在する場
合、XMLPicklingError が出されます。 おそらくこれが正しい動作と思われますが、確信は持てません。
設計上の選択
XML 文書設計において実にあいまいな点は、タグ属性をいつ使用し、副エレメントをいつ使用するかの選択です。 この設計上の問題についての意見には
相違があり、 XML プログラマーたちはしばしば、彼らの見解に対立があると強く感じます。 おそらくこの点は、xml_pickle 文書構造の決定における最
大の問題でした。
決定された一般原則は、本来「複数」であるもの は副エレメントで表現すべきであるということです。 たとえば、Python リストには項目を好きなだけ含
めることができるので、 それは一連の 副エレメントとして表現されます。 一方、数はです (値自体は 1 より大きいかもしれませんが、数自体は 1 つのも
の です)。 その場合は、"value" (値) と呼ばれる XML 属性を使う方が、より論理的であろうと思われます。 本当に難しいケースは Python ストリングに関
係しています。 基本的に、それらはリストと同様のシーケンス・オブジェクトです。 ストリング内の各文字を、仮に タグを使って表現するなら、 人間に
とっての読み易さという目標を損なうことになり、XML 表現の量がふくれ上がるということになってしまいます。 そこでストリングは、数の場合と同様
に、XML の "value" (値) 属性に入れるという決定がなされました。 しかしながら、見た目の美しさと言う観点からすると、タグで挟んで表現した方がよ
いと思われます。 複数行のストリングの場合は特にそうです。 しかし、仕様には "ただの文字列である" #PCDATA しかなかったことからすれば、 この決
定は一貫性のあるものと思われます。
ストリングが XML の "value" (値) 属性に格納されるため、 さらには XML 文書のシンタックス上の性質を維持するため、 Python ストリングを "安全な" 形
で格納する必要がありました。 Python ストリングに生じる可能性のある、安全性を損なう要因がいくつかあります。 第 1 のタイプは不等号記号 (< と >)
のような基本マークアップ文字です。 第 2 のタイプは引用符とアポストロフィで、これらは属性を開始させる文字です。 第 3 のタイプはヌル文字など、
対応の難しい ASCII 値です。 考慮した 1 つの方法は、Python ストリング全体を、 base64 エンコード方式のような何らかの方法でエンコードすることで
した。 こうすればストリングは "安全" なものになりますが、全く人が読むことのできないものになってしまいます。 それで、混合アプローチを使用する
ことが決定されました。 基本 XML 文字は「&amp;」、「&gt;」、「&quot;」といったスタイルで逃げます。 対応の難しい ASCII 値は「\000」のような
Python スタイルで逃げます。 このような組み合わせにより、人が読みやすい XML 表現にはなりますが、 格納されているストリングのデコードにはやや
めんどうなアプローチが求められることになります。
想定される使用法
xml_pickle を活用できる多くの用途が考えられており、 ユーザーからのフィードバックによると、それは使用準備段階に入っています。 いくつかのアイ
デアを以下に紹介します。
- Python オブジェクトの XML 表現を、 既存の XML 指向のツール (必ずしも Python で書かれていなくてよい) を使って、 索引付けお
よびカタログ化することができます。 これにより、Python オブジェクト・データベース (ZODB、PAOS、 あるいは単純な shelve) の
索引付けのための手段が整います。
- Python オブジェクトの XML 表現を、 他の OOP 言語 (特に、類似した範囲の基本タイプをもつもの) のオブジェクトとして保管す
ることができます。 これは、まだ行われていないことの 1 つです。 これは CORBA、XML-RPC、SOAP といった、ずっと「重い」
プロトコルとも目的が重なっていますが、 xml_pickle はオブジェクト・トランスポート仕様としては見事に「軽量」です。
- XML 文書の印刷と表示のためのツールを使って、 Python オブジェクトの便利で読みやすい表現を、XML 中間形式を介して提供す
ることができます。
- Python オブジェクトを手作業で「デバッグする」ことができます。 これは、XML エディターまたは単純なテキスト・エディターを
使って、 Python オブジェクトの XML 表現を使って行います。 手作業で変更を加えたオブジェクトをいったん "復元" したら、 プログ
ラムで編集を行ったのと同じ効果を調べることができます。 これは、他の既存の Python デバッガーおよびラッパーに、追加のオプ
ションが提供されたようなものです。
xml_pickle の新たな使用法を開発した場合や、 モジュールに新しい用途をもたらすような機能強化が得られた場合には、お知らせ下さい。
参考文献
●
Python 用の XML ツールの紹介 : 魅力的な Python、第 1 回
●
Python の xml.dom モジュールのさらに詳しい説明: 魅力的な Python、第2回
●
XML に関する Python Special Interest Group
●
World Wide Web Consortium (W3C) の DOM ページ
●
DOM レベル 1 勧告
●
この記事で使用または言及されたファイル
●
Sean McGrath 氏による XML Processing with Python。 XML のバックグラウンドを持つプログラマーのための Python の親しみやすい紹介で
す。 McGrath 氏は彼の著書を大いに使って彼の pyxie モジュールと関連ツールの価値について論じ、 それらの技法を XML 処理のための最適な
アプローチであるとしています。 pyxie が読者個人の問題にとって最適のアプローチであってもそうでなくても、 McGrath 氏の著書は Python
の有用な入門書と言えます (XML についてはそれほどでもありませんが)。
著者について
David Mertz 氏は、書くことと理解との間に大きな関係があることに気付きました。 氏はたとえば、氏自身の博士論文を理解することか
ら始めました。 David Mertz 氏の連絡先は [email protected] です。 彼のライフワークは http://gnosis.cx/publish/ で参照できます。 この
記事や過去のコラム、また今後のコラムに対するご意見をお寄せください。
この記事についてどう思われますか?
大変素晴らしい
良い
まあまあ
改善の余地あり
フィードバックを送る
コメントがあればこちらからお送りください (Subjectは、変更しないでください)
プライバシー
リーガル
お問い合わせ
不充分・不完全である