PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

9.15. XML 函数 #

9.15.1. 生成 XML 内容
9.15.2. XML 谓词
9.15.3. 处理 XML
9.15.4. 把表映射为 XML

本节描述的函数和类函数表达式作用于 xml 类型的值。 关于 xml 类型的信息请参见 Section 8.13。 用于与 xml 类型互相转换的类函数表达式 xmlparse 和 xmlserialize 记录在那里, 而非本节中。

这些函数中的大多数要求 PostgreSQL 是用 configure --with-libxml 构建的。

9.15.1. 生成 XML 内容 #

有一组函数和类函数表达式可用于从 SQL 数据产生 XML 内容。 因此, 它们特别适合于把查询结果格式化为 XML 文档, 以便在客户端应用程序中处理。

9.15.1.1. xmltext #

xmltext ( text ) → xml

函数 xmltext 返回一个 XML 值, 它带有单个文本节点, 并把输入参数作为其内容。 预定义实体, 例如与符号 (&)、 左右尖括号 (< >) 和引号 ("") 都会被转义。

示例:

SELECT xmltext('< foo & bar >');
         xmltext
-------------------------
 &lt; foo &amp; bar &gt;

9.15.1.2. xmlcomment #

xmlcomment ( text ) → xml

函数 xmlcomment 创建一个 XML 值, 其中包含一个以指定文本为内容的 XML 注释。 文本不能包含 “--” 或以 “-” 结尾, 否则产生的构造将不是一个有效的 XML 注释。 如果参数为空, 则结果为空。

示例:

SELECT xmlcomment('hello');

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

9.15.1.3. xmlconcat #

xmlconcat ( xml [, ...] ) → xml

函数 xmlconcat 串接一个由单独的 XML 值组成的列表, 创建一个包含 XML 内容片段的单一值。 空值会被省略; 只有当没有非空参数时结果才为空。

示例:

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

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

XML 声明 (如果存在) 按如下方式组合。 如果所有参数值具有相同的 XML 版本声明, 则在结果中使用该版本, 否则不使用任何版本。 如果所有参数值的独立声明值都为 “yes”, 则在结果中使用该值。 如果所有参数值都有独立声明值, 并且至少一个为 “no”, 则在结果中使用它。 否则, 结果将没有独立声明。 如果确定结果需要一个独立声明但没有版本声明, 则会使用版本为 1.0 的版本声明, 因为 XML 要求一个 XML 声明必须包含版本声明。 编码声明在所有情况下都会被忽略并移除。

示例:

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

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

9.15.1.4. xmlelement #

xmlelement ( NAME name [, XMLATTRIBUTES ( attvalue [ AS attname ] [, ...] ) ] [, content [, ...]] ) → xml

xmlelement 表达式产生一个具有给定名字、属性和内容的 XML 元素。 语法中展示的 name 和 attname 项是简单的标识符, 而非值。 attvalue 和 content 项是表达式, 它们可以产生任何 PostgreSQL 数据类型。 XMLATTRIBUTES 之内的参数产生 XML 元素的属性; content 值会被串接起来形成它的内容。

示例:

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 是该字符的十六进制记法的 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) 将以 base64 或十六进制编码表示, 取决于配置参数 xmlbinary 的设置。 各种数据类型的具体行为预计会演化, 以使 PostgreSQL 的映射与 SQL:2006 及后续版本中规定的映射对齐, 如 Section D.3.1.3 中所讨论。

9.15.1.5. xmlforest #

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

xmlforest 表达式使用给定的名字和内容产生一个元素组成的 XML 森林 (序列)。 与 xmlelement 一样, 每个 name 必须是一个简单标识符, 而 content 表达式可以有任何数据类型。

例子:

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

正如第二个例子所示, 如果内容值是一个列引用, 那么元素名可以省略, 在这种情况下默认使用列名。 否则必须指定一个名字。

不是有效 XML 名字的元素名会按照上文针对 xmlelement 展示的方式转义。 类似地, 内容数据会被转义为有效的 XML 内容, 除非它已经是 xml 类型。

注意, 如果 XML 森林由多于一个元素组成, 它们就不是有效的 XML 文档, 因此把 xmlforest 表达式包在 xmlelement 中可能会很有用。

9.15.1.6. xmlpi #

xmlpi ( NAME name [, content ] ) → xml

