IBM®
本文へジャンプ
    Japan [変更]    ご利用条件
 
 
検索範囲検索:    
    ホーム    製品    サービス & ソリューション    サポート & ダウンロード    マイアカウント    
skip to main content

developerWorks Japan  >  XML  >

XMLの論考 第12回: Pythonモジュールxml2sqlおよびdtd2sqlの使用

DTDおよびXML文書からのSQLステートメントの生成

developerWorks
ページオプション

JavaScript を要するドキュメントオプションは表示されません

原文はこちら

原文はこちら


レベル: 初級

David Mertz, Ph.D (mertz@gnosis.cx), Author, Gnosis Software, Inc.

2001年 6月 01日

前回の記事では、SQL照会からのXML文書の生成について探りました。今回、David Mertzは、それなりの制約と複雑さがあるものの、XML文書およびDTDからRDBMSストレージ形式への逆方向の変換も同様に可能であることを示します。ここで論じるPythonのパブリック・ドメイン・ユーティリティーxml2sql およびdtd2sql は、整合性を保ち逆変換可能な方法で、データベースを作成しデータを挿入するための、SQLステートメントを生成します。この技法を7つのコード・サンプルによって示します。

XML文書とRDBMSはともに、まだしばらくの間利用され続けることでしょう。これは、さまざまなデータ・モデルを調べ、XMLが状況にどのように適合できるのかを検討したうえでの、私のこれまでの (そして現在の) 結論です。今回のユーティリティーの解説では、開発者のために、データおよびフォーマットの変換をもう少し簡単にするための努力を続けます。プログラマーは、dtd2sql およびxml2sql を使用することにより、XML文書の内容をSQLデータベースに自動的に 移動させることが (そしてまた、後で情報を戻すことが) できます。

注意

私は、今回および以前のsql2dtd およびsql2xml の説明で示すユーティリティーが、XMLとSQLとの間での迅速で現実的な変換方法を求めている開発者の作業を容易にするものと期待しています。しかし、これらのユーティリティーがデータベース分析担当者の代わりになるとは考えないでください。最適化、正規化、および非正規化は、知識と経験を必要とする複雑な仕事です。私が提供するツールは、実用的ですぐれた、配置の容易なソリューションを提供しますが、これらのソリューションは、必ずしも常にカスタム開発に取って代われるわけではありません。

さらに、まず第一にxml2sql およびdtd2sql は、表指向の情報を含むXML文書で使用したときに最も本領を発揮します。散文指向およびリニア指向のXML文書を変換する場合には、そのありがたみは大幅に減少します。このような制約は、実質的には、xml2sql が利用するxml_objectify ライブラリーによる制約と同じです。ただし、ここで焦点を当てている事項は、実際はたいした制約ではありません。どのような 技法でも (たとえカスタム開発でも)、RDBMSフレームワーク内で散文データやリニア・データをごく自然に表現することはできないのです。モデルが異なっているだけで、xml2sql の働きはどのユーティリティーにも引けを取りません。

最後に、xml2sql が特に高速または有効であるとは期待しないでください。このユーティリティーは移植性や汎用性を考慮して設計されているものです。したがって、xml2sql およびdtd2sql は、(特定のRDBMSのため、またはODBCなどのメカニズムを介して) なんらかのデータベース・ライブラリーを呼び出すのではなく、単純なテキスト形式のSQLステートメントを作成します。モジュールdtd2sqlCREATE TABLE ステートメントのリストを生成し、xml2sqlINSERT INTO ステートメントのリストを生成します。これらのステートメントを実際のRDBMSに送り込むのは、ユーザーまたはプログラマーの仕事です。このようにすることにより、開発者はこれらのステートメントをどのベンダーのRDBMSにも、同じようにうまく送り込むことができるようになります。




上に戻る


実際にやってみる

モジュールxml2sql およびdtd2sql は、おそらく、実例を示すと最も分かりやすいと思います。その後で、設計に関する理論的な問題点に話を戻すことにします。

