XML 函数

PostgreSQL 9.4.4 中文手册
上一页 | 上一级 | 章 9. 函数和操作符 | 下一页

# 9.14. XML 函数

在本节描述的函数和像函数的表达式操作都是基于`xml`类型的值。 查看第 8.13 节获取关于`xml`类型的信息。 像函数表达式的`xmlparse`和`xmlserialize` 用来转换为和从类型`xml`转换，不在这里重复。 使用这些函数需要安装与配置了`configure --with-libxml`。

## 9.14.1. 生成XML内容

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

### 9.14.1.1. `xmlcomment`

    xmlcomment(text)

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

例子：

    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版本声明，则在结果中使用版本。 否则不用版本。如果所有的参数值有独立的声明值"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.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元素和属性名的名称由序列`_x`HHHH`_` 替换有问题的字符转义，这里的`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`数据类型） 将用base64或16进制编码表示，取决于配置参数xmlbinary的设置。 单个数据类型的特定行为预计将发展为了使SQL和PostgreSQL数据类型和XML架构规范一致， 到时将出现更准确描述。

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

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

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

请注意，如果包含一个以上的元素，XML的森林不是有效的XML文档， 所以在`xmlelement`里面封装`xmlforest`表达式可能是有用的。

### 9.14.1.5. `xmlpi`

    xmlpi(name target [, content])

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

示例：

    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值的根节点属性。如果指定一个版本， 它替换根节点的版本声明值;如果指定一个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.20 节获取关于聚合函数的更多信息。

示例：

    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`子句到聚合调用， 描述在第 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.2. XML Predicates

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

### 9.14.2.1. `IS DOCUMENT`

    xml IS DOCUMENT

如果参数XML值是一个合法的XML文档，表达式`IS DOCUMENT`返回真。 否则返回假（例如，内容片段）或如果参数为空则返回空。请参阅第 8.13 节 获取关于文档和内容片段之间的不同。

### 9.14.2.2. `XMLEXISTS`

    XMLEXISTS(text PASSING [BY REF] xml [BY REF])

如果第一个参数中的XPath表达式返回任何节点，那么函数`xmlexists`返回真， 否则返回假。（如果其他参数是null，结果是null。）

示例：

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

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

在PostgreSQL中，`BY REF`子句没有影响， 但是为了与SQL的一致性和其他实现的兼容性是允许的。SQL标准中， 第一个`BY REF`是必须的，第二个`BY REF`是可选的。 也请注意，SQL标准声明`xmlexists`构造接受XQuery表达式作为第一个参数， 但是PostgreSQL目前只接受XQuery的一个子集XPath。

### 9.14.2.3. `xml_is_well_formed`

    xml_is_well_formed(text)
    xml_is_well_formed_document(text)
    xml_is_well_formed_content(text)

这些函数检查`text`字符串是不是格式良好的XML，返回布尔结果。 `xml_is_well_formed_document`检查格式良好的文档， `xml_is_well_formed_content`检查格式良好的内容。 `xml_is_well_formed`如果xmloption参数设置为 `DOCUMENT`则检查文档，如果设置为`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.14.3. 处理XML

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

    xpath(xpath, xml [, nsarray])

`xpath`函数，对XML值`xml` 计算XPath表达式`xpath`（`text`值）的结果。 它返回一个XML值的数组对应XPath表达式所产生的节点集。 如果XPath表达式返回一个标量值而不是节点集，那么返回一个单个元素的数组。

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

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

示例：

    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)

    xpath_exists(xpath, xml [, nsarray])

`xpath_exists`函数是`xpath`函数的一种特殊化形式。 这个函数返回一个布尔值表明是否满足这个查询，而不是返回满足XPath的单个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.14.4. 到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>

    ...

如果没有可用的表名，也就是当映射一个查询或游标时， 第一个格式用字符串`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>

模式映射如上所述。

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

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

上一页 | 起始页 | 下一页
文本检索函数和操作符 | 上一级 | JSON 函数和操作符