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になります。

Example:

SELECT xmlcomment('hello');

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

9.14.1.2. xmlconcat

 xmlconcat(xml[, ...])
 

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

Example:

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処理命令を作成します。内容が存在すれば、その内容は?>文字シーケンスを含んではなりません。

Example:

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.18を参照してください。

例:

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/>

現在の実装において連結の順序は原則として定義されていないことに注意してください。しかし、入力値を別の形で保存することも可能です。例えば、上記の例において次のようにして順序に影響を与えることもできるでしょう。

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

しかしこの手法はあらゆる場面や、すべてのPostgreSQLのバージョンに対して保障されているわけではありません。将来のPostgreSQLバージョンは(xmlagg(expr ORDER BY expr, expr, ... のような)相応の方法でこの順序を制御する追加機能を提供してくれるかもしれません。

9.14.1.8. XML述語

xml IS DOCUMENT

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

9.14.2. Processing XML

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

xpath(xpath, xml[, nsarray])

関数xpathは、XML値xmlに対し、XPath式xpathを評価します。そして、XPath式で作成されたノードセットに対応するXML値の配列を返します。

関数の3番目の引数は名前空間マッピング配列です。この配列は、第2軸が2に等しい長さをもつ2次元配列です(つまり、それは配列の配列で、それぞれは正確に2つの要素からなります)。それぞれの配列のエントリの最初の要素は名前空間の名前で、2番目は名前空間のURIです。

Example:

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)

9.14.3. 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>
アダルトレンタルサーバー