★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

9.14. XML関数

この節で説明される関数および擬似関数式は、xml型の値に対して機能します。 xml型についての情報は項8.13を点検してください。 xml型のやりとりを変換するxmlparseおよびxmlserialize擬似関数式はここでは繰り返しません。 これらの多くの関数を使用するには、インストレーションの際configure --with-libxml付きでビルドされていることが必要です。

9.14.1. XML内容の生成

SQLデータからXML内容を生成するために関数と擬似関数式の一式が提供されています。 そのようなものとして、クライアントアプリケーションが問い合わせ結果を処理のためXML文書に書式化するのにこれらは特に適しています。

9.14.1.1. xmlcomment

xmlcomment(text)

関数xmlcommentは特定のテキストを内容としてXMLコメントを含んだXML値を作成します。 テキストには結果として構築されるXMLコメントが有効になるよう"--"または"-"で終結する内容を含んではなりません。引数がNULLならば結果もNULLになります。

例:

SELECT xmlcomment('hello');

  xmlcomment
--------------
 <!--hello-->

9.14.1.2. xmlconcat

xmlconcat(xml[, ...])

関数xmlconcatは、XMLの内容断片を含む単一値を作成するために個別のXML値のリストを結合します。 NULL値は削除され、NULL以外の引数が存在しないときのみ結果はNULLになります。

例:

SELECT xmlconcat('<abc/>', '<bar>foo</bar>');

      xmlconcat
----------------------
 <abc/><bar>foo</bar>

XML宣言が提示されている場合は次のように組み合わせることができます。 全ての引数の値が同一のXMLversion宣言を持っていれば、そのversionが結果に使用されます。さもなければversionは使用されません。 もし全ての引数の値がstandalone宣言値である"yes"であれば、その値が結果に使用されます。 もし全ての引数の値がstandalone宣言値であり、その中で1つでも"no"がある場合、それが結果に使用されます。 さもなければ、結果はstandalone宣言を持ちません。 もし結果がstandalone宣言を必要としていても、standalone宣言がない場合には、XMLはversion宣言を含むXML宣言を要求するため、version 1.0のversion宣言が使用されます。 encoding宣言は無視され、全ての場合で削除されます。

例:

SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone="no"?><bar/>');

             xmlconcat
-----------------------------------
 <?xml version="1.1"?><foo/><bar/>

9.14.1.3. xmlelement

xmlelement(name name [, xmlattributes(value [AS attname] [, ... ])] [, content, ...])

xmlelement式は与えられた名前、属性、および内容を持つXML要素を生成します。

例:

SELECT xmlelement(name foo);

 xmlelement
------------
 <foo/>

SELECT xmlelement(name foo, xmlattributes('xyz' as bar));

    xmlelement
------------------
 <foo bar="xyz"/>

SELECT xmlelement(name foo, xmlattributes(current_date as bar), 'cont', 'ent');

             xmlelement
-------------------------------------
 <foo bar="2007-01-26">content</foo>

有効でないXML名の要素と属性名は、シーケンス_xHHHH_により障害となる文字を置換することでエスケープされます。ここで、HHHHは16進数によるその文字のUnicode文字コード番号です。 例をあげます。

SELECT xmlelement(name "foo$bar", xmlattributes('xyz' as "a&b"));

            xmlelement
----------------------------------
 <foo_x0024_bar a_x0026_b="xyz"/>

属性値が列参照の場合、明示的な属性名を指定する必要はありません。この場合、デフォルトで列名が属性名として使用されます。 その他の場合には、属性は明示的な名前で与えられなければなりません。 従って、以下の例は有効です。

CREATE TABLE test (a xml, b xml);
SELECT xmlelement(name test, xmlattributes(a, b)) FROM test;

しかし、以下の例は有効ではありません。

SELECT xmlelement(name test, xmlattributes('constant'), a, b) FROM test;
SELECT xmlelement(name test, xmlattributes(func(a, b))) FROM test;

