ISO/IEC 9075-14 (SQL/XML) 中与 XML 相关的规范在 SQL:2006 中引入了重大修订。PostgreSQL 对 XML 数据类型及相关函数的实现很大程度上遵循 2003 年的早期版本,并借鉴了一些后续版本的内容。特别是
虽然当前标准提供了一系列 XML 数据类型来存储“文档”或“内容”(包括未类型或 XML Schema 类型的变体),以及一个 XML(SEQUENCE)
类型来存储任意 XML 内容片段,但 PostgreSQL 只提供了一个 xml
类型,它可以存储“文档”或“内容”。标准中的“序列”类型在该类型中没有等效项。
PostgreSQL 提供了两个在 SQL:2006 中引入的函数,但它们使用 XPath 1.0 语言,而不是标准为它们指定的 XML 查询语言。
PostgreSQL 不支持 RETURNING CONTENT
或 RETURNING SEQUENCE
子句。在规范中定义了这些子句的函数,其行为将隐式返回内容。
本节将介绍您可能遇到的一些由此产生的差异。
PostgreSQL 特有的函数 xpath()
和 xpath_exists()
使用 XPath 语言查询 XML 文档。PostgreSQL 还提供了标准函数 XMLEXISTS
和 XMLTABLE
的仅限 XPath 的变体,这些函数官方使用 XQuery 语言。对于所有这些函数,PostgreSQL 都依赖于 libxml2 库,该库仅提供 XPath 1.0。
XQuery 语言与 XPath 2.0 及更高版本之间存在紧密的联系:在两个版本中语法正确且执行成功的任何表达式都会产生相同的结果(对于包含数字字符引用或预定义实体引用的表达式,XQuery 会将其替换为相应的字符,而 XPath 会保留它们,这是一个小的例外)。但这些语言与 XPath 1.0 之间没有这种联系;XPath 1.0 是一个较早的语言,在许多方面都存在差异。
需要注意两类限制:标准 SQL 中定义的函数从 XQuery 限制为 XPath,以及标准和 PostgreSQL 特有的函数都将 XPath 限制为 1.0 版本。
XQuery 超出 XPath 功能的特性包括:
XQuery 表达式除了 XPath 的所有可能值之外,还可以构造和返回新的 XML 节点。XPath 可以创建和返回原子类型(数字、字符串等)的值,但只能返回输入到表达式中的文档中已存在的 XML 节点。
XQuery 具有用于迭代、排序和分组的控制结构。
XQuery 允许声明和使用局部函数。
较新的 XPath 版本开始提供与这些功能重叠的能力(例如函数式 for-each
和 sort
、匿名函数以及用于从字符串创建节点的 parse-xml
),但这些功能在 XPath 3.0 之前不可用。
对于熟悉 XQuery 和 XPath 2.0 或更高版本的开发者来说,XPath 1.0 会带来一些需要应对的差异:
XQuery/XPath 表达式的基本类型 sequence
(可以包含 XML 节点、原子值或两者兼有)在 XPath 1.0 中不存在。1.0 表达式只能产生一个节点集(包含零个或多个 XML 节点),或者一个原子值。
与可以包含任意所需项且顺序任意的 XQuery/XPath 序列不同,XPath 1.0 节点集没有保证的顺序,并且像任何集合一样,不允许同一项多次出现。
libxml2 库似乎总是将节点集以其在输入文档中出现的相对顺序返回给 PostgreSQL。其文档并未承诺此行为,并且 XPath 1.0 表达式也无法控制它。
XQuery/XPath 提供了 XML Schema 中定义的所有类型以及许多针对这些类型的运算符和函数,而 XPath 1.0 仅具有节点集和三个原子类型:boolean
、double
和 string
。
XPath 1.0 没有条件运算符。XQuery/XPath 表达式如 if ( hat ) then hat/@size else "no hat"
在 XPath 1.0 中没有等效项。
XPath 1.0 没有字符串的顺序比较运算符。 "cat" < "dog"
和 "cat" > "dog"
都为 false,因为它们是对两个 NaN
的数值比较。相比之下,=
和 !=
会像字符串一样比较字符串。
XPath 1.0 模糊了 XQuery/XPath 定义的“值比较”和“一般比较”之间的区别。 sale/@hatsize = 7
和 sale/@customer = "alice"
都是存在量化的比较,如果存在任何 sale
具有给定的属性值,则为 true。但 sale/@taxable = false()
是对整个节点集的“有效布尔值”进行值比较。只有当不存在任何 sale
具有 taxable
属性时,它才为 true。
在 XQuery/XPath 数据模型中,“文档节点”可以具有文档形式(即,只有一个顶级元素,外部只有注释和处理指令)或内容形式(这些约束已放宽)。在 XPath 1.0 中,其等效项“根节点”只能是文档形式。这也是为什么传递给任何 PostgreSQL 基于 XPath 的函数作为上下文项的 xml
值必须是文档形式的原因之一。
这里强调的差异并非全部。在 XQuery 和 XPath 2.0 及更高版本中,存在一个 XPath 1.0 兼容模式,W3C 的 函数库更改 和 在该模式下应用的语言更改 列表更全面地(但仍不详尽)地说明了这些差异。兼容模式不能使后期语言与 XPath 1.0 完全等同。
在 SQL:2006 及更高版本中,标准 SQL 数据类型与 XML Schema 类型之间的双向转换都得到了精确的指定。但是,这些规则是使用 XQuery/XPath 的类型和语义来表达的,并且与 XPath 1.0 的不同数据模型没有直接应用。
当 PostgreSQL 将 SQL 数据值映射到 XML(如 xmlelement
)或将 XML 映射到 SQL(如 xmltable
的输出列)时,除了少数特殊处理的情况外,PostgreSQL 仅假设 XML 数据类型的 XPath 1.0 字符串形式将作为 SQL 数据类型的文本输入形式有效,反之亦然。此规则的优点在于简单性,同时为许多数据类型产生与标准中指定的映射类似的结果。
如果需要与其他系统进行互操作,对于某些数据类型,可能需要显式使用数据类型格式化函数(例如 第 9.8 节 中的函数)来生成标准映射。
本节涉及的限制并非 libxml2 库固有的,而是适用于 PostgreSQL 当前实现的限制。
BY VALUE
传递机制 #SQL 标准定义了两个“传递机制”,它们适用于将 XML 参数从 SQL 传递到 XML 函数或接收结果:BY REF
,在这种机制下,特定的 XML 值保留其节点身份;以及 BY VALUE
,在这种机制下,传递 XML 的内容,但节点身份不保留。可以在参数列表之前指定一个机制,作为所有参数的默认机制,或在任何参数之后指定,以覆盖默认值。
为了说明区别,如果在 SQL:2006 环境中,x
是一个 XML 值,那么以下两个查询将分别产生 true 和 false:
SELECT XMLQUERY('$a is $b' PASSING BY REFx
AS a,x
AS b NULL ON EMPTY); SELECT XMLQUERY('$a is $b' PASSING BY VALUEx
AS a,x
AS b NULL ON EMPTY);
PostgreSQL 会接受 XMLEXISTS
或 XMLTABLE
构造中的 BY VALUE
或 BY REF
,但会忽略它们。xml
数据类型存储的是字符串序列化表示,因此没有需要保留的节点身份,传递总是有效地 BY VALUE
。
基于 XPath 的函数支持传递一个参数作为 XPath 表达式的上下文项,但不支持传递额外的命名参数供表达式使用。
XML(SEQUENCE)
类型 #PostgreSQL 的 xml
数据类型只能存储 DOCUMENT
或 CONTENT
形式的值。XQuery/XPath 表达式的上下文项必须是单个 XML 节点或原子值,但 XPath 1.0 进一步将其限制为仅限 XML 节点,并且没有允许 CONTENT
的节点类型。结果是,一个格式正确的 DOCUMENT
是 PostgreSQL 可以作为 XPath 上下文项提供的唯一形式的 XML 值。
如果您在文档中发现任何不正确、与您的实际使用经验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。