xmlpi 表达式创建一个 XML 处理指令。 与 xmlelement 一样, name 必须是一个简单标识符, 而 content 表达式可以有任何数据类型。 如果存在, content 不得包含字符序列 ?>。

示例:

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

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

9.15.1.7. xmlroot #

xmlroot ( xml, VERSION {text|NO VALUE} [, STANDALONE {YES|NO|NO VALUE} ] ) → xml

xmlroot 表达式改变一个 XML 值的根节点的属性。 如果指定了一个版本, 它会替换根节点版本声明中的值; 如果指定了一个独立设置, 它会替换根节点独立声明中的值。

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.15.1.8. xmlagg #

xmlagg ( xml ) → xml

与这里描述的其他函数不同, 函数 xmlagg 是一个聚集函数。 它把对聚集函数调用的输入值串接起来, 非常类似于 xmlconcat 所做的, 只是串接发生在多个行之间, 而非单行的多个表达式之间。 有关聚集函数的更多信息请参见 Section 9.21。

示例:

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

要确定串接的顺序, 可以向聚集调用添加一个 ORDER BY 子句, 如 Section 4.2.7 中所描述。 例如:

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.15.2. XML 谓词 #

本节描述的表达式检查 xml 值的属性。

9.15.2.1. IS DOCUMENT #

xml IS DOCUMENT → boolean

如果参数 XML 值是一个适当的 XML 文档, 表达式 IS DOCUMENT 返回真, 不是则返回假 (也就是说, 它是一个内容片段), 如果参数为空则返回空。 关于文档与内容片段之间的区别, 请参见 Section 8.13。

9.15.2.2. IS NOT DOCUMENT #

xml IS NOT DOCUMENT → boolean

如果参数 XML 值是一个适当的 XML 文档, 表达式 IS NOT DOCUMENT 返回假, 不是则返回真 (也就是说, 它是一个内容片段), 如果参数为空则返回空。

9.15.2.3. XMLEXISTS #

XMLEXISTS ( text PASSING [BY {REF|VALUE}] xml [BY {REF|VALUE}] ) → boolean

函数 xmlexists 求值一个 XPath 1.0 表达式 (第一个参数), 并以传入的 XML 值作为它的上下文项。 如果那次求值的结果产生一个空节点集, 该函数返回假; 如果产生任何其他值, 则返回真。 如果任何参数为空, 该函数返回空。 作为上下文项传入的非空值必须是一个 XML 文档, 而不能是一个内容片段或任何非 XML 值。

示例:

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

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

BY REF 和 BY VALUE 子句在 PostgreSQL 中会被接受, 但被忽略, 如 Section D.3.2 中所讨论。

在 SQL 标准中, xmlexists 函数求值一个 XML Query 语言中的表达式, 但 PostgreSQL 只允许一个 XPath 1.0 表达式, 如 Section D.3.1 中所讨论。

9.15.2.4. xml_is_well_formed #

xml_is_well_formed ( text ) → boolean
xml_is_well_formed_document ( text ) → boolean
xml_is_well_formed_content ( text ) → boolean

这些函数检查一个 text 字符串是否表示格式良好的 XML, 并返回一个布尔结果。 xml_is_well_formed_document 检查格式良好的文档, 而 xml_is_well_formed_content 检查格式良好的内容。 如果 xmloption 配置参数被设置为 DOCUMENT, 则 xml_is_well_formed 做前者, 如果被设置为 CONTENT 则做后者。 这意味着 xml_is_well_formed 对于查看对 xml 类型的简单转换是否会成功很有用, 而另外两个函数对于查看 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.15.3. 处理 XML #

为了处理 xml 数据类型的值, PostgreSQL 提供了求值 XPath 1.0 表达式的 xpath 和 xpath_exists 函数, 以及 XMLTABLE 表函数。

9.15.3.1. xpath #

xpath ( xpath text, xml xml [, nsarray text[] ] ) → xml[]

函数 xpath 针对给定的 XML 值 xml 求值 XPath 1.0 表达式 xpath (以文本给出)。 它返回一个由 XML 值组成的数组, 对应于该 XPath 表达式产生的节点集。 如果 XPath 表达式返回的是一个标量值而非节点集, 则返回一个单元素数组。

第二个参数必须是一个格式良好的 XML 文档。 特别是, 它必须有一个单一的根节点元素。

