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类型,该类型可以保留“文档”或“内容”。没有等同于标准的“序列”类型。

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

本节介绍您可能会遇到的一些差异。

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 及更高版本之间有很强的联系:任何在语法上有效并在两者中成功执行的表达式都会产生相同的结果(对于包含数字字符引用或 sched 义实体引用的表达式,只有一个小 exception),XQuery 会替换该表达式和相应的字符,而 XPath 则将其保留)。但是这些语言与 XPath 1.0 之间没有这种联系。它是一种较早的语言,在很多方面都有所不同。

要牢记两类限制:对于 SQL 标准中指定的功能,从 XQuery 到 XPath 的限制;对于标准功能和 PostgreSQL 特定的功能,从 XPath 到 1.0 版的限制。

D.3.1.1. XQuery 对 XPath 的限制

XQuery 超越 XPath 的功能包括:

  • 除了所有可能的 XPath 值之外,XQuery 表达式还可以构造和返回新的 XML 节点。 XPath 可以创建和返回原子类型的值(数字,字符串等),但是只能返回作为表达式 Importing 提供的文档中已经存在的 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在 XPath 1.0 中不存在,它可以包含 XML 节点和/或原子值。 1.0 表达式只能产生一个节点集(包含零个或多个 XML 节点)或单个原子值。

  • 与可以按任何所需 Sequences 包含任何所需项的 XQuery/XPath 序列不同,XPath 1.0 节点集没有保证的 Sequences,并且像任何一组一样,不允许同一项目出现多次。

Note

libxml2 库似乎总是将节点集及其成员以与 Importing 文档中相同的相对 Sequences 返回给 PostgreSQL。它的文档没有落实此行为,并且 XPath 1.0 表达式无法控制它。

  • 尽管 XQuery/XPath 提供了 XML Schema 中定义的所有类型以及这些类型上的许多运算符和函数,但 XPath 1.0 仅具有节点集以及三种原子类型booleandoublestring

  • XPath 1.0 没有条件运算符。 XQuery/XPath 表达式(例如if ( hat ) then hat/@size else "no hat")没有等效的 XPath 1.0.

  • XPath 1.0 没有用于字符串的排序比较运算符。 "cat" < "dog""cat" > "dog"均为假,因为它们都是两个NaN的数字比较。相反,=!=会将字符串作为字符串进行比较。

  • 当 XQuery/XPath 定义值比较和一般比较时,XPath 1.0 会模糊它们之间的区别。 sale/@hatsize = 7sale/@customer = "alice"都是存在的量化比较,如果存在具有给定属性值的sale,则为 true,但sale/@taxable = false()是与整个节点集的“有效布尔值”的值比较。仅当sale完全没有taxable属性时,才为 true。

  • 在 XQuery/XPath 数据模型中,文档节点既可以具有文档形式(即,仅是一个顶级元素,其外部仅包含 Comments 和处理指令),也可以具有内容形式(已放宽那些约束)。在 XPath 1.0 中,它的等效项* root node *只能是文档形式。这是作为上下文项传递给任何基于 PostgreSQL XPath 的函数的xml值必须采用文档形式的部分原因。

这里突出显示的差异并不是全部。在 XQuery 和 XPath 2.0 及更高版本中,存在 XPath 1.0 兼容模式,并且在该模式下应用的功能库变更language changes的 W3C 列表提供了更完整(但仍不是穷尽)的区别说明。兼容模式不能使更高版本的语言完全等同于 XPath 1.0.

D.3.1.3. SQL 和 XML 数据类型和值之间的 Map

在 SQL:2006 和更高版本中,精确指定了标准 SQL 数据类型和 XML Schema 类型之间的两个转换方向。但是,这些规则是使用 XQuery/XPath 的类型和语义表示的,并没有直接应用于 XPath 1.0 的不同数据模型。

当 PostgreSQL 将 SQL 数据值 Map 为 XML(如xmlelement)或 XMLMap 为 SQL(如xmltable的输出列)时,除特殊处理的少数情况外,PostgreSQL 只是假定 XML 数据类型的 XPath 1.0 字符串形式为相反,它作为 SQL 数据类型的文本 Importing 形式有效。对于许多数据类型,此规则具有简单性,同时可以生成类似于标准中指定的 Map 的结果。在此版本中,如果xmltable列表达式产生布尔值或双精度值,则需要显式转换。参见Section D.3.2

在考虑与其他系统的互操作性的情况下,对于某些数据类型,可能有必要显式使用数据类型格式化函数(例如Section 9.8中的那些)来生成标准 Map。

D.3.2. 实施的附带限制

本节涉及的不是 libxml2 库中固有的限制,而是适用于 PostgreSQL 中的当前实现。

D.3.2.1. 布尔或双精度类型的 xmltable 列所需的强制转换

评估 XPath 布尔值或数字结果的xmltable列表达式将产生“意外的 XPath 对象类型”错误。解决方法是将列表达式重写为 XPath string函数内部;然后,PostgreSQL 将成功将字符串值分配给 Boolean 或双精度型的 SQL 输出列。

D.3.2.2. 列路径结果或 XML 类型的 SQL 结果列

在此版本中,可以将评估为 XML 节点集的xmltable列表达式分配给 XML 类型的 SQL 结果列,从而产生以下内容的串联:对于该节点集中的大多数类型的节点,包含 XPath 的文本节点 1.0 节点的“字符串值”,但对于元素节点,为节点本身的副本。仅当该节点集具有单个节点且大多数节点类型的字符串值都替换为空字符串(元素的字符串值)时,才可以将该节点集分配给非 XML 类型的 SQL 列节点替换为仅由其直接文本节点子代(不包括后代子代)组成的串联,并且文本或属性节点的字符串值如 XPath 1.0 中所定义。分配给 XML 类型的结果列的 XPath 字符串值必须可解析为 XML。

最好不要开发依赖于这些行为的代码,这些行为与规范几乎没有相似,并且已在 PostgreSQL 12 中进行了更改。

D.3.2.3. 仅支持 BY VALUE 传递机制

SQL 标准定义了两种“传递机制” *,它们在将 XML 参数从 SQL 传递到 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 将在XMLEXISTSXMLTABLE构造中接受BY REF,但将忽略它。 xml数据类型包含字符串序列化的表示形式,因此没有要保留的节点标识,并且传递始终是BY VALUE

D.3.2.4. 无法将命名参数传递给查询

基于 XPath 的函数支持传递一个参数以用作 XPath 表达式的上下文项,但不支持传递附加值以作为命名参数可用于表达式。

D.3.2.5. 没有 XML(SEQUENCE)类型

PostgreSQL xml数据类型只能保存DOCUMENTCONTENT形式的值。 XQuery/XPath 表达式上下文项必须是单个 XML 节点或原子值,但是 XPath 1.0 进一步将其限制为仅 XML 节点,并且没有允许CONTENT的节点类型。结果是格式正确的DOCUMENT是 PostgreSQL 可以作为 XPath 上下文项提供的唯一 XML 值形式。