本文へジャンプ

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


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

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

  • 閉じる [x]

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

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

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


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

  • 閉じる [x]

XMLの論考: 第1回

XML文書をオブジェクトとして'Python 的に'取り組む

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

概要: 「XML の論考」コラムの最初の記事で、David Mertz 氏は xml_pickle モジュールを紹介していますが、これは、XML と Python を境い目を作らずに統合しようとする彼の継続的な探求の一部でもあります。この記事で、Mertz 氏は、 xml_pickle に至った設計上の目標と決定について論じ、考えられる使い方について説明します。

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


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_picklepickle を汎用的に置き換えるものではありません。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 オブジェクトに入れられることがあります。次いで、結果として生じるオブジェクトを "加工" した場合、<attr> タグの順序は、おそらく元の文書の順序とは異なったものになります。これは特徴であってバグではありませんが、知っておくべき事柄です。

制限

現行バージョン (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 リストには項目を好きなだけ含めることができるので、それは一連の<item> 副エレメントとして表現されます。一方、数はです (値自体は 1 より大きいかもしれませんが、数自体は 1 つのもの です)。その場合は、"value" (値) と呼ばれる XML 属性を使う方が、より論理的であろうと思われます。本当に難しいケースは Python ストリングに関係しています。基本的に、それらはリストと同様のシーケンス・オブジェクトです。ストリング内の各文字を、仮に<char> タグを使って表現するなら、人間にとっての読み易さという目標を損なうことになり、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 の新たな使用法を開発した場合や、モジュールに新しい用途をもたらすような機能強化が得られた場合には、お知らせ下さい。


参考文献

著者について

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=XML
ArticleID=241033
ArticleTitle=XMLの論考: 第1回
publish-date=08012000
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 など)に対するお客様ご自身のタグを表示します。