もし要素内容が指定されればそのデータ型に従って書式化されます。 もし内容そのものがxml型であれば、複合XML文書が構築されます。 例をあげます。

SELECT xmlelement(name foo, xmlattributes('xyz' as bar),
                            xmlelement(name abc),
                            xmlcomment('test'),
                            xmlelement(name xyz));

                  xmlelement
----------------------------------------------
 <foo bar="xyz"><abc/><!--test--><xyz/></foo>

そのほかの型の内容は有効なXML文字データにフォーマットされます。 これは特に文字<、>、および&がエンティティに変換されることを意味します。 バイナリデータ(データ型はbytea)は、構成パラメータxmlbinaryの設定にしたがって、base64もしくは16進符号化方式で表現されます。 個々のデータ型に対する特定の動作は、XMLスキーマ仕様でのSQLおよびPostgreSQLデータ型に調整するため展開されると期待されます。この時点でより詳細な記述が出現します。

9.14.1.4. xmlforest

xmlforest(content [AS name] [, ...])

xmlforest式は与えられた名前と内容を使用し、要素のXMLフォレスト(シーケンス)を生成します。

例:

SELECT xmlforest('abc' AS foo, 123 AS bar);

          xmlforest
------------------------------
 <foo>abc</foo><bar>123</bar>


SELECT xmlforest(table_name, column_name)
FROM information_schema.columns
WHERE table_schema = 'pg_catalog';

                                         xmlforest
-------------------------------------------------------------------------------------------
 <table_name>pg_authid</table_name><column_name>rolname</column_name>
 <table_name>pg_authid</table_name><column_name>rolsuper</column_name>
 ...

第2の例に見られるように、内容の値が列参照の場合、要素名は省略可能です。この時は、列名がデフォルトで使用されます。 そうでない時は、名前が指定されなければなりません。

有効なXML名ではない要素名は上のxmlelementで説明した通りエスケープされます。 同様にして、既にxml型であるものを除き、内容データは有効なXML内容になるようにエスケープされます。

XMLフォレストは1より多い要素からなる場合、有効なXML文書ではないことに注意してください。 したがって、xmlelementxmlforest式をラップすることが有用なことがあります。

9.14.1.5. xmlpi

xmlpi(name target [, content])

xmlpi式はXML処理命令を作成します。 内容が存在すれば、その内容は?>文字シーケンスを含んではなりません。

例:

SELECT xmlpi(name php, 'echo "hello world";');

            xmlpi
-----------------------------
 <?php echo "hello world";?>

9.14.1.6. xmlroot

xmlroot(xml, version text | no value [, standalone yes|no|no value])

xmlroot式はXML値のルートノードの属性を変更します。 versionが指定されていると、ルートノードのversion宣言での値を変更し、standalone設定が指定されていると、ルートノードのstandalone宣言での値を変更します。

SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'),
               version '1.0', standalone yes);

                xmlroot
----------------------------------------
 <?xml version="1.0" standalone="yes"?>
 <content>abc</content>

9.14.1.7. xmlagg

xmlagg(xml)

ここで説明している関数とは異なり、xmlagg関数は集約関数です。 単一行の要素ではなく、複数行にまたがった連結となりますが、xmlconcatが行うように、入力値を集約関数呼び出しに連結します。 集約関数についての追加情報は項9.20を参照してください。

例:

CREATE TABLE test (y int, x xml);
INSERT INTO test VALUES (1, '<foo>abc</foo>');
INSERT INTO test VALUES (2, '<bar/>');
SELECT xmlagg(x) FROM test;
        xmlagg
----------------------
 <foo>abc</foo><bar/>

連結の順序を決定するため、項4.2.7に記述されているようにORDER BY句を集計呼び出しに追加すると良いでしょう。 以下は例です。

SELECT xmlagg(x ORDER BY y DESC) FROM test;
        xmlagg
