Skip to content

D.3. XML 限制和符合 SQL/XML#

D.3.1. 查询仅限于 XPath 1.0
D.3.2. 实现的偶然限制

ISO/IEC 9075-14 (SQL/XML) 中与 XML 相关的规范进行了重大修订,并引入了 SQL:2006。PostgreSQL对 XML 数据类型和相关函数的实现主要遵循较早的 2003 年版本,并借鉴了较新版本的一些内容。特别是

  • 在当前标准提供了一系列 XML 数据类型来保存非类型或 XML 模式类型变体中的“文档”或“内容”,以及类型 XML(SEQUENCE) 来保存任意 XML 内容片段的情况下,PostgreSQL 提供了单个 xml 类型,它可以保存“文档”或“内容”。没有与标准的“序列”类型等效的内容。

  • PostgreSQL 提供了 SQL:2006 中引入的两个函数,但使用 XPath 1.0 语言的变体,而不是标准中为它们指定的 XML 查询。

本节介绍你可能遇到的部分由此产生的差异。

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 的功能包括

  • 除了所有可能的 XPath 值之外,XQuery 表达式还可以构造和返回新的 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 序列不同,XPath 1.0 节点集没有保证的顺序,并且与任何集合一样,不允许同一项出现多次。

    注意

    libxml2 库似乎始终以输入文档中相对相同的顺序将节点集返回到 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 的数字比较。相比之下,=!= 将字符串作为字符串进行比较。

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

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

此处突出显示的差异并非全部。在 XQuery 和 2.0 及更高版本的 XPath 中,存在 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 数据类型的文本输入形式有效,反之亦然。此规则具有简单性的优点,同时对于许多数据类型,它产生的结果与标准中指定的映射类似。

如果与其他系统之间的互操作性是一个问题,对于某些数据类型,可能需要明确使用数据类型格式化函数(例如第 9.8 节中的函数)来生成标准映射。

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

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

D.3.2.1. 仅支持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 VALUEBY REF,但会忽略它们。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的节点类型。结果是,格式良好的DOCUMENT是PostgreSQL可以作为 XPath 上下文项提供的唯一形式的 XML 值。