MSDN 查询词:XQuery 语言参考
一、 XQuery 基础知识
1、术语说明:
XSD:XML Schema 语言
原子类型:不可分割的类型,如 Schema 中内建的 string、integer 等
简单类型:原子类型、列表类型、联合类型合起来统称为简单类型,与复杂类型相对。
2、序列:由节点和原子值构成,序列中的项以逗号分隔。
空序列表示为 "()"
只包含一项的序列可视为原子值,如 (1) = 1,反之亦然。
在 SQL Server XQuery 的序列表达式中,序列必须是同类的,即或者是一个原子值序列,或者是一个节点序列,不能混搭。
3、命名空间声明:可以使用 WITH XMLNAMESPACES 声明,也可在 XML 数据类型相关的方法中使用 declare namespace 声明,若
两者声明的命名空间名称相同,后者会覆盖前者。如:
WITH XMLNAMESPACES ('http://someURI' as pd)
Select id, Catalog.query('declare namespace pd="http://otherURI";
/pd:root/pd:type') From Product Where id = 9
4、预定义的命名空间,在 MSDN "序列和 QName (XQuery)" 一节中列出。
5、在 SQL Server XQuery 中,不支持当前日期和时间上下文函数:fn:current-date、fn:current-timet 和 fn:current-
dateTime。
6、原子化:提取项的类型化值的过程。
某些 XQuery 运算符依赖于隐式原子化,如算术运算符和比较运算符,当运用这一类型的运算符时,会隐式调用数据函数 data()
,首先检索节点的类型化值,并转换为原子值。例:
declare @x xml
set @x = '<root><int org="1.4">1</int><int org="2.8">3</int></root>'
select @x.query('sum(//int/@org)') -- 返回:4.2
select @x.query('sum(//int)') -- 返回:4
注意最后一句,类型为简单类型的元素也可以隐式原子化
7、布尔值:如果操作数是空序列或布尔 false,返回 false,否则返回 true。
Declare @x xml
Set @x = '<root><a>true</a></root>'
Select @x.query('if(//a[1]) then "true" else "false"') --返回 "true"
但是
Select @x.query('if(data(//a[1])) then "true" else "false"')
会出现编译错误,因为 XQuery 中 if 只接受布尔值和节点集,而 data(//a[1]) 返回一个无类型的原子值(注意:不要以为该节
点下的文本为 "true",就会返回布尔值 true,但可以通过强制类型转换将其转换为布尔值,如 xs:Boolean(data((//a)[1])),
但是使用 xs:Boolean(data(//a[1])) 或 data(//a[1]) cast as xs:boolean? 则会导致转换错误),另一个解决的办法是定义一
个 Schema 与该 XML 文档关联,如
Create XML Schema Collection SC as '
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="root">
<complexType>
<sequence maxOccurs="unbounded">
<element name="a" type="Boolean" />
</sequence>
</complexType>
</element>
</schema>'
Go
declare @x xml(SC)
set @x = "<root><a>true</a></root>"
select @x.query('if(data((//a)[1])) then "true" else "false"')
注意:最后一句的判断条件 data((//a)[1]),有几点需要注意:
(1) 不可以省略为 (//a)[1],这将会变成一个节点选择,只要选择到相应的节点,返回值永远为 true。
(2) 不可以写为 data(//a[1]),//a[1] 其实会选择到一个节点集(如果多个元素包含 a 元素,会选择一系列的这些元素下的
第一个 a 元素)
(3) 也不可写为 data(/root/a[1]),原因同 (2),但可写为 data(/root[1]/a[1])。
最后还有一种很有趣的情形:
declare @x xml
set @x = ''
select @x.query('if(true) then "true" else "false"')
会返回什么?"true"?不对,是 "false",而且永远是 "false"。因为这里的 if 条件判断中,是把 true 当作一个元素选择来处
理的,即在 @x 中查找名称为 "true" 的元素,这肯定找不到,所以就永远返回 "false" 了。
那么改成 if("true") 行不行呢?不行,改成 if(1) 也不行。if 里的条件判断不会隐式转换类型,必须写成 if(xs:boolean
("true"))、if("true" cast as xs:boolean?) 或 if(true())。