----------------------
 <bar/><foo>abc</foo>

下記は以前のバージョンで推奨されていた、非標準的な方法例です。特定のケースでは有用かもしれません。

SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
        xmlagg
----------------------
 <bar/><foo>abc</foo>

9.14.2. XML述語

この節で記述されている式は、xml値の属性をチェックします。

9.14.2.1. IS DOCUMENT

xml IS DOCUMENT

IS DOCUMENTは引数XML値が適切なXML文書であれば真を返し、そうでなければ(つまり、内容の断片)偽を返すか、もしくは引数がNULLであればNULLを返します。 文書と内容の断片の差異については項8.13を参照してください。

9.14.2.2. XMLEXISTS

XMLEXISTS(text PASSING [BY REF] xml [BY REF])

関数xmlexistsはXPath式の第一引数が何かしらのノードであれば真を返し、そうでなければ偽を返します。 (もしいずれの引数もNULLであった場合はNULLを返します。)

例:

SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Toronto</town><town>Ottawa</town></towns>');

 xmlexists
------------
 t
(1 row)

BY REF句は、PostgreSQLには何の影響も与えませんが、別製品とのSQL互換性や順応性のため、付与することができます。 SQL標準では最初にBY REFを必要としており、2つ目の引数以降はオプショナルです。加えてSQL標準ではxmlexistsはXQueryを第一引数として取る構成としていますが、 PostgreSQLでは現在XQueryのサブセットにあたるXpathのみサポートしていることに注意してください。

9.14.2.3. xml_is_well_formed

xml_is_well_formed(text)
xml_is_well_formed_document(text)
xml_is_well_formed_content(text)

これらの関数はtext文字列が整形式かどうかをチェックし、論理値で結果を返します。 xml_is_well_formed_documentは文書が整形式かをチェックし、一方xml_is_well_formed_contentは内容が整形式かをチェックします。 xml_is_well_formedは、xmloptionパラメータ値がDOCUMENTに設定されていれば前者を、CONTENTが設定されていれば後者のチェックを実施します。 これは、xml_is_well_formedは単純なxml型へのキャストが成功するかの判断に有用であり、その他の2つの関数はXMLPARSEの対応による変換が成功するかの判断に有用であることを意味します。

例:

SET xmloption TO DOCUMENT;
SELECT xml_is_well_formed('<>');
 xml_is_well_formed 
--------------------
 f
(1 row)

SELECT xml_is_well_formed('<abc/>');
 xml_is_well_formed 
--------------------
 t
(1 row)

SET xmloption TO CONTENT;
SELECT xml_is_well_formed('abc');
 xml_is_well_formed 
--------------------
 t
(1 row)

SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</pg:foo>');
 xml_is_well_formed_document 
-----------------------------
 t
(1 row)

SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</my:foo>');
 xml_is_well_formed_document 
-----------------------------
 f
(1 row)

最後の例は、名前空間が正しく一致しているかのチェックも含むことを示しています。

9.14.3. XMLの処理

データ型xmlの値を処理するため、PostgreSQLは関数xpathxpath_existsを提供しており、それはXPath 1.0式を評価します。

xpath(xpath, xml [, nsarray])

関数xpathは、XML値xmlに対し、XPath式xpath(ひとつのtext値)を評価します。そして、XPath式で作成されたノードセットに対応するXML値の配列を返します。 もし、XPath式がノードセットではなくスカラー値を返す場合、単一要素の配列が返されます。

2番目の引数は整形済XML文書でなければなりません。特に、単一のルートノード要素を持たなければなりません。

オプショナルな関数の3番目の引数は名前空間マッピング配列です。 この配列は、第2軸が2に等しい長さをもつ2次元text配列です(つまり、それは配列の配列で、それぞれは正確に2つの要素からなります)。 それぞれの配列のエントリの最初の要素は名前空間の名前(別名)で、2番目は名前空間のURIです。 この配列内で提供される別名がXML文書自身で使用されるものと同じであることは必要ではありません(言い換えると、XML文書内およびxpath関数の両方の文脈の中で、別名はローカルです)。