该函数可选的第三个参数是一个命名空间映射数组。 这个数组应当是一个二维 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)

9.15.3.2. xpath_exists #

xpath_exists ( xpath text, xml xml [, nsarray text[] ] ) → boolean

函数 xpath_exists 是 xpath 函数的一种特化形式。 这个函数不返回满足该 XPath 1.0 表达式的各个 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.15.3.3. xmltable #

XMLTABLE (
    [ XMLNAMESPACES ( namespace_uri AS namespace_name [, ...] ), ]
    row_expression PASSING [BY {REF|VALUE}] document_expression [BY {REF|VALUE}]
    COLUMNS name { type [PATH column_expression] [DEFAULT default_expression] [NOT NULL | NULL]
                  | FOR ORDINALITY }
            [, ...]
) → setof record

xmltable 表达式基于一个 XML 值、 一个用于提取行的 XPath 过滤器, 以及一组列定义来产生一个表。 虽然它在语法上类似于一个函数, 但它只能作为查询的 FROM 子句中的一张表出现。

可选的 XMLNAMESPACES 子句给出一个以逗号分隔的命名空间定义列表, 其中每个 namespace_uri 是一个 text 表达式, 而每个 namespace_name 是一个简单标识符。 它规定文档中使用的 XML 命名空间及其别名。 目前不支持默认命名空间的说明。

必需的 row_expression 参数是一个 XPath 1.0 表达式 (以 text 给出), 它会被求值, 并以 XML 值 document_expression 作为它的上下文项, 来获得一组 XML 节点。 这些节点就是 xmltable 要转换成输出行的对象。 如果 document_expression 为空, 或者 row_expression 产生一个空节点集或任何非节点集的值, 则不会产生任何行。

document_expression 为 row_expression 提供上下文项。 它必须是一个格式良好的 XML 文档; 不接受片段/森林。 BY REF 和 BY VALUE 子句会被接受但被忽略, 如 Section D.3.2 中所讨论。

在 SQL 标准中, xmltable 函数求值 XML Query 语言中的表达式, 但 PostgreSQL 只允许 XPath 1.0 表达式, 如 Section D.3.1 中所讨论。

必需的 COLUMNS 子句指定将在输出表中产生的列。 格式请参见上文的语法摘要。 每一列都需要一个名字和一个数据类型 (除非指定了 FOR ORDINALITY, 在那种情况下隐含的类型是 integer)。 路径、默认值和可空性子句是可选的。

被标记为 FOR ORDINALITY 的列会被填上行编号, 从 1 开始, 顺序是从 row_expression 的结果节点集中检索节点的顺序。 至多只能有一列被标记为 FOR ORDINALITY。

Note

XPath 1.0 没有为节点集中的节点规定顺序, 因此依赖结果的特定顺序的代码将是取决于实现的。 细节可以在 Section D.3.1.2 中找到。

一列的 column_expression 是一个 XPath 1.0 表达式, 它会对每一行求值, 以 row_expression 结果中的当前节点作为它的上下文项, 来找出该列的值。 如果没有给出 column_expression, 那么列名会被用作一个隐式路径。

如果一列的 XPath 表达式返回一个非 XML 值 (在 XPath 1.0 中它被限定为字符串、 布尔值或双精度值), 并且该列具有一个非 xml 的 PostgreSQL 类型, 那么该列的设置方式就如同把该值的字符串表示赋给该 PostgreSQL 类型。 (如果该值是一个布尔值, 当输出列的类型类别是数字时, 其字符串表示被取为 1 或 0, 否则为 true 或 false。)

如果一列的 XPath 表达式返回一个非空的 XML 节点集, 并且该列的 PostgreSQL 类型是 xml, 那么如果该表达式结果处于文档或内容形式, 该列会被精确地赋值为该表达式结果。 [7]

被赋给一个 xml 输出列的非 XML 结果会产生内容, 即一个带有该结果字符串值的单一文本节点。 被赋给任何其他类型列的 XML 结果不得有多于一个节点, 否则会抛出错误。 如果恰好有一个节点, 该列的设置方式就如同把该节点的字符串值 (按 XPath 1.0 的 string 函数的定义) 赋给该 PostgreSQL 类型。

