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 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 之间;后者是更早的语言,在许多方面都不同。
需要记住两类限制:一是 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 序列(sequence)不同,XPath 1.0 的节点集没有保证顺序, 并且像任何集合一样,不允许同一条目出现多次。
libxml2库看起来总是把节点集以其成员在输入文档中的相对顺序 返回给PostgreSQL。但它的文档并未承诺这种行为, 而 XPath 1.0 表达式本身也无法控制这一点。
虽然 XQuery/XPath 提供了 XML Schema 中定义的全部类型,以及围绕这些类型的大量操作符和函数, 但 XPath 1.0 只有节点集以及三种原子类型:boolean、double和string。
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 = 7和sale/@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 完全等同。
在 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中的函数)来生成标准规定的映射。
本节讨论的限制并非libxml2库本身固有, 而是适用于PostgreSQL当前实现的限制。
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 VALUE或 BY REF出现在XMLEXISTS或 XMLTABLE结构中的用法, 但会忽略它们。xml数据类型保存的是序列化后的字符串表示, 因而没有需要保留的节点身份,所以传递在实际上始终等同于BY VALUE。
基于 XPath 的函数支持传递一个参数作为 XPath 表达式的上下文项, 但不支持传递额外的值,供表达式作为命名参数使用。
XML(SEQUENCE) 类型 #PostgreSQL的xml数据类型只能保存 DOCUMENT或CONTENT形式的值。 一个 XQuery/XPath 表达式的上下文项必须是单个 XML 节点或原子值, 但 XPath 1.0 又进一步限制它只能是 XML 节点,并且没有允许CONTENT的节点类型。 归根结底,格式良好的DOCUMENT是 PostgreSQL能够作为 XPath 上下文项提供的唯一 XML 值形式。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。