XPath 数据类型 (SQLXML 4.0)

适用于:SQL ServerAzure SQL 数据库

Microsoft SQL Server、XPath 和 XML 架构 (XSD) 具有非常不同的数据类型。 例如,XPath 没有整数或日期数据类型,但SQL Server和 XSD 有许多数据类型。 XSD 对时间值使用纳秒精度,SQL Server最多使用 1/300 秒精度。 因此,将一种数据类型映射到另一种数据类型并不是始终可行的。 有关将SQL Server数据类型映射到 XSD 数据类型的详细信息,请参阅数据类型强制和 sql:数据类型注释 (SQLXML 4.0)

XPath 有三种数据类型: 字符串数字布尔值数字数据类型始终为 IEEE 754 双精度浮点。 SQL Server float (53) 数据类型最接近 XPath 编号。 但是, float (53) 并不完全是 IEEE 754。 例如,NaN(非数字)和 infinity 均未使用。 尝试将非数值字符串转换为 数字 并尝试除以零会导致错误。

XPath 转换

在您使用 OrderDetail[@UnitPrice > "10.0"] 之类的 XPath 查询时,隐式和显式数据类型转换可能会对查询的意义产生细微的变化。 因此,理解 XPath 数据类型的实现方式十分重要。 XPath 语言规范 XML 路径语言 (XPath) 版本 1.0 W3C 建议 1999 年 10 月 8 日,可在 W3C 网站上 http://www.w3.org/TR/1999/PR-xpath-19991008.html找到。

XPath 运算符分为四个类别:

  • 布尔运算符(and、or)

  • 关系运算符 (<、 >、 <=、 >=)

  • 相等运算符(=、!=)

  • 算术运算符(+、-、*、div、mod)

每个运算符类别都以不同方式转换其操作数。 XPath 运算符根据需要隐式转换其操作数。 算术运算符将其操作数转换为 数字,并生成数字值。 布尔运算符将其操作数转换为 布尔值,并生成布尔值。 关系运算符和相等运算符产生布尔值。 但是,根据其操作数的原始数据类型,这两种运算符具有不同的转换规则,如下表所示。

操作数 关系运算符 相等运算符
这两种操作数均为节点集。 如果且仅当一个集中有一个节点,第二个集中有一个节点,以便其 字符串 值的比较为 TRUE 时,才为 TRUE。 相同。
一个是节点集,另一个是 字符串 如果且仅当节点集中有一个节点时,该节点与转换为数字字符串比较为 TRUE,则为 TRUE。 如果且仅当节点集中有一个节点时,该节点与字符串的比较为 TRUE,则为 TRUE。
一个是节点集,另一个是 数字 如果且仅当节点集中有一个节点时,它与数字的比较为 TRUE,则为 TRUE。 相同。
一个是节点集,另一个是 布尔值 如果且仅当节点集中有一个节点时,当转换为布尔值,然后转换为 number 时,该节点与转换为数字布尔值比较为 TRUE,则为 TRUE。 如果且仅当节点集中有一个节点时,当转换为 布尔值时,该节点与 布尔 值的比较为 TRUE,则为 TRUE。
两者均不是节点集。 将这两个操作数转换为 数字 ,然后比较。 将两个操作数均转换为常见类型,然后进行比较。 如果任一为 布尔值 ,则转换为 布尔值;如果其中一个为 number ,则转换为 number;否则,请转换为 字符串

注意

由于 XPath 关系运算符始终将其操作数转换为 数字,因此无法进行 字符串 比较。 为了包含日期比较,SQL Server 2000 提供了 XPath 规范的此变体:当关系运算符将字符串字符串、节点集与字符串或字符串值 node-set 进行比较时,将执行字符串比较 (而不是数字比较) 。

节点集转换

节点集转换并非始终都是直观的。 节点集通过仅获取 集中 第一个节点的字符串值来转换为字符串。 通过将节点集转换为字符串,然后将字符串转换为数字,将节点集转换为数字。 通过测试节点集是否存在,将节点集转换为 布尔值

注意

SQL Server不对节点集执行位置选择:例如,XPath 查询Customer[3]表示第三个客户;SQL Server不支持这种类型的位置选择。 因此,不会实现 XPath 规范所述的 node-set-to-string 或 node-set-to-number 转换。 无论 XPath 规范指定“first”语义,SQL Server都使用“any”语义。 例如,根据 W3C XPath 规范,XPath 查询Order[OrderDetail/@UnitPrice > 10.0]选择具有 UnitPrice 大于 10.0 的第一个 OrderDetail 的订单。 在SQL Server,此 XPath 查询选择具有 UnitPrice 大于 10.0 的任何 OrderDetail 的订单。

转换为 布尔值 会生成存在测试;因此,XPath 查询 Products[@Discontinued=true()] 等效于 SQL 表达式“Products.Discontinued 不是 null”,而不是 SQL 表达式“Products.Discontinued = 1”。 若要使查询等效于后一个 SQL 表达式,请先将 node-set 转换为非布尔 类型,例如 number。 例如 Products[number(@Discontinued) = true()]

因为如果运算符对于节点集中任一节点为 TRUE,则大多数运算符均定义为 TRUE;所以,在节点集为空时,这些运算的计算结果始终为 FALSE。 因此,如果 A 为空,则 A = BA != B 均为 FALSE,并且 not(A=B)not(A!=B) 均为 TRUE。

通常,如果数据库中该列的值不 为 null,则存在映射到列的属性或元素。 如果元素的任何子集存在,则映射到行的元素将存在。

注意

使用 is-constant 批注的元素始终存在。 因此,XPath 谓词不能用于 is-constant 元素。

