ISO/IEC 9075-14中与XML相关的规范进行了重大修订 (SQL/XML)与SQL:2006一起被引入. PostgreSQL's 的XML数据类型和相关函数的实现基本上沿用了2003年的早期版本。有一些借鉴了后来的版本。 特别是:
现行标准提供了一系列可扩展标记语言数据类型,其中将“文档”或“内容”保存在非类型或XML Schema类型的变体,以及类型XML(SEQUENCE)
用于保存任意的XML内容片段。
PostgreSQL提供了一个单一的xml
类型,可以容纳“文档”或“内容”。 没有相应的标准的“序列”类型。
PostgreSQL提供了两个函数在SQL:2006中引入的,但是在变体中,使用的是XPath 1.0语言,而不是在标准中为其指定的XML查询。
本节介绍了一些你可能会遇到的差异。
PostgreSQL-指定的函数
xpath()
和 xpath_exists()
使用XPath语言查询XML文档。
PostgreSQL也提供了标准函数中的XPath-only变体XMLEXISTS
和
XMLTABLE
, 其中正式采用XQuery语言。所有这些函数
PostgreSQL都依赖于libxml2 库,而这个库仅在XPath 1.0中提供。
在XQuery语言和XPath 2.0及以后的版本之间有很强的联系:任何语法上有效的表达式,在这两个版本中都能成功地执行,都会产生相同的结果(对于包含数字字符引用或预定义的实体引用的表达式会略有不同, XQuery会用相应的字符替换,而 XPath则不会。) 但这些语言和XPath 1.0之间没有这种联系,它是一种较早的语言,在很多方面都有区别。
有两类限制需要记住:一是对SQL标准中指定的函数从XQuery到XPath的限制,二是对标准和PostgreSQL特定函数XPath的限制是1.0版本 。
除了XPath的特性之外,XQuery的特性还包括:
除了所有可能的XPath值之外,XQuery表达式还可以构造和返回新的XML节点。 XPath 可以创建和返回原子类型(数字、字符串等)的值,但只能返回作为表达式输入的文档中已经存在的XML节点。
XQuery有用于迭代、排序和分组的控制结构。
XQuery允许声明和使用局部函数。
最近的 XPath 版本开始提供与这些功能重叠的功能(例如函数式的 for-each
和sort
,匿名函数,以及 parse-xml
从字符串中创建节点的parse-xml
),但这些功能在 XPath 3.0 之前是不具备的。
对于熟悉XQuery和XPath 2.0或更高版本的开发人员来说,XPath 1.0带来了许多不同的地方,需要解决的是:
一个XQuery/XPath表达式的基本类型,即 sequence
,它可以包含XML节点、原子值或两者,在XPath 1.0中不存在。一个1.0表达式只能产生一个节点集(包含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"
都是假的,因为每一个都是两个NaN
的数值比较。相比之下,=
和!!=
确实将字符串作为字符串进行比较。
XPath 1.0模糊了XQuery/XPath定义的值比较和一般比较之间的区别。 sale/@hatsize = 7
和sale/@customer = "alice"
都是存在的量化比较,如果有任何sale
属性的给定值,则为真。但sale/@taxable = false()
是与整个节点集的有效布尔值的值比较。只有当没有sale
有一个taxable
属性时,它才是真值。
在XQuery/XPath数据模型中,一个文档节点既可以有文档形式(即正好有一个顶层元素,只有注释和处理指令以外的注释和处理指令),也可以有内容形式(放宽了这些限制)。在XPath 1.0中,它的等价物是根节点,只能是文档形式。这也是xml
的值被作为 上下文项到任何 PostgreSQL的上下文项 基于XPath的函数必须是以文档形式出现。
这里强调的区别并不是全部。在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标准定义了两种传递机制,适用于从SQL向XML函数传递XML参数或接收结果时。BY REF
,其中一个特定的XML
值保留其节点身份,以及BY VALUE
,其中传递XML的内容,但不保留节点身份。可以在参数列表之前指定,作为所有参数的默认机制,也可以在任何参数之后指定,以覆盖默认机制。
为了说明区别,如果x
是一个XML值,那么在SQL:2006环境下的这两个查询将分别产生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值。