xml2モジュールはXPath問い合わせとXSLT機能を提供します。
PostgreSQL 8.3から、SQL/XML標準に基づくXML関連の機能はコアサーバ内に存在します。 この機能は、XML構文検査、本モジュールと同等のことを行うXPath問い合わせなどを範囲としますが、APIには互換性はありません。新しい標準APIのため、本モジュールはPostgreSQL 8.4で削除される予定ですので、アプリケーションの変換が推奨されています。本モジュールの機能のうち新しいAPIに適用できないことがわかった場合、その不足に取り組むことができるようにpgsql-hackers@postgresql.orgにその問題を表明してください。
表F-35はこのモジュールで提供される関数を示しています。 これらの関数は簡単なXML解析とXPath問い合わせを提供します。 すべての引数はtext型です。簡潔にするため説明しません。
表 F-35. 関数
xml_is_well_formed(document) returns bool
| これはパラメータとして与えられた文書テキストを解析し、文書が製形式のXMLであれば真を返します。
(注意:PostgreSQL 8.2以前ではこの間数は |
xpath_string(document,query) returns text
xpath_number(document,query) returns float4
xpath_bool(document,query) returns bool
| これらの関数は与えられた文書に対するXPath問い合わせを評価し、結果を指定した型にキャストします。 |
xpath_nodeset(document,query,toptag,itemtag) returns text
| これは文書に対する問い合わせを評価し、XMLタグ内に結果を包みます。 結果が複数の値であれば、出力は以下のようになります。 <toptag> <itemtag>Value 1 which could be an XML fragment</itemtag> <itemtag>Value 2....</itemtag> </toptag>toptagまたはitemtagが空文字だった場合、対応するタグは省略されます。 |
xpath_nodeset(document,query) returns text
| xpath_nodeset(document,query,toptag,itemtag)と同様ですが、結果は両方のタグを省きます。 |
xpath_nodeset(document,query,itemtag) returns text
| xpath_nodeset(document,query,toptag,itemtag)と同様ですが、結果はtoptagを省きます。 |
xpath_list(document,query,separator) returns text
| この間数は複数の値を指定した区切り文字で区切って返します。 例えば、区切り文字が,ならばValue 1,Value 2,Value 3となります。 |
xpath_list(document,query) returns text
| これは、,を区切り文字として使用する、上の関数のラッパです。 |
xpath_table(text key, text document, text relation, text xpaths, text criteria) returns setof record
xpath_tableは各文書集合に対するXPath問い合わせ集合を評価し、結果をテーブルとして返すテーブル関数です。
元文書テーブルのプライマリキーフィールドが結果の第一列として返されますので、結果セットを容易に結合で使用することができます。
表 F-36. パラメータ
| key | "key"フィールドの名前です。 これは、出力テーブルの第一列として使用される単なるフィールドです。 つまり、これは各出力行の出現元を識別するレコードです。 (後述の複数値に関する注記を参照してください。) |
| document | XML文書を含むフィールドの名前です。 |
| relation | 文書を含むテーブルまたはビューの名前です。 |
| xpaths | |で区切られた、1つ以上のXPath式です。 |
| criteria | WHERE句の内容です。 これは省略することができません。 リレーション内の全行を処理したい場合はtrueまたは1=1を使用してください。 |
(XPath文字列を除く)これらのパラメータは普通のSQL SELECT 文に単純に置換されます。 このため、多少の柔軟性があります。
SELECT <key>, <document> FROM <relation> WHERE <criteria>
文は上の通りですので、これらのパラメータにはそれぞれの場所で有効なものであれば何でもよいわけです。 このSELECTの結果は正確に2つの列を返さなければなりません(キーまたは文書に対して複数のフィールドを列挙させようとしない限りです)。 この簡略された手法では、SQLインジェクション攻撃を防ぐためにユーザから与えられた値をすべて検証しなければならないことに注意してください。
この関数は、出力列を指定するためのAS句を付けたFROM式内で使用されなければなりません。 以下に例を示します。
SELECT * FROM
xpath_table('article_id',
'article_xml',
'articles',
'/article/author|/article/pages|/article/title',
'date_entered > ''2003-01-01'' ')
AS t(article_id integer, author text, page_count integer, title text);
このAS句は、仮想テーブルの列名とその型を定義します。 先頭が"key"フィールド、残りがXPath問い合わせに対応します。 結果列よりより多くのXPath問い合わせが存在する場合、余った問い合わせは無視されます。 XPath問い合わせより多くの結果列が存在する場合には余った列はNULLになります。
この例でpage_count結果列が整数として定義されていることに注意してください。 関数は内部的に文字列表現で扱います。 このため、出力内で整数で扱いたいと言っている時、XPath結果の文字列表現を取り出し、整数(またはAS句で要求した任意の型)に変換するためにPostgreSQLの入力関数を使用します。 例えば、結果が空など、変換できない場合はエラーになります。 ですので、データに何らかの問題があると考えられる場合、列型として'text'に限定する方がよいかもしれません。
SELECT文の呼び出しでは、単なるSELECT *でなければならない必要性はありません。 出力列を名前で参照することも他のテーブルと結合することも可能です。 この関数は希望の何らかの操作(例えば集約、結合、ソートなど)を行うことができる仮想テーブルを生成します。 このため以下をより複雑な例として示すことができます。
SELECT t.title, p.fullname, p.email
FROM xpath_table('article_id', 'article_xml', 'articles',
'/article/title|/article/author/@id',
'xpath_string(article_xml,''/article/@date'') > ''2003-03-20'' ')
AS t(article_id integer, title text, author_id integer),
tblPeopleInfo AS p
WHERE t.author_id = p.person_id;
当然ながら、簡便にするためにこれをすべてビューとして包み隠すことができます。
xpath_table関数は各XPath問い合わせの結果が複数の値を持つ可能性があることを前提としています。
このため、この関数が返す行数は入力文書の数と同じにならない可能性があります。
返される最初の行には各問い合わせの最初の結果が、2番目の行には各問い合わせの2番目の結果が含まれます。
問い合わせの1つが他よりも少ない値を持つ場合は代わりにNULLが返されます。
指定したXPath問い合わせが単一の結果(おそらく一意な文書識別子)のみを返すことがユーザが分かっている場合があります。 もしこれを複数の結果を返すXPathと一緒に使用されると、単一値の結果は結果の最初の行にのみ現れます。 この解決方法はより単純なXPath問い合わせに対する結合部分としてキーフィールドを使用することです。 以下に例を示します。
CREATE TABLE test (
id int4 NOT NULL,
xml text,
CONSTRAINT pk PRIMARY KEY (id)
);
INSERT INTO test VALUES (1, '<doc num="C1">
<line num="L1"><a>1</a><b>2</b><c>3</c></line>
<line num="L2"><a>11</a><b>22</b><c>33</c></line>
</doc>');
INSERT INTO test VALUES (2, '<doc num="C2">
<line num="L1"><a>111</a><b>222</b><c>333</c></line>
<line num="L2"><a>111</a><b>222</b><c>333</c></line>
</doc>');
SELECT * FROM
xpath_table('id','xml','test',
'/doc/@num|/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
'true')
AS t(id int4, doc_num varchar(10), line_num varchar(10), val1 int4, val2 int4, val3 int4)
WHERE id = 1 ORDER BY doc_num, line_num
id | doc_num | line_num | val1 | val2 | val3
----+---------+----------+------+------+------
1 | C1 | L1 | 1 | 2 | 3
1 | | L2 | 11 | 22 | 33
各行にdoc_numを付けるためには、2つのxpath_tableを呼び出し、その結果を結合することです。
SELECT t.*,i.doc_num FROM
xpath_table('id', 'xml', 'test',
'/doc/line/@num|/doc/line/a|/doc/line/b|/doc/line/c',
'true')
AS t(id int4, line_num varchar(10), val1 int4, val2 int4, val3 int4),
xpath_table('id', 'xml', 'test', '/doc/@num', 'true')
AS i(id int4, doc_num varchar(10))
WHERE i.id=t.id AND i.id=1
ORDER BY doc_num, line_num;
id | line_num | val1 | val2 | val3 | doc_num
----+----------+------+------+------+---------
1 | L1 | 1 | 2 | 3 | C1
1 | L2 | 11 | 22 | 33 | C1
(2 rows)
libxsltがインストールされている場合、以下の関数を使用することができます。
xslt_process(text document, text stylesheet, text paramlist) returns text
この関数はXSLスタイルシートを文書に適用し、変換した結果を返します。 paramlistは、'a=1,b=2'という形で指定された、変換で使用されるパラメータ代入式のリストです。 パラメータ解析はあまり熟考されたものではないことに注意してください。パラメータ値にカンマを入れることができません。
また、文書またはスタイルシートのいずれかの値が<で始まらなければ、URLとして扱われ、libxsltはそれを取り込みます。
この結果xslt_processをURLの内容を取り込むための道具として使用できることになります。
これにはセキュリティ上の暗示があることに注意しなければなりません。
また、変換用のパラメータを渡さない、2つのパラメータを取るバージョンのxslt_processも存在します。
John Gray <jgray@azuli.co.uk>
本モジュールの開発はTorchbox Ltd. (www.torchbox.com)が後援です。 PostgreSQLと同じBSDライセンスです。