一个 XML 元素的字符串值是该元素及其后代中包含的全部文本节点按文档顺序的 串接。 一个没有后代文本节点的元素的字符串值是一个空字符串 (而非 NULL)。 任何 xsi:nil 属性都会被忽略。 注意, 两个非文本元素之间只有空白的 text() 节点会被保留, 并且 text() 节点上的前导空白不会被展平。 定义其他 XML 节点类型和非 XML 值的字符串值的规则, 请参见 XPath 1.0 的 string 函数。

这里给出的转换规则与 SQL 标准的规则并不完全相同, 如 Section D.3.1.3 中所讨论。

如果路径表达式对某一行返回一个空节点集 (通常发生在它不匹配的时候), 那么该列会被设置为 NULL, 除非指定了一个 default_expression; 在那种情况下会使用对该表达式求值得到的值。

default_expression 并不会在 xmltable 被调用时立即被求值, 而是在每次需要该列的默认值时被求值。 如果该表达式符合稳定或不可变的条件, 可以跳过重复求值。 这意味着你可以有效地在 default_expression 中使用诸如 nextval 之类的易变函数 (create_if_missing 为真时, 如果索引为负, 新值会被加在数组的开头, 为正时加在末尾)

例子:

CREATE TABLE xmldata AS SELECT
xml $$
<ROWS>
  <ROW id="1">
    <COUNTRY_ID>AU</COUNTRY_ID>
    <COUNTRY_NAME>Australia</COUNTRY_NAME>
  </ROW>
  <ROW id="5">
    <COUNTRY_ID>JP</COUNTRY_ID>
    <COUNTRY_NAME>Japan</COUNTRY_NAME>
    <PREMIER_NAME>Shinzo Abe</PREMIER_NAME>
    <SIZE unit="sq_mi">145935</SIZE>
  </ROW>
  <ROW id="6">
    <COUNTRY_ID>SG</COUNTRY_ID>
    <COUNTRY_NAME>Singapore</COUNTRY_NAME>
    <SIZE unit="sq_km">697</SIZE>
  </ROW>
</ROWS>
$$ AS data;

SELECT xmltable.*
  FROM xmldata,
       XMLTABLE('//ROWS/ROW'
                PASSING data
                COLUMNS id int PATH '@id',
                        ordinality FOR ORDINALITY,
                        "COUNTRY_NAME" text,
                        country_id text PATH 'COUNTRY_ID',
                        size_sq_km float PATH 'SIZE[@unit = "sq_km"]',
                        size_other text PATH
                             'concat(SIZE[@unit!="sq_km"], " ", SIZE[@unit!="sq_km"]/@unit)',
                        premier_name text PATH 'PREMIER_NAME' DEFAULT 'not specified');

 id | ordinality | COUNTRY_NAME | country_id | size_sq_km |  size_other  | premier_name
----+------------+--------------+------------+------------+--------------+---------------
  1 |          1 | Australia    | AU         |            |              | not specified
  5 |          2 | Japan        | JP         |            | 145935 sq_mi | Shinzo Abe
  6 |          3 | Singapore    | SG         |        697 |              | not specified

下面的例子展示了多个 text() 节点的串接、 把列名用作 XPath 过滤器, 以及对空白、 XML 注释和处理指令的处理:

CREATE TABLE xmlelements AS SELECT
xml $$
  <root>
   <element>  Hello<!-- xyxxz -->2a2<?aaaaa?> <!--x-->  bbb<x>xxx</x>CC  </element>
  </root>
$$ AS data;

SELECT xmltable.*
  FROM xmlelements, XMLTABLE('/root' PASSING data COLUMNS element text);
         element
-------------------------
   Hello2a2   bbbxxxCC

下面的例子说明了如何使用 XMLNAMESPACES 子句来指定 XML 文档以及 XPath 表达式中使用的命名空间列表:

