9.14. XML 函数
From PostgreSQL 中文维基, PostgreSQL 中文站, PostgreSQL 中国社区, PostgreSQL Chinese community
目录 |
[编辑] 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>