例:

SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
             ARRAY[ARRAY['my', 'http://example.com']]);

 xpath  
--------
 {test}
(1 row)

デフォルト(匿名)名前空間を取り扱うためには、以下のようなことを実施してください。

SELECT xpath('//mydefns:b/text()', '<a xmlns="http://example.com"><b>test</b></a>',
             ARRAY[ARRAY['mydefns', 'http://example.com']]);

 xpath
--------
 {test}
(1 row)

xpath_exists(xpath, xml [, nsarray])

関数xpath_existsは、xpath関数の特別な形式です。この関数は、XPathを満足する個別のXML値を返す代わりに、問い合わせがそれを満足するかどうかを論理値で返します。 この関数は、名前空間にマッピングされた引数をもサポートする点を除き、標準のXMLEXISTS述語と同じです。

例:

SELECT xpath_exists('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
                     ARRAY[ARRAY['my', 'http://example.com']]);

 xpath_exists  
--------------
 t
(1 row)

9.14.4. XMLにテーブルをマップ

以下の関数はリレーショナルテーブルの内容をXML値にマップします。 これらはXMLエクスポート機能と考えることができます。

table_to_xml(tbl regclass, nulls boolean, tableforest boolean, targetns text)
query_to_xml(query text, nulls boolean, tableforest boolean, targetns text)
cursor_to_xml(cursor refcursor, count int, nulls boolean,
              tableforest boolean, targetns text)

それぞれの関数の戻り値型はxmlです。

table_to_xmlは、パラメータtblとして渡された名前付きのテーブルの内容をマップします。 regclass型はオプションのスキーマ修飾と二重引用符を含む、通常の表記法を使用しテーブルを特定する文字列を受け付けます。 query_to_xmlは、パラメータqueryとしてテキストが渡された問い合わせを実行し、結果セットをマップします。 cursor_to_xmlは、パラメータcursorで指定されたカーソルから提示された行数を取得します。 この変異形は、それぞれの関数により結果値がメモリーに構築されるため、巨大なテーブルをマップする必要がある場合推奨されます。

tableforestが偽であれば、結果のXML文書は以下のようになります。

<tablename>
  <row>
    <columnname1>data</columnname1>
    <columnname2>data</columnname2>
  </row>

  <row>
    ...
  </row>

  ...
</tablename>

tableforestが真であれば、結果は以下のようなXML文書の断片です。

<tablename>
  <columnname1>data</columnname1>
  <columnname2>data</columnname2>
</tablename>

<tablename>
  ...
</tablename>

...

テーブル名が1つも有効でなければ、つまり、問い合わせ、またはカーソルをマップする時、文字列tableが最初の書式で使用され、rowが2番目の書式で使用されます。

これらどの書式を選択するのかはユーザ次第です。 最初の書式は適切なXML文書で、多くのアプリケーションにおいて重要です。 第2の書式は、後に結果値が1つの文書に再び組み立てられる場合、cursor_to_xml関数内でより有用になる傾向があります。 上記で説明したXML内容を作成する関数、特にxmlelementは結果を好みにかえるために使用することができます。

データの値は上記関数xmlelementで説明したのと同じ方法でマップされます。

パラメータnullsは出力にNULL値が含まれる必要があるかを決定します。 もし真であれば列内のNULL値は以下のように表現されます。

<columnname xsi:nil="true"/>

ここでxsiはXMLスキーマインスタンスに対するXML名前空間接頭辞です。 適切な名前空間宣言が結果値に追加されます。 もし偽の場合、NULL値を含む列は単に出力から削除されます。

パラメータtargetnsは結果の希望するXML名前空間を指定します。 特定の名前空間が必要なければ、空文字列を渡す必要があります。