テストのために、簡単なテスト・スクリプトを1つ作成しました。開発を行うためには、一般的に使用されているオープン・ソースのRDBMSであるmySQLを使用しました。mySQLには、より洗練されたRDBMSに比較すると、いくつかの制約がありますが、テスト用プラットフォームとしては優れています。サンプルのDTDおよびXML文書は、私が書いたdeveloperWorksチュートリアルから取ったものです (このコレクションについては、参考文献を参照)。リスト1に示す私のスクリプトはOS/2コマンド・ファイルですが、Windowsでも同じように機能するはずであり、ごくわずかの修正を加えるだけでUnix類似システムでも使用できるはずです。


リスト1. XMLをSQLに転送するためのテスト・スクリプト
                
echo drop database test;      > test.sql
echo create database test;    >> test.sql
echo use test;                >> test.sql
python dtd2sql.py dwtut.dtd   >> test.sql
python xml2sql.py haskell.xml >> test.sql
mysql -u root -pPASSWORD test  < test.sql

リスト1のスクリプトの最初の数行は、mySQLでtest データベースを除去し、復元しているだけです。現実社会では、表からのINSERT およびDELETE を除き、既存のデータベースをdrop する必要はめったにないはずです。私がdrop を使用したのは、テストを行うときに新規に始めるのがよいと考えたためです。

dtd2sql を実行すると、STDINのDTD、またはコマンド行で指定したファイル名からのDTDが使用されます。このDTDは、XML文書の内部サブセットであっても、また必要な場合には、外部ファイルであってもかまいません。ただし、このツールは一度に1つのソースからしか読み取りができず、また、現在のところ、複雑なマルチファイルDTD、パラメタ実体、または外部定義を部分的に指定変更する内部サブセットを扱うことはできません。すでに述べたように、dtd2sql は、単に一連のCREATE TABLE ステートメントを作成するだけです。

リスト2で、dtd2sql からの出力行に注目し、それを分断する方法を調べてみましょう (表示のためのラッピングが追加されています)。


リスト2. dtd2sqlから得られるサンプルCREATE TABLEステートメント
                
CREATE TABLE a (
    primary_key BIGINT UNSIGNED PRIMARY KEY,
    seq INT UNSIGNED,
    href BLOB,
    PCDATA BLOB,
    _XML BLOB,
    foreign_key_p BIGINT UNSIGNED,
    foreign_key_li BIGINT UNSIGNED,
    foreign_key_prompt BIGINT UNSIGNED,
    foreign_key_response BIGINT UNSIGNED
);

いくつかの列名は a エレメント自体の定義から簡単に説明がつきます。その他の列名については、やや詳しく検討する必要があります。


リスト3. <a> XMLエレメントのDTD項目
                
