9.14. XML 函数

From PostgreSQL 中文维基, PostgreSQL 中文站, PostgreSQL 中国社区, PostgreSQL Chinese community

Jump to: navigation, search

目录

[编辑] XML 函数

本节里描述的函数和函数样的表达式操作类型 xml 的数值。参阅第8.13节获取有关xml类型的信息。用于在 xml 类型和字符类型之间转换的函数样表达式 xmlparse 和 xmlserialize 不在这里重复了。使用下面函数基本上都需要安装的版本是带着 configure 参数 --with-libxml 编译的。


[编辑] 生成 XML 内容

有一堆函数可以用于从 SQL 数据中生成 XML 内容。因此,它们很适合用于把查询结果格式化为 XML 文档给客户端应用处理。

[编辑] xmlcomment
  xmlcomment(text)

函数 xmlcomment 创建一个包含 XML 注释的 XML 数值,用声明的文本当做内容。文本不能博瀚 -- 或者用一个 - 结尾,这样生成的构造才是合法的 XML 注释。如果参数是空,那么结果是空。

例子:


SELECT xmlcomment('hello');

  xmlcomment
--------------
 <!--hello-->
[编辑] xmlconcat
xmlconcat(xml[, ...])

函数 xmlconcat 把一系列独立的 XML 数值连接在一起,创建一个包含 XML 内容片断的数值。空值将会被忽略;如果没有非空的参数,那么结果就只是空(NULL)。

例子:

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

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

如果出现了 XML 声明,那么会和后面的一起组合起来,如果所有参数值都是一样的 XML 版本声明,那么在结果中使用该版本,否则就不使用任何版本。如果所有参数值都有独立的声明值"yes",那么在结果中使用该值。如果所有参数都有独立的声明值并且之少有一个是"no",那么则使用这个。否则结果将不会有独立的声明。如果结果被判断为要求有独立的声明但是没有版本声明,那么将使用一个版本 1.0 的声明,因为 XML 声明要求包含一个版本声明。编码声明将会被忽略,并且在所有情况下都会被移除。

例子:

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

             xmlconcat
-----------------------------------
 <?xml version="1.1"?><foo/><bar/>
[编辑] 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 是该字符的 Unicode codepoint 之十六进制表现形式。比如:

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 或者 hex 编码的方式表现,具体形式取决于配置参数 xmlbinary 的设置。独立数据类型的特定行为将随着 SQL 和 PostgreSQL 数据类型以及 XML 模式规范的进化而变化,到时候会出现更精确的描述。

[编辑] 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>
 ...

如第二个例子里看到的,如果内容数值是一个字段引用,那么元素名称可以省略,这个时候字段名会被用做缺省。否则,必须声明名称。

非法的元素名会按照上面 xmlelement 那样逃逸。类似的还有,内容数据会逃逸成合法的 XML 内容,除非它已经是 xml 类型。

请注意,如果XML 森林包含超过一个元素,那么它就不是有效的 XML 文档。所以可能吧 xmlforest 表达式裹在一个 xmlelement 里头可能也很有用。

[编辑] xmlpi
xmlpi(name target [, content])

xmlpi 表达式创建一个 XML 处理指令。这个内容,如果出现的话,必须是不包含字符序列 ?> 的。

例子:

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

            xmlpi
-----------------------------
 <?php echo "hello world";?>
[编辑] xmlroot
xmlroot(xml, version text|no value [, standalone yes|no|no value])

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>
[编辑] XML 谓词
 xml IS DOCUMENT

如果参数 XML 的值是合法的 XML 文档,那么表达式 IS DOCUMENT 返回真,如果不是就返回假(也就是说,它是一个文档片断),如果参数是空则返回空。参阅8.13节获取有关文档和文档片断之间的区别的信息。

[编辑] 处理 XML

要处理数据类型为 xml 的数值,PostgreSQL 提供了函数 xpath,它计算 XPath 1.0 表达式。

  xpath(xpath, xml[, nsarray])

函数 xpath 针对 XML 数值 xml 计算 XPath 比阿大是 xpath。它返回一个XPath 表达式生成的 XML 值的数组。

函数第三个参数是一个名字空间映射的数组。这个数组应该是一个两维的数组,第二维度的长度应该等于 2(也就是说,它应该是一个数组的数组,每个数组包括两个元素)。每个数组的第一个元素是名字空间的名称,第二个是名字空间的 URI。

例子:

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)

[编辑] 把表映射为 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 把给定名称的表的的内容映射为 xml,表名称通过参数 tbl 传递。regclass 类型接受使用通常的表示法表示的表名称字串,包括可选的模式修饰和双引号。query_to_xml 执行指定的查询,这个查询是以参数 query 传递进来的,然后把结果集转换成xml。cursor_to_xml 从参数 cursor 执行的游标中抓取指定数目的行,然后转换成 xml。如果需要映射很大的表,我们推荐使用这个变种,因为每个函数的结果值都是在内存里制作的。

如果 tableforest 为假(false),那么生成的 XML 文档看起来像这样:


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

  <row>
    ...
  </row>

  ...
</tablename>

如果 tableforest 为真(true),那么结果是一个 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)

另外,还有下面的函数可以用于模拟把整个模式或者整个数据库都映射为 XML 数据。

  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>

这里的模式映射和上面说的一样了。

举一个例子,演示使用上面的程序的输出,图 9-1 显示了一个 XSLT 样式表,它把 talbe_to_xml_and_xmlschema 的输出的表数据转换成一个包含表格展现方式的 HTML 文档。用类似的方法,这些函数的结果可以转换成其他 XML 为基础的格式。

图 9-1. 把 SQL/XML 输出转换成 HTML 的 XSLT stylesheet(风格表)

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