以下の関数は、対応する上記関数により行われたマッピングを記述するXMLスキーマ文書を返します。

table_to_xmlschema(tbl regclass, nulls boolean, tableforest boolean, targetns text)
query_to_xmlschema(query text, nulls boolean, tableforest boolean, targetns text)
cursor_to_xmlschema(cursor refcursor, nulls boolean, tableforest boolean, targetns text)

一致するXMLデータマッピングとXMLスキーマ文書を取得するため、同じパラメータが渡されることが不可欠です。

以下の関数は、XMLデータマッピングとそれに対応するXMLスキーマがお互いにリンクされた、1つの文書(またはフォレスト)を作成します。 これらは自己完結した、自己記述的な結果を希望する場合に便利です。

table_to_xml_and_xmlschema(tbl regclass, nulls boolean, tableforest boolean, targetns text)
query_to_xml_and_xmlschema(query text, nulls boolean, tableforest boolean, targetns text)

さらに、以下の関数がスキーマ全体、または現在のデータベース全体の類似マッピングを作成するため利用できます。

schema_to_xml(schema name, nulls boolean, tableforest boolean, targetns text)
schema_to_xmlschema(schema name, nulls boolean, tableforest boolean, targetns text)
schema_to_xml_and_xmlschema(schema name, nulls boolean, tableforest boolean, targetns text)

database_to_xml(nulls boolean, tableforest boolean, targetns text)
database_to_xmlschema(nulls boolean, tableforest boolean, targetns text)
database_to_xml_and_xmlschema(nulls boolean, tableforest boolean, targetns text)

これらはメモリー内に作成される必要がある、多くのデータを生成する潜在的可能性があることに注意してください。 巨大なスキーマ、またはデータベースの内容マッピングを要求する際は、カーソル経由の可能性があっても、その代わりにテーブルを別々にマップすることを検討することは無駄ではありません。

スキーマ内容マッピングの結果は以下のようになります。

<schemaname>

table1-mapping

table2-mapping

...

</schemaname>

ここで、テーブルマッピング書式は上で説明したとおりtableforestパラメータに依存します。

データベース内容マッピング書式は以下のようになります。

<dbname>

<schema1name>
  ...
</schema1name>

<schema2name>
  ...
</schema2name>

...

</dbname>

ここで、スキーママッピングは上記のとおりです。

これらの関数で作成された出力を使用する1つの例として、図9-1は、テーブルデータの表形式への翻訳を含むtable_to_xml_and_xmlschemaからHTML文書への出力の変換をおこなうXSLTスタイルシートを示します。 同じようにして、これらの関数の結果は他のXML基準書式に変換されます。

図 9-1. SQL/XML出力をHTMLに変換するXSLTスタイルシート

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns="http://www.w3.org/1999/xhtml"
>

  <xsl:output method="xml"
      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
      doctype-public="-//W3C/DTD XHTML 1.0 Strict//EN"
      indent="yes"/>

  <xsl:template match="/*">
    <xsl:variable name="schema" select="//xsd:schema"/>
    <xsl:variable name="tabletypename"
                  select="$schema/xsd:element[@name=name(current())]/@type"/>
    <xsl:variable name="rowtypename"
                  select="$schema/xsd:complexType[@name=$tabletypename]/xsd:sequence/xsd:element[@name='row']/@type"/>

    <html>
      <head>
        <title><xsl:value-of select="name(current())"/></title>
      </head>
      <body>
        <table>
          <tr>
            <xsl:for-each select="$schema/xsd:complexType[@name=$rowtypename]/xsd:sequence/xsd:element/@name">
              <th><xsl:value-of select="."/></th>
            </xsl:for-each>
          </tr>

          <xsl:for-each select="row">
            <tr>
              <xsl:for-each select="*">
                <td><xsl:value-of select="."/></td>
              </xsl:for-each>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>