declare @myXPath xml
set @myXpath=
'
<vehicles>
<car vin="123" make="Ford" model="Mustang">
<repair>
<id>3</id>
<description>Replace supercharger.</description>
<cost>4000.34</cost>
</repair>
<repair>
<id>45</id>
<description>repair top.</description>
<cost>45.67</cost>
</repair>
</car>
<car vin="234" make="Mozda" model="Miata">
<repair>
<id>7</id>
<description>Repair top.</description>
<cost>123.45</cost>
</repair>
<repair>
<id>22</id>
<description>Oil change.</description>
<cost>29.99</cost>
</repair>
</car>
<truck vin="567" make="Nissan" mode="Pathfinder">
<repair>
<id>2</id>
<description>Replace air filter.</description>
<cost>34.5</cost>
</repair>
<repair>
<id>6</id>
<description>Oil change.</description>
<cost>39.99</cost>
</repair>
</truck>
</vehicles>
'
下面介绍如何访问xml数据
一、XML数据的查询
1.XPATH的query方法
例如,可以在查询中使用//car来搜索XML树种所有包含car元素的节点。//表示派生或者自身,如果查询表达式起始于//则表示查询文档的当前节点及其派生节点。因此//car
表示在xml文档中查找包含car元素的当前节点及其派生节点。xquery还支持轴(axis)。
XQuery所支持的轴
轴 | 缩写形式 |
Attribute | @ |
Child | NA |
descendant-or-self::node() | // |
parent::node() | .. |
self:node() | . |
还可以在查询语句中使用[expression]语法以包含过滤器表达式。注意,过滤器表达式中引用的任何节点都是相对于当前在进行求值得节点。在访问xml属性时,属性名必须包含@前缀。
select @myxpath.query('//car[@vin="234"]')
该查询使用一个XPath表达式来定位文档中所以vin属性值234的car元素并返回包含该元素的xml节点。
如果要查询所返回的结果包含car和truck元素,可以指定当前节点(表示一个圆点)替换单词car。下面的查询将返回vin属性为567的元素,在本例中返回一个truck元素。但是如果car中也有一个567的元素,将会返回car和truck两个元素。
Sql:
select @myxpath.query('//.[@vin="567"]')
2.在过滤器中使用sql变量
可以使用sql变量代替一个常量以获取car 或者truck元素。要想处理存储过程中的参数,就可以使用这种方法。
Sql:
declare @findvar nvarchar(20)
set @findvar='567'
select @myXpath.query('//.[@vin=sql:variable("@findvar")]')
(返回结果与select @myxpath.query('//.[@vin="567"]')
是一样的。)
该返回类型是xml,如果想以字符串形式返回car元素的make属性值就必须使用value方法,如下面的sql语句
declare @findvar nvarchar(20)
set @findvar='567'
select @myxpath.query('//.[@vin=sql:variable("@findvar")]').value('(//@make)[1]','nvarchar(max)')
本语句返回的结果:Nissan
注意:value方法要求查询表达式只能有一个返回值,因此即使知道查询表达式@make只会返回一个值也要使用圆括号将表达式括起来,并在后面用[1表示只使用第一个查询结果。
如果@findvar='567'在car和truck中都有一个567的,结果将只显示car中的节点而truck的节点将不会显示。
可以使用Text方法来执行基于文本的节点查询。该方法返回节点的文本。如果节点包含子节点,则会一并显示子节点的文本,但不会返回子节点的元素标记。下面代码返回repair的ID等于7的car或者truck元素。
注意:该查询将完整地返回repair下的id元素为7的car元素及其所有的repair字元素。
如果只想获取id等于7的rapir元素可以按照下面的进行查询
select @myxpath.query('//repair[id/text()="7"]')
显示结果,只包含repair元素,如下
<repair>
<id>7</id>
<description>Repair top.</description>
<cost>123.45</cost>
</repair>
过滤器可以使用..指定父节点来查询父节点的信息。例如要想获取id为7的repair元素的description父元素,可以使用下面的代码
select @myxpath.query('//repair/description[../id/text()="7"]')
返回结果:
<description>Repair top.</description>
该查询定位所有包含id元素且id值为7的description父元素,不管car元素还是truck元素下面的,都将显示。
二、执行常见的操作
1.执行常见的比较操作
XPath提供多个可以用于比较原子值、序列或原子值序列的比较操作符。常见的有=、!=、<、>、<=、>=。只要参与比较的两个操作数满足操作符的逻辑关系,就返回true。
下面的示例将返回id节点大于或等于40的所有repair元素
select @myxpath.query('//repair[id>=45]')
返回的结果
<repair>
<id>45</id>
<description>repair top.</description>
<cost>45.67</cost>
</repair>
注意:在处理数值型的数据时一定不要使用引号。
select @myxpath.query('//repair[id>=” 45” ]')
将与上面的查询完全不一样,这时查询中如果id值为6,7..都是满足条件的。因为此时进行的字符串操作而不是数值操作,6,7都大于40的第一个字符4,因此也是满足条件的。
2.执行值比较操作
可以使用比较操作符来比较原子值(atomic values)。Sql server2005支持下列的比较操作符:eq、ne、lt、gt、le和ge。在确实需要输入一个原子值以进行比较操作时就可以值比较操作符。这样可以保证使用正确的类型进行比较操作。
select @myxpath.query('//repair[xs:decimal(cost[1]) ge 40]')
查询结果
<repair>
<id>3</id>
<description>Replace supercharger.</description>
<cost>4000.34</cost>
</repair>
<repair>
<id>45</id>
<description>repair top.</description>
<cost>45.67</cost>
</repair>
<repair>
<id>7</id>
<description>Repair top.</description>
<cost>123.45</cost>
</repair>
注意:在使用该值比较操作符时需要显示的将cost转化为xs:decimal并且由于cost必须是一个原子值,因此要用[1]来获取第一个cost结果。
3.节点比较操作符
用于确定两个节点是否是同一个节点,下面测试两个car的节点,以判断它们是否是同一个节点。
Sql语句:
select @myxpath.query('
if((/vehicles/*[@vin="123"])[1] is (/vehicles/*[@make="Ford"])[1])
then
<result>These nodes are actually the same node.</result>
else
<result>These nodes are diffenrent nodes.</result>
')
该示例首先使用两个包含星号的xpath查询表达式获取vehicle节点的所有节点。第一个表达式通过查找匹配的vin属性来过滤子节点。第二个表达式通过查找匹配的make属性来过滤子节点。
然后该示例测试这两个查询表达式所返回的节点是否在同一个节点。
返回结果:
<result>These nodes are actually the same node.</result>
4.使用节点次序比较操作
节点次序比较操作符用于比较xml数据中的2个节点,以确定哪个节点是第一个节点。>>表示“位于后面”,<<操作符表示“位于前面”。这两个操作符都使用2个操作数。下面代码使用>>判断id为7的repair节点是否位于id为2的repair节点后面。
代码:
select @myxpath.query('
if((/vehicles/*/repair[./id="7"])[1]>>(/vehicles/*/repair[./id="2"])[1])
then
<result>repait 7 is after repair 2.</result>
else
<result>repait 7 is before repair 2.</result>
')
返回结果:<result>repait 7 is before repair 2.</result>
注意:前面的代码中的2个参数将执行一个XPath查询,以获取一个节点集,并返回第一个查询结果。
5.使用逻辑操作符
可以在查询中使用and 或者or逻辑操作符以组合多个逻辑表达式。下面代码显示vin为567或者234的car或者truck节点。
代码:
select @myxpath.query('/vehicles/*[@vin="567" or @vin="234"]')
显示结果:
<car vin="123" make="Ford" model="Mustang">
<repair>
<id>3</id>
<description>Replace supercharger.</description>
<cost>4000.34</cost>
</repair>
<repair>
<id>45</id>
<description>repair top.</description>
<cost>45.67</cost>
</repair>
</car>
<car vin="234" make="Mozda" model="Miata">
<repair>
<id>7</id>
<description>Repair top.</description>
<cost>123.45</cost>
</repair>
<repair>
<id>22</id>
<description>Oil change.</description>
<cost>29.99</cost>
</repair>
</car>
注意:该查询将找到2个相匹配的vehicles子节点,并且返回一个car节点和一个truck节点,因为逻辑表达式使用*(星号) 来选择vehicles节点的所有子节点。
(未完待续)