受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

D.3. XML 的限制以及对 SQL/XML 的符合性 #

SQL:2006 对 ISO/IEC 9075-14(SQL/XML)中的 XML 相关规范做了重大修订。 PostgreSQL对 XML 数据类型及相关函数的实现, 大体遵循较早的 2003 年版,同时也借鉴了后续版本的一些内容。特别是:

  • 当现行标准提供一组 XML 数据类型,用于以无类型或 XML Schema 类型化的变体保存 文档内容,并提供 XML(SEQUENCE) 类型来保存任意 XML 内容片段时,PostgreSQL只提供单一的 xml类型,该类型可以保存文档内容。 标准中的sequence类型在这里没有对应物。

  • PostgreSQL提供了 SQL:2006 引入的两个函数, 但其变体使用的是 XPath 1.0,而不是标准为其规定的 XML Query 语言。

  • PostgreSQL不支持 RETURNING CONTENTRETURNING SEQUENCE子句; 规范中被定义为带有这些子句的函数,在这里都隐式返回内容。

本节介绍由此产生的一些差异。

D.3.1. 查询受限于 XPath 1.0 #

PostgreSQL特有的函数 xpath()xpath_exists() 使用 XPath 语言查询 XML 文档。PostgreSQL 还提供了标准函数XMLEXISTSXMLTABLE的 仅限 XPath 版本,而这两个标准函数正式使用的是 XQuery 语言。 对于所有这些函数,PostgreSQL都依赖 libxml2库,而该库只提供 XPath 1.0。

XQuery 与 XPath 2.0 及更高版本之间有很强的关联:凡是在两者中语法有效且都能成功执行的表达式, 其结果都相同(一个小例外是包含数字字符引用或预定义实体引用的表达式, XQuery 会将其替换为相应字符,而 XPath 则保持不变)。 但这种关联并不适用于这些语言与 XPath 1.0 之间;后者是更早的语言,在许多方面都不同。

需要记住两类限制:一是 SQL 标准所规定函数从 XQuery 缩减到 XPath 的限制, 二是标准函数和PostgreSQL特有函数都只能使用 XPath 1.0 的限制。

D.3.1.1. 将 XQuery 限制为 XPath #

XQuery 具有而 XPath 不具备的特性包括:

  • XQuery 表达式除了能够产生 XPath 所有可能的值之外, 还可以构造并返回新的 XML 节点。XPath 可以创建并返回原子类型的值 (数字、字符串等),但它只能返回作为表达式输入提供的文档中本就存在的 XML 节点。

  • XQuery 提供了用于迭代、排序和分组的控制结构。

  • XQuery 允许声明和使用局部函数。

较新的 XPath 版本开始提供与这些能力部分重叠的功能 (例如函数式风格的for-eachsort、 匿名函数,以及用parse-xml从字符串创建节点), 但在 XPath 3.0 之前并不具备这些特性。

D.3.1.2. XPath 仅限于 1.0 #

对熟悉 XQuery 和 XPath 2.0 或更高版本的开发人员来说,XPath 1.0 存在若干必须面对的差异:

  • XQuery/XPath 表达式的基础类型 sequence 可以包含 XML 节点、原子值或两者兼有, 但 XPath 1.0 中不存在这一类型。1.0 表达式只能产生一个节点集 (包含零个或多个 XML 节点),或者一个单一的原子值。

  • 与可按任意顺序包含任意条目的 XQuery/XPath 序列(sequence)不同,XPath 1.0 的节点集没有保证顺序, 并且像任何集合一样,不允许同一条目出现多次。

    Note

    libxml2库看起来总是把节点集以其成员在输入文档中的相对顺序 返回给PostgreSQL。但它的文档并未承诺这种行为, 而 XPath 1.0 表达式本身也无法控制这一点。

  • 虽然 XQuery/XPath 提供了 XML Schema 中定义的全部类型,以及围绕这些类型的大量操作符和函数, 但 XPath 1.0 只有节点集以及三种原子类型:booleandoublestring

  • XPath 1.0 没有条件操作符。像 if ( hat ) then hat/@size else "no hat" 这样的 XQuery/XPath 表达式,在 XPath 1.0 中没有等价写法。

  • XPath 1.0 没有用于字符串的排序比较操作符。 "cat" < "dog""cat" > "dog" 都为假,因为它们实际上都是两个NaN之间的数值比较。 相比之下,=!=确实会把字符串按字符串来比较。

  • XPath 1.0 模糊了 XQuery/XPath 所定义的值比较一般比较之间的区别。 sale/@hatsize = 7sale/@customer = "alice" 都属于存在量词比较:只要存在任意一个sale具有给定属性值,结果就为真。 但sale/@taxable = false()则是将整个节点集的 有效布尔值进行值比较。只有在没有任何sale 拥有taxable属性时,它才为真。

  • 在 XQuery/XPath 数据模型中,文档节点既可以是文档形式 (即恰好有一个顶层元素,且其外部只允许注释和处理指令),也可以是内容形式 (放宽这些约束)。它在 XPath 1.0 中对应的根节点只能是文档形式。 这也是为什么xml值在作为上下文项传给任何基于 XPath 的 PostgreSQL函数时,必须采用文档形式的部分原因。