当节点集转换为 字符串数字时,如果批注架构中检查了任何) ,则其 XDR 类型 (,并且该类型用于确定所需的转换。

将 XDR 数据类型映射到 XPath 数据类型

节点的 XPath 数据类型派生自架构中的 XDR 数据类型,如下表所示, (节点 EmployeeID 用于说明目的) 。

XDR 数据类型 等效

XPath 数据类型
使用的 SQL Server 转换
Nonebin.base64bin.hex 空值 NoneEmployeeID
boolean boolean CONVERT(bit, EmployeeID)
number、int、float、i1、i2、i4、i8、r4、r8、ui1、ui2、ui4、ui8 数字 CONVERT(float(53), EmployeeID)
id、idref、idrefsentity、entities、enumerationnotation、nmtoken、nmtokens、chardate、Timedate、Time.tz、string、uri、uuid string CONVERT(nvarchar(4000), EmployeeID, 126)
fixed14.4 无(在 XPath 中没有等效于 fixed14.4 XDR 数据类型的数据类型) CONVERT(money, EmployeeID)
date string LEFT(CONVERT(nvarchar(4000), EmployeeID, 126), 10)
time

time.tz
string SUBSTRING(CONVERT(nvarchar(4000), EmployeeID, 126), 1 + CHARINDEX(N'T', CONVERT(nvarchar(4000), EmployeeID, 126)), 24)

无论值是使用 SQL Server datetime 数据类型还是字符串存储在数据库中,日期和时间转换都适合工作。 请注意,SQL Server datetime 数据类型不使用时区,其精度小于 XML 时间数据类型。 若要包含时区数据类型或其他精度,请使用字符串类型将数据存储在SQL Server中。

在某一节点从其 XDR 数据类型转换为 XPath 数据类型时,有时候可能需要执行附加的转换(从一个 XPath 数据类型转换为另一个 XPath 数据类型)。 例如,请考虑下面的 XPath 查询:

(@m + 3) = 4  

如果 @m 为 fixed14.4 XDR 数据类型,则使用以下命令完成从 XDR 数据类型到 XPath 数据类型的转换:

CONVERT(money, m)  

在此转换中,节点 mfixed14.4 转换为 money。 但如果添加值 3,则要求附加的转换:

CONVERT(float(CONVERT(money, m))  

该 XPath 表达式计算为:

CONVERT(float(CONVERT(money, m)) + CONVERT(float(53), 3) = CONVERT(float(53), 3)  

如下表中所示,这一转换同样适用于其他 XPath 表达式(例如文字表达式或复合表达式)。

X 未知 X 为字符串 X 是数字 X 为布尔值
string(X) CONVERT (nvarchar(4000), X, 126) - CONVERT (nvarchar(4000), X, 126) CASE WHEN X THEN N'true' ELSE N'false' END
number(X) CONVERT (float(53), X) CONVERT (float(53), X) - CASE WHEN X THEN 1 ELSE 0 END
boolean(X) - LEN (X) > 0 X != 0 -

示例

A. 在 XPath 查询中转换数据类型

在针对带批注的 XSD 架构指定的以下 XPath 查询中,该查询选择 EmployeeID 属性值为 E-1 的所有 Employee 节点,其中“E-”是使用 sql:id-prefix 注释指定的前缀。

Employee[@EmployeeID="E-1"]

该查询中的谓词等效于 SQL 表达式:

N'E-' + CONVERT(nvarchar(4000), Employees.EmployeeID, 126) = N'E-1'

由于 EmployeeID是 (idref、idrefsnmtokensnmtokens 等 id) XSD 架构中的数据类型值之一,因此 EmployeeID 将使用前面所述的转换规则转换为字符串 XPath 数据类型。

CONVERT(nvarchar(4000), Employees.EmployeeID, 126)

“E-”前缀将添加到字符串,然后结果将与 N'E-1' 进行比较。

B. 在 XPath 查询中执行若干数据类型转换

考虑以下根据带批注的 XSD 架构指定的 XPath 查询:OrderDetail[@UnitPrice * @OrderQty > 98]

此 XPath 查询返回满足谓词 @UnitPrice * @OrderQty > 98的所有 <OrderDetail> 元素。 如果在批注架构中使用 fixed14.4 数据类型对 UnitPrice 进行批注,则此谓词等效于 SQL 表达式:

CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice)) * CONVERT(float(53), OrderDetail.OrderQty) > CONVERT(float(53), 98)

在 XPath 查询中转换值时,第一个转换将 XDR 数据类型转换为 XPath 数据类型。 由于 UnitPrice 的 XSD 数据类型是固定的 14.4,如上表所述,这是使用的第一个转换:

CONVERT(money, OrderDetail.UnitPrice))   

由于算术运算符将其操作数转换为 数字 XPath 数据类型,因此应用从一个 XPath 数据类型到另一个 XPath 数据类型的第二个转换 () ,其中值转换为 float (53) (float (53) 接近 XPath number 数据类型) :

CONVERT(float(53), CONVERT(money, OrderDetail.UnitPrice))   

假设 OrderQty 属性没有 XSD 数据类型, 则 OrderQty 在单个转换中转换为 数字 XPath 数据类型:

CONVERT(float(53), OrderDetail.OrderQty)  

同样,值 98 转换为 数字 XPath 数据类型:

CONVERT(float(53), 98)  

注意

如果架构中使用的 XSD 数据类型与数据库中的基础SQL Server数据类型不兼容,或者执行了不可能的 XPath 数据类型转换,SQL Server可能会返回错误。 例如,如果 EmployeeID 属性使用 id 前缀 批注进行批注,XPath Employee[@EmployeeID=1] 将生成错误,因为 EmployeeID 具有 ID 前缀 注释,无法转换为 数字