9.14. XML函数

在本节描述的函数和像函数的表达式都是操作基于xml类型的值。 查看Section 8.13获取关于xml类型的信息。 像函数表达式的xmlparsexmlserialize 用来转换为和从类型xml转换不在这里重复。使用这些函数需要在构建命令 configure --with-libxml安装。

9.14.1. 生成XML内容

一组函数和像函数的表达式可用于从SQL数据生成XML内容。 所以它们特别适合于查询结果格式化成 在客户端应用程序处理的XML文件。

9.14.1.1. xmlcomment

xmlcomment(text)

xmlcomment函数创建一个包含XML注释的特定文本内容的值。文本中不能包含"--""-"的结束,这样的文本是有效的XML注释。如果参数是空,结果是空。

Example:

SELECT xmlcomment('hello');

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

9.14.1.2. xmlconcat

xmlconcat(xml[, ...])

函数xmlconcat连接一个独立的XML值列表来创建一个包含XML内容片段的单值。 忽略空值;只有当参数都为空时结果是空。

示例:

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

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

XML声明,如果存在,结合如下。如果所有参数使用相同的XML版本声明,则在结果是使用版本。否则不用版本。 如果所有的参数值有独立的声明值,然后这个值在结果里使用。如果所有的参数值有独立的声明,并且至少有一个是"没有的", 然后这个值在结果里使用。否则结果将没有独立声明。如果结果决定需要一个独立的声明,但没有声明版本,将使用一个带有版本1.0的版本声明, 因为XML需要一个XML声明包含版本声明。忽略编码声明,在所有情况下删除。

Example:

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(namename[, xmlattributes(value[ASattname][, ...])][, 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>

不合法的元素和属性名由逃逸序列_xHHHH_替换有问题的字符, 这里的HHHH是字符Unicode编码值的16进制表示。例如:

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字符串数据。这意味着特殊字符 <, >, and &将转化为一般符号。将二进制数据(bytea数据类型用base64或16进值编码表示,根据 配置参数xmlbinary的设置。单个数据类型的特定行为,预计演变以对齐与 XML 架构规范, 在哪个点的更准确描述将出现 SQL 和 PostgreSQL 的数据类型。

9.14.1.4. xmlforest

xmlforest(content[ASname][, ...])

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

在第二个例子可以看出,如果内容值为列引用,元素名称可以省略。在这种情况下,默认使用列名。否则,必须指定名称。

非法XML名的元素名称,像上面的xmlelement逃逸处理。类似内容数据逃逸生成有效的XML内容, 除非它已经是xml类型的。

请注意,如果组成一个以上的元素,XML的森林不是有效的XML文档,所以在xmlelement封装 xmlforest表达式可能是有用的。

9.14.1.5. xmlpi

xmlpi(nametarget[content])

xmlpi表达式创建一条XML处理指令。 如果存在,内容必须不能包含字符序列?>

示例:

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

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

9.14.1.6. xmlroot

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

xmlroot表示更改根节点属性的XML值。如果指定一个版本, 它替换根节点的版本声明值;如果指定一个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,除了串联发生跨行,而不是单行中跨表达式。请参阅Section 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/>

为了确定连接顺序,一个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.14.1.8. XML谓词

xmlIS DOCUMENT

表达式IS DOCUMENT如果参数XML值是一个合法的XML文档,返回真。否则返回假(例如,内容片段)或如果参数为空则返回空。 请参阅Section 8.13关于文档和内容片段之间的不同。

9.14.2. 处理XML

PostgreSQL提供了xpath函数处理xml数据类型的值。 计算XPath 1.0表达式的结果。

xpath(xpathxml[nsarray])

xpath函数,对xmlXML值计算xpathXPath表达式的结果。 它返回一个XML值的数组对应XPath表达式所产生的节点集。

第二个参数必须是一个完整的XML文档。特别是,它必须有一个根节点元素。

该函数的第三个参数是一个命名空间的数组映射。这个数组应该是一个两维数组, 第二个轴的长度等于2(它应该是一个数组的数组,其中每个包含完全2个元素)。 每个数组项的第一个元素是命名空间名称的别名,第二个命名空间 URI。 这个数组的别名不是必须提供的,与在XML文档本身使用的相同。(换句话说,在XML文档和在的XPath 函数的上下文中,别名是local)。

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)

How to deal with default (anonymous) namespaces:

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.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映射命名表的内容,传递参数tblregclass类型接受使用常用符号的字符串标识表,包括可选的模式(schema)结构和双引号。 query_to_xml执行传递的文本query参数查询,并映射结果集。 cursor_to_xmlcursor的游标中获取指定数量的行。如果大数据表映射,建议使用这个函数, 因为每个函数的结果值在内存中构建的。

如果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架构实例的XML命名空间前缀。 为结果值添加一个适当的命名空间声明。 如果假, 从输出的列包含空值只是简单的省略。

参数的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架构一个文档或森林中,联系在一起。 它们可能很有用,想自我包含和描述的结果:

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>

模式映射如上所述。

使用这些函数产生的输出作为例子,Figure 9-1显示一个XSLT样式表转换 table_to_xml_and_xmlschema到HTML的输出,该文当中包含了一个表格再现表数据。 以类似的方式,可以从这些函数转换成其它基于XML格式的结果。

Figure 9-1. XSLT样式表--将SQL/XML转换成HTML

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