这里强调的差异并不全面。在 XQuery 以及 XPath 2.0 及更高版本中, 存在 XPath 1.0 兼容模式,而 W3C 给出的 函数库变化语言变化 列表,在该模式下提供了更完整但仍不穷尽的差异说明。 兼容模式也不能让较新的语言与 XPath 1.0 完全等同。

D.3.1.3. SQL 与 XML 数据类型和值之间的映射 #

在 SQL:2006 及之后的版本中,标准 SQL 数据类型与 XML Schema 类型之间双向转换的规则都被精确定义了。 但是,这些规则是用 XQuery/XPath 的类型和语义来表达的,无法直接应用到 XPath 1.0 那套不同的数据模型上。

PostgreSQL把 SQL 数据值映射到 XML (例如xmlelement),或者把 XML 映射到 SQL (例如xmltable的输出列)时,除少数被特殊处理的情况外, PostgreSQL只是简单地假定:XML 数据类型在 XPath 1.0 中的字符串形式 可以作为 SQL 数据类型的文本输入形式,反之亦然。 这一规则的优点在于简单,同时对许多数据类型来说,其结果也与标准规定的映射大致相似。

如果需要与其他系统互操作,那么对于某些数据类型,可能需要显式使用数据类型格式化函数 (例如Section 9.8中的函数)来生成标准规定的映射。

D.3.2. 实现带来的附带限制 #

本节讨论的限制并非libxml2库本身固有, 而是适用于PostgreSQL当前实现的限制。

D.3.2.1. 仅支持BY VALUE传递机制 #

SQL 标准定义了两种传递机制,适用于从 SQL 向 XML 函数传递 XML 参数, 或在接收结果时使用:BY REF表示某个特定 XML 值保留其节点身份, BY VALUE表示传递 XML 的内容,但不保留节点身份。 该机制既可以写在参数列表之前,作为所有参数的默认机制,也可以写在任一参数之后,以覆盖默认机制。

为了说明其中的区别,如果x是一个 XML 值, 那么在 SQL:2006 环境中,下面两个查询将分别产生 true 和 false:

SELECT XMLQUERY('$a is $b' PASSING BY REF x AS a, x AS b NULL ON EMPTY);
SELECT XMLQUERY('$a is $b' PASSING BY VALUE x AS a, x AS b NULL ON EMPTY);

PostgreSQL会接受BY VALUEBY REF出现在XMLEXISTSXMLTABLE结构中的用法, 但会忽略它们。xml数据类型保存的是序列化后的字符串表示, 因而没有需要保留的节点身份,所以传递在实际上始终等同于BY VALUE

D.3.2.2. 无法向查询传递命名参数 #

基于 XPath 的函数支持传递一个参数作为 XPath 表达式的上下文项, 但不支持传递额外的值,供表达式作为命名参数使用。

D.3.2.3. 没有 XML(SEQUENCE) 类型 #

PostgreSQLxml数据类型只能保存 DOCUMENTCONTENT形式的值。 一个 XQuery/XPath 表达式的上下文项必须是单个 XML 节点或原子值, 但 XPath 1.0 又进一步限制它只能是 XML 节点,并且没有允许CONTENT的节点类型。 归根结底,格式良好的DOCUMENTPostgreSQL能够作为 XPath 上下文项提供的唯一 XML 值形式。

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。