PostgreSQLでXMLを処理してみよう!(第5回)(1)
第5回 SQL/XMLを利用したXMLデータ生成
-リレーショナルデータからXMLへ-
響 楽人
1.はじめに
本連載も今回で5回目となりました。今回は、XMLデータ生成について取り上げます。前回は、格納されたXMLデータをXSLTを使って変換し、ブラウザで表示できるHTML形式に変換する方法を紹介しました。今回は、XMLではないRDBのリレーショナルデータ部分を取り出して、XML (HTML) を生成する方法を紹介します。
リレーショナルデータを取り出してXML形式に変換する場面としては、例えば取引先から指定のXML形式でデータの提出が要求されているが、社内システムでは、対応するデータがRDB形式で保存されている場合が考えられます。このような場合、PostgreSQLに準備されているXML関数を使えば、リレーショナルデータを簡単にXMLデータに変換することができます。
2.リレーショナルデータからXMLを生成する―SQL/XML―
先に「PostgreSQLに準備されているXML関数」と書きましたが、これはISOのSQL:2003標準で定義されているXML関連の機能 (ISO/IEC 9075-14 XML-related specifications (SQL/XML) ) のことです。
SQL/XMLには、XMLデータ型についての定義、SQLからXMLへの対応付けの規程などが含まれています。これを規定したISO/IEC 9075-14は、2008年版がISO規格としては最新ですが、2003年版、2006年版などもあり、機能の拡張や修正などが刻々と行われるため、データベースでの実装も何をどこまでサポートしているかは製品によって様々です。PostgreSQLの場合、SQL/XMLのXML型の値を生成する関数としては、XMLCONCAT、XMLELEMENT (XMLATTRIBUTESを含む)、XMLFOREST、XMLROOT、XMLPI、 XMLCOMMENT、xml型と他の型との変換を行う XMLPARSE、XMLSERIALIZE, さらに集約関数としてXMLAGGが定義されています。以下にPostgreSQLが対応しているSQL/XMLの関数について説明します。
xmlelement() | 与えられた名前、属性、および内容を持つXML要素を生成する |
xmlforest() | 与えられた名前と内容を使用し、要素のXMLフォレスト(シーケンス)を生成する |
xmlattributes() | XML属性を生成する |
xmlcomment() | 特定のテキストを内容としてXMLコメントを含んだXML値を作成する |
xmlconcat() | XMLの内容断片を含む単一の値を作成するための個別のXML値のリストを結合する |
xmlagg() | xmlconcatが行うように、入力値を集約関数呼び出しに連結する |
xmlpi() | XML処理命令を作成する |
xmlroot() | XML値のルートノードの属性を変更する |
xmlparse() | 文字列型の値からXML型の値への変換を行う |
xmlserialize() | XML型の値から文字列型の値への変換を行う |
2.1 XML関数の使い方
ここで、前述のXML関数によるXMLデータ生成のイメージをつかんでいただくため、代表的ないくつかの関数の働きを説明します。
2.1.1 xmlelement関数
xmlelement 関数は、指定されたテキストを内容とする要素を作成する関数です。一つの xmlelement関数で生成される要素は一つだけですが、入れ子にして指定すれば要素の階層構造を作ることができます。以下に使用例を挙げます。
(※以下の例のいくつかでmeiboテーブルを使っています。これは連載第3回で作成したテーブルです。第3回で格納したデータがmeiboテーブルに入っていれば、同じ照会結果が得られるはずです。)
- 例1 空要素を作る:
-
testdb=# select xmlelement (name a); xmlelement ------------ <a/> (1 row)
- 例2 要素に値を入れる:
-
testdb=# select xmlelement (name a,100); xmlelement ------------ <a>100</a> (1 row)
- 例3 テーブルの列を参照して要素を生成する。(列名を値に指定し、参照するテーブル名をFROM句に記述する):
-
testdb=# select xmlelement (name a,age)from meibo; xmlelement ------------ <a>45</a> <a>41</a> <a>33</a> <a>32</a> <a>23</a> (5 rows)
- 例4 要素の階層構造を生成する (xmlelement 関数自体を入れ子にして指定):
-
testdb=# select xmlelement (name a, xmlelement (name b, xmlelement (name c, xmlelement (name d, xmlelement (name e))))); xmlelement ---------------------------------- <a><b><c><d><e/></d></c></b></a> (1 row)
2.1.2 xmlforest関数
xmlforest関数は与えられた名前と値で複数の要素を並列に生成する関数です。構文は、xmlforest(content [AS name] [, ...]) です。
- 例7 値が100の要素<a>と、値が200の要素<b>を作成する:
-
testdb=# select xmlforest(100 as a, 200 as b); xmlforest ---------------------- <a>100</a><b>200</b> (1 row)
- 例8 meiboテーブルのname列を参照して要素<a>の列を作成する:
-
testdb=# select xmlforest(name as a) from meibo; xmlforest ----------------- <a>生田靖</a> <a>前田孝</a> <a>鈴木花子</a> <a>田中一郎</a> <a>石川順子</a> (5 rows)
- 例9 meiboテーブルの列を参照して列名を要素名、値を要素の値とするシーケンスを作成する:
-
testdb=# select xmlforest(id,name,department) from meibo; xmlforest ---------------------------------------------------------------------------- <id>1031</id><name>生田靖</name><department>IT事業統括部</department> <id>1088</id><name>前田孝</name><department>ネットワーク管理課</department> <id>1101</id><name>鈴木花子</name><department>開発一課</department> <id>1103</id><name>田中一郎</name><department>開発二課</department> <id>1076</id><name>石川順子</name><department>開発一課</department> (5 rows)
ただし、この状態ではXMLとして有効な文書ではありません(XMLはただ一つの最上位要素で括られなければならない)ので、xmlforest式をxmlelement関数でラップして有効な文書とする必要があります。しかし、このSELECT文の内部でラップしても列ごとに処理が繰り返されてしまうため、テーブル全体として一つのXML文書とすることはできません。この方法については、「変換の実際」で説明します。
2.1.3 要素に属性を付与するxmlattributes関数
要素に属性を付与するにはxmlelement関数の中でxmlattributes()を使って属性を指定します。
- 例10 要素aを作る際、値が”100”である属性bを付与する:
-
testdb=# select xmlelement (name a,xmlattributes(100 as b)); xmlelement -------------- <a b="100"/> (1 row)
- 例11 要素aを作る際、meiboテーブルのid列のデータを値とする属性bを付与する:
-
testdb=# select xmlelement (name a,xmlattributes(id as b)) from meibo; xmlelement --------------- <a b="1031"/> <a b="1088"/> <a b="1101"/> <a b="1103"/> <a b="1076"/> (5 rows)
- 例12 要素aを作る際、列名(id)をそのまま属性名とする属性を付与する(xmlattributes でas~の部分を省略):
-
testdb=# select xmlelement (name a,xmlattributes(id),name) from meibo; xmlelement --------------------------- <a id="1031">生田靖</a> <a id="1088">前田孝</a> <a id="1101">鈴木花子</a> <a id="1103">田中一郎</a> <a id="1076">石川順子</a> (5 rows)