<!--A hyperlink to some other resource.-->
<!ELEMENT a (#PCDATA | code)* >
<!ATTLIST a href CDATA #REQUIRED  >

CREATE TABLE ステートメントにはprimary_key 列とseq 列が含まれます。seq 列は、(いくつかの行について順次性が存在しないことを示す以外には) ほとんど意味を持たない場合があります。このようなCREATE TABLE ステートメントが (ユーザーによってコマンド行から、あるいはカスタム・アプリケーションによって) 実行されると、各表内にこうした列が作成されます。href 列は、同じ名前のXMLタグ属性から直接得られます。また、PCDATA 列と_XML 列には、エレメントの実際の内容 (組み込み文字レベルのマークアップが付く場合と付かない場合があります) が入ります。

示されたCREATE TABLE ステートメントで最も興味深い点は、いくつかのforeign_key_* 列です。それらについて、以下で考えます。




上に戻る


関係の作成

リレーショナル・モデルによると、異なる複数の表は、基本キー / 外部キーの識別を介して相互に接続されます。SQLにおけるJOINは、ある表の中のフィールドが別の表の中の別のフィールドに対応しなければならないことを示す手段にすぎません。基本キー は、リレーショナル・モデルでは特別なものです。これは、表の各レコード (行) ごとに固有でなければなりません。ほとんどの場合、データベース分析担当者は、データの深い構造を調べ(アプリケーション・プログラマーやエンド・ユーザーと相談して)、基本キーの候補として最もふさわしいものを決めます。これらのキーは複数の列が連結されたものでもよく、多くの場合、社会保障番号、従業員ID、ISBN、または部品IDなどのIDが、その役割を果たします。

明らかに、dtd2sql は、データベース分析担当者が行う背景研究をすべて行えるわけではありません。dtd2sql はDTD (または、場合によってはXML文書) だけしか調べないのですから当然です。したがって、属性またはエレメント内容を固有にする場合に、どれを固有にするのかを決定するための現実的な方法はありません。幸い、dtd2sql はいくつかの商用RDBMSと同じ道筋をたどって、「自然な」基本キーを避けることができます。その代わりに、モジュールは完全に人工的な基本キー (固有性の要件を分離しながら、データ表記の役割を拒否する基本キー) を選択することができます。このようなパターンは、適切な「実世界の」データを識別する一般的な戦略に比べ、実際にはデータベース設計においてすぐれた直交性を得ることができると思われます。またこの方法は、各表の基本キーに、同一で予測可能な名前とフォーマットを与えるという利点も備えています。

使用される基本キーは、ランダムな18桁の整数です。Pythonのrandom モジュールが非常に優れたものであると想定すると、衝突の危険性はきわめて小さなものです。ただし、このコードは、衝突が起こらないことを厳密に保証するわけではありません (おそらく、今後のバージョンでは保証されることでしょう)。現状では、これでよしとするしかありません。

次のステップは、これらの基本キーをSQL JOINのために使用できるようにすることです。そのためには、XMLエレメントにサブエレメントを含めることができる場合には、親の基本キーに対応する外部キーがそのサブエレメントに必ず含まれるようにする必要があります。上記の目的を達するための最も倹約的な方法は、非ルート形式のそれぞれのXMLエレメントごとにforeign_key 列を1つを作成することです。その場合、結果データベースを照会したSQLユーザーは、どのJOINによって (たとえば、オリジナルのDTDの読み取りによって) その結果が作られたのかを知る 必要があります。

わたしは、物惜しみしないで明示性を選ぶことにします。表が対応しているXMLエレメントの親である可能性のある すべてのエレメントごとに、個別のforeign_key_* 列を1つ作成します。したがって、上のCREATE TABLE の例では、dtd2sql は、リスト4で示されている DTDエレメント定義を識別しています。


リスト4. <a> の親の可能性があるエレメント
                
<!ELEMENT p        (#PCDATA | code | img | br | i | b | a)* >
<!ELEMENT li       (#PCDATA | code | img | br | i | b | a)* >
<!ELEMENT prompt   (#PCDATA | code | img | br | i | b | a)* >
<!ELEMENT response (#PCDATA | code | img | br | i | b | a)* >

明示的な方法によるdtd2sql の利点は、作成される表構造に、DTD内の情報の大半が本来的に含まれることです (ただし、それによって限量子が区別されることはないため、すべての情報が含まれるわけではありません)。




上に戻る


紆余曲折

dtd2sql によって作成された表にデータを書き込むのは、xml2sql の仕事です。技術的には、どちらのツールも、なんらかのデータを実際にどこかに書き込むことはありません。いずれも、データがどのようなものであるのかを指定するだけです。実際にデータをロードするには、RDBMSに同梱されているツールを使用する必要があります。

実のところ、xml2sql の果たす役割はきわめて小さいのです。中心部分 (walkNodes() 関数) のコードの行数は50行足らずです。さらに、そうした少数の行は十分に文書化されてはいますが、プログラミングの技巧によって簡潔にするための努力は行われていません。もちろん、xml2sql が行う内容のほとんどは、実際にはxml_objectify によって行われます。xml2sql のための最初のステップは、xml_objectify を使用して「Python方式の」オブジェクトを作成することです。その後、実行されるINSERT INTO SQLステートメントを出力して、ネストされたすべての属性を反復するのは簡単です。ただし、古いバージョンのxml_objectify のユーザーは、XMLエレメント名が「分断」される方法がやや異なるので、最新バージョンを入手する必要があります。

xml2sql を実行すると、SQLステートメントの集まりが戻されます。このステートメントのコレクションは、通常のSTDOUTの振る舞いに基づいてリダイレクトおよびパイピングすることができ、それにより、xml2sql がRDBMSのコマンド行ツールと直接に結合されます。xml2sql をサポート・モジュールとして使用したい場合には、SQLステートメントのセットをPythonリストとして入手することができます。(これは、いくつかのデータベース・モジュールとともに簡単に使用することができます)。生成される代表的なステートメントは、リスト5の例のようになります (表示のためにラップされています)。


リスト5. 生成される代表的なステートメント
                
INSERT INTO p
       (primary_key, seq, foreign_key_text__column, PCDATA)
VALUES (15447926390024014, 0, 527610371062647168,
        "Navigating through the tutorial is easy:");

リスト5のINSERT INTO の形式から、私たちのDTD内の<p> エレメントと対応する表が作成されたことが分かります。実際には、このエレメントがXML文書で発生しているということが分かるだけです。DTDに対するXML文書の妥当性検査は、これらのモジュールの外部で処理される必要があります。ただし、XML文書が有効であるとすると、dtd2sql によって正しい表および列が作成されています。

INSERT INTO からは、この特定の<p> タグが<text-column> エレメント、すなわち、基本キーが527610371062647168 になっているエレメント内でネストされていることも分かります(有効なSQL列名を得るには、なんらかの名前分断が必要です)。また、この<p> エレメントになんらかのPCDATA内容が含まれていること、およびそのseq 列値がゼロになっていることも分かります。そのリスト・ビットの意味は、この<p> エレメントがコンテナー内の唯一の内容であることを表します。同じ<text-column> 内で複数の<p> エレメントが発生している場合、それらに、1から始まる番号が付けられます。




上に戻る


組み合わせ

RDBMS内に多くのデータがある場合、通常は、構造化された使いやすい方法で、そのデータを戻す必要があります。幸い、使用される基本キーと外部キーの戦略の基本を理解することにより、必要なものをすべて入手することができます。実際、多くの点で、この時点で得られる柔軟性は、XPath照会構文で得られる柔軟性を上回って います。リスト6の例を参照してください。


リスト6. RDBMSからのデータの選択
                
SELECT "Paragraph", p.seq, p._XML
  FROM title,panel,body,text__column TC,p
 WHERE title.foreign_key_panel = panel.primary_key
   AND body.foreign_key_panel = panel.primary_key
   AND TC.foreign_key_body = body.primary_key
   AND p.foreign_key_text__column = TC.primary_key
   AND title.PCDATA="About Haskell"
 ORDER BY p.seq
;

少し説明しておきます。JOINはすべて同じ形式になっています。foreign_key_X フィールドは、なんらかの表Xprimary_key とJOINされています。すべてのJOINが実施されると、ORDER、GROUP、その他の方法とともに、より現実的な条件を追加することができます。この場合、<title> が「About Haskell」になっている<panel> の、すべての段落 (<p> エレメント) を調べる必要があります。この結果は、リスト7に似たものになります。


リスト7. XMLチュートリアルに対するSQL照会
                
C:\mysql2\bin>mysql -u root -pgnosis test < haskell.sql
Paragraph  seq  _XML
Paragraph  1    Haskell is just one of a number of functional programming...
Paragraph  2    Among functional languages, Haskell is in many ways the...
Paragraph  3    On a minor note, Haskell is syntactically easier to get...




上に戻る


結論

このコラムではdtd2sql およびxml2sql のコマンド行の使用法を説明しました。クイック・テストを行ったり実際のシェルを使用したりするためには、おそらく、この方法が適していると思われます。しかし、Pythonにおけるほとんどの作業と同様に、ユーザーのコード内でモジュールを再利用することは非常に簡単です。自己テスト・コード (コマンド行で使用) は、どのモジュールのインポートでも使用できる、分かりやすいテンプレートを提供します。他の多くのモジュールについて協力していただいたように、ユーザーがこれらのモジュールをどのように利用しているのか、アイデアを聞かせてください。



参考文献

  • この記事で説明されているモジュールは、http://gnosis.cx/download/dtd2sql.py およびhttp://gnosis.cx/download/xml2sql.py からダウンロードすることができます。

  • この記事で使用されているデータ・ファイルとサポートのアーカイブは、http://gnosis.cx/download/xml_matters_12.zip にあります。

  • サポート・モジュールxml_objectify は、http://gnosis.cx/download/xml_objectify.py にあります。

  • 一般に、Gnosis Softwareのダウンロード・ディレクトリーには、私が (主としてIBM developerWorksのコラムおよび記事のために) 作成したさまざまなソフトウェアが含まれています。多くの場合、特定のソフトウェア・モジュールのさまざまなバージョン (最新で最大のバージョンとそれ以前のバージョンの両方)がこのディレクトリーから入手できます。http://gnosis.cx/download/ を調べてみてください。

  • David Mertzのこれまでの「XMLの論考」もご覧ください。
    • XMLの論考 第1回では、Pythonのxml_pickleオブジェクトを紹介しています。
    • XMLの論考 第2回では、Pythonのxml_objectifyの使い方について説明しています。
    • XMLの論考 第3回では、DocBookを紹介しています。
    • XMLの論考 第4回では、引き続き、DocBookでレガシー文書アーカイブを構築する方法について説明しています。
    • XMLの論考 第5回では、XSLTを介してXML文書をHTMLの変換する方法について説明しています。.
    • XMLの論考 第6回では、いくつかのXMLエディターを比較し、特に、テキスト中心の文書に適しているものを探っています。
    • XMLの論考 第7回では、DTDとXML Schemaを比較検討し、開発者がどのような場合に、成熟しつつあるW3C XML Schemaに背を向けてDTDにこだわりたくなるのかを示しています。
    • XMLの論考 第8回 では、コンピューター科学者たちによって概念化されたデータ・モデル という抽象的な理論が、特定の複数表現データ・フローを開発するために、どのように役立っているのかを説明しています。
    • XMLの論考 第9回では、RDBMSから独立してポータブルXML結果セットの生成を行えるようにする、パブリック・ドメインsql2dtd およびsql2xml ユーティリティーについて論じています。
    • XMLの論考 第10回は、Davidの「魅力的なPython第15回」のコラムで示された汎用フル・テキスト・インデクサーを拡張し、XML特定の検索および索引付け機能を組み込み、インデクサーでどのようにXMLの階層ノード構造を利用できるのかを説明しています。
    • XMLの論考 第11回では、このシリーズの最初のコラムで紹介したモジュールxml_pickle およびxml_objectify を再び取り上げています。

  • IBMのDB2 Extenderページでは、DB2がXMLを扱う方法について基本的な概要を示し、PDFファイルとして表示可能な、XMLでの照会に関する詳しいホワイト・ペーパーへのリンク、およびDB2 Extenderダウンロードへのリンクを提供しています。

  • Solutions 2001開発者コンファレンスが8月13日から18日までサンフランシスコで開催されました。


著者について

Photo of David Mertz

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




記事の評価


サイト改善のため、ご意見をお寄せください。こちらのフォームからお願いいたします。



 


 


不充分・不完全である大変素晴らしい
 


この記事を共有する

del.icio.us del.icio.us newsing newsing FC2ブックマーク FC2ブックマーク
Choix! Choix! ニフティクリップ ニフティクリップ Yahoo!ブックマーク Yahoo!ブックマーク
MM/memo MM/memo CZブックマーク CZブックマーク livedoorクリップ livedoorクリップ
はてなブックマーク はてなブックマーク Buzzurl(バザール) Buzzurl(バザール)




上に戻る


    日本IBMについて プライバシー お問い合わせ