WITH xmldata(data) AS (VALUES ('
<example xmlns="http://example.com/myns" xmlns:B="http://example.com/b">
 <item foo="1" B:bar="2"/>
 <item foo="3" B:bar="4"/>
 <item foo="4" B:bar="5"/>
</example>'::xml)
)
SELECT xmltable.*
  FROM XMLTABLE(XMLNAMESPACES('http://example.com/myns' AS x,
                              'http://example.com/b' AS "B"),
             '/x:example/x:item'
                PASSING (SELECT data FROM xmldata)
                COLUMNS foo int PATH '@foo',
                  bar int PATH '@B:bar');
 foo | bar
-----+-----
   1 |   2
   3 |   4
   4 |   5
(3 rows)

9.15.4. 把表映射为 XML #

以下函数把关系表的内容映射为 XML 值。 它们可以被看作 XML 导出功能:

table_to_xml ( table regclass, nulls boolean,
               tableforest boolean, targetns text ) → xml
query_to_xml ( query text, nulls boolean,
               tableforest boolean, targetns text ) → xml
cursor_to_xml ( cursor refcursor, count integer, nulls boolean,
                tableforest boolean, targetns text ) → xml

table_to_xml 映射由参数 table 传入的命名表的内容。 regclass 类型接受使用惯用记法标识表的字符串, 包括可选的模式限定和双引号 (细节请参见 Section 8.19)。 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>

...

如果没有可用的表名, 也就是说在映射一个查询或游标时, 第一种格式使用字符串 table, 第二种格式使用 row。

在这些格式之间的选择由用户决定。 第一种格式是一个适当的 XML 文档, 这在许多应用程序中都很重要。 如果结果值以后要被重新组装成一个文档, 那么第二种格式在 cursor_to_xml 函数中往往更有用。 上面讨论的、 用于产生 XML 内容的那些函数 (特别是 xmlelement) 可以用来按自己的偏好修饰结果。

数据值的映射方式与上文针对 xmlelement 函数描述的相同。

参数 nulls 决定空值是否应当被包括在输出中。 如果为真, 列中的空值会被表示为:

<columnname xsi:nil="true"/>

其中 xsi 是 XML Schema Instance 的 XML 命名空间前缀。 会向结果值中添加一个适当的命名空间声明。 如果为假, 包含空值的列会被简单地从输出中省略。

参数 targetns 规定期望的结果 XML 命名空间。 如果不想要任何特定的命名空间, 应当传入一个空字符串。

以下函数返回 XML Schema 文档, 描述上面相应函数执行的映射:

table_to_xmlschema ( table regclass, nulls boolean,
                     tableforest boolean, targetns text ) → xml
query_to_xmlschema ( query text, nulls boolean,
                     tableforest boolean, targetns text ) → xml
cursor_to_xmlschema ( cursor refcursor, nulls boolean,
                      tableforest boolean, targetns text ) → xml

要获得相匹配的 XML 数据映射和 XML Schema 文档, 传入相同的参数至关重要。

以下函数把 XML 数据映射和相应的 XML Schema 一起放在一个文档 (或森林)中, 并把它们链接起来。 在希望得到自包含、 自描述的结果时, 它们可能很有用:

table_to_xml_and_xmlschema ( table regclass, nulls boolean,
                             tableforest boolean, targetns text ) → xml
query_to_xml_and_xmlschema ( query text, nulls boolean,
                             tableforest boolean, targetns text ) → xml

此外, 还有一些函数可用于产生整个模式或整个当前数据库的类似映射:

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

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

这些函数会忽略当前用户不可读的表。 数据库级函数还会忽略当前用户对其没有 USAGE (查找) 特权的模式。

注意, 这些函数有可能产生大量数据, 这些数据需要在内存中构建。 当请求大型模式或数据库的内容映射时, 值得考虑改为逐个映射表, 甚至可能通过一个游标来进行。

模式内容映射的结果看起来像这样:

<schemaname>

table1-mapping

table2-mapping

...

</schemaname>

其中表映射的格式取决于 tableforest 参数, 如上文所解释。

数据库内容映射的结果看起来像这样:

<dbname>

<schema1name>
  ...
</schema1name>

<schema2name>
  ...
</schema2name>

...

</dbname>

其中模式映射如上文所述。

作为使用这些函数产生的输出的一个例子, Example 9.1 展示了一个 XSLT 样式表, 它把 table_to_xml_and_xmlschema 的输出转换为一个包含表数据表格化呈现的 HTML 文档。 以类似的方式, 这些函数的结果可以被转换为其他基于 XML 的格式。

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



[7] 一个在顶层包含多于一个元素节点、 或者在元素之外包含非空白文本的结果, 是内容形式的一个例子。 一个 XPath 结果也可能不属于任何形式, 例如当它返回一个从包含它的元素中选出的属性节点时。 这样的结果会被放入内容形式, 其中每个这样的不允许的节点都会被替换为它的字符串值, 如 XPath 1.0 的 string 函数所定义的那样。