nodes()方法(xml Data Type)

本主题适用于: SQL Server (starting with 2008) Azure SQL Database Azure SQL Data Warehouse  Parallel Data Warehouse

如果你想把一个xml数据类型实例分割到相关的数据中,则nodes()方法很有用。它允许你标识想要映射到新行中的节点。

每个xml数据类型实例具有一个潜在提供的上下文节点。对于存储在列或者变量中的XML实例,默认上下文节点是document节点。document节点是每个xml数据类型实例中的顶层。

nodes()方法的结果是一个行集,它包含了原始XML实例的逻辑副本。在这个逻辑副本中,每个行实例的上下文节点被设置为用查询表达式标识的节点之一,所以随后的查询可以相对于这些上下文节点来导航。

你可以从行集中取得多个值。举个例子,你可以对由nodes()返回的行集应用value()方法,从原始XML实例中取得多个值。注意如果把value()方法应用到XML实例上,只返回一个值。

句法

nodes (XQuery) as Table(Column)

参数

XQuery
是一个字符串字面值。如果查询表达式构造了节点,这些构造得的节点会曝露在结果行集中。如果查询表达式产品一个空序列,行集将是空的。如果查询表达式静态地生成包含原子值而不是节点的序列,则会引发静态错误。
Table(Column)
是针对结果集的表名和列名。

备注

作为一个示例,假定你有下面的表:

T (ProductModelID int, Instructions xml)

下面的产品说明书文档存储在表中。只显示了一些片段。注意文档中有三个产品产地。

<root>
  <Location LocationID="10"...>
     <step>...</step>
     <step>...</step>
      ...
  </Location>
  <Location LocationID="20" ...>
       ...
  </Location>
  <Location LocationID="30" ...>
       ...
  </Location>
</root>

一个引用查询表达式/root/Locationnodes()方法,将返回一个行集,带有三个行,每个行包含了原始XML文档的一个产地副本,而且上下文项被设置为<Location>节点之一:

Product
ModelID      Instructions
----------------------------------
1       <root>
             <Location LocationID="20" ... />
             <Location LocationID="30" .../></root>
1      <root><Location LocationID="10" ... />
             <Location LocationID="30" .../></root>
1      <root><Location LocationID="10" ... />
             <Location LocationID="20" ... />
             </root>

你可以利用xml 数据类型方法来查询该行集。下面的查询提取出了每个生成的行的上下文项的子树:

SELECT T2.Loc.query('.')
FROM   T
CROSS APPLY Instructions.nodes('/root/Location') as T2(Loc)

这是结果:

ProductModelID  Instructions
----------------------------------
1        <Location LocationID="10" ... />
1        <Location LocationID="20" ... />
1        <Location LocationID="30" .../>

注意返回的行集维持了类型信息。你可以对nodes()方法的结果应用xml数据类型方法,比如说query()value()exist()nodes()。然而,你不能对它应用modify()方法来修改该XML实例。

而且,行集中的上下文节点不能被物化。也就是说,你不能在一个SELECT语句中使用它。然而,你可以在IS NULL和COUNT(*)中使用它。

使用nodes方法的场景与使用OPENXML (Transact-SQL)的场景相同。这个函数提供了XML的一个行集视图。然而,当你在包含了若干行XML文档的表上使用nodes()方法时,你并不一定得使用指针。

注意nodes()方法返回的行集是一个非命名的行集。因此,必须使用别名来显式指定它。

nodes()函数不能直接应用到一个用户定义的函数上。如果想要对一个用户定义的标量函数使用nodes()函数,你可以把用户定义函数的结果赋值给一个变量,或者使用派生表来赋值一个列,别名到一个用户定义函数返回值,然后使用CROSS APPLY来从别名中选择。

下面的示例演示了一个方法,使用CROSS APPLY来从一个用户定义函数的结果中选择。

USE AdventureWorks;
GO
CREATE FUNCTION XTest()
RETURNS xml
AS
BEGIN
RETURN '<document/>';
END;
GO
SELECT A2.B.query('.')
FROM
(SELECT dbo.XTest()) AS A1(X)
CROSS APPLY X.nodes('.') A2(B);
GO
DROP FUNCTION XTest;
GO

示例

针对一个xml类型的变量使用nodes()方法

在下面的示例中,有一个XML文档,具有<Root>顶级元素,以及三个<row>子元素。该查询使用nodes()方法来设置分开的上下文节点,每个节点对应每个<row>元素。nodes()方法返回一个行集,带有三个行。每个行具有一个原始XML的逻辑副本,每个上下文节点标识了原始文档中的一个不同的<row>元素。

然后查询从每一行中返回上下文节点:

DECLARE @x xml
SET @x='<Root>
    <row id="1"><name>Larry</name><oflw>some text</oflw></row>
    <row id="2"><name>moe</name></row>
    <row id="3" />
</Root>'
SELECT T.c.query('.') AS result
FROM   @x.nodes('/Root/row') T(c)
GO

下面的是结果。在本示例中,查询方法返回上下文项以及它的内容:

<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3"/>

对应所有三个,在上下文节点中应用父节点访问器,返回<Root>元素

SELECT T.c.query('..') AS result
FROM   @x.nodes('/Root/row') T(c)
go

这是结果

<Root>
    <row id="1"><name>Larry</name><oflw>some text</oflw></row>
    <row id="2"><name>moe</name></row>
    <row id="3" />
</Root>
<Root>
    <row id="1"><name>Larry</name><oflw>some text</oflw></row>
    <row id="2"><name>moe</name></row>
    <row id="3" />
</Root>
<Root>
    <row id="1"><name>Larry</name><oflw>some text</oflw></row>
    <row id="2"><name>moe</name></row>
    <row id="3" />
</Root>

针对一个xml类型的列指定nodes()方法

本示例中所用的自行车产品说明书,它存储在ProductModel表的Instructions xml类型列中。

在下面的示例中,针对Instructions列指定nodes()方法,该列是ProductModel表中的xml类型列。

nodes()方法通过指定/MI:root/MI:Location路径,把<Location>元素设置为上下文节点。结果的行集包含了原始文档的逻辑副本,每行对应文档中的每个<Location>节点,其上下文节点设置为<Location>元素。因此,nodes()函数给了一个<Location>上下文节点的集合。

query()方法针对该行集请求self::node,因此,返回每一行中的<Location>

在这个示例中,该查询把某个产品模块的产品说明书中的每个 <Location> 元素设置为上下文节点。你可以使用这些上下文节点来取得以下这些值:

  • 在每个<Location>中找到LocationID。
  • 在每个 <Location>里取回生产步骤(<step>子元素)。

该查询返回上下文项,用到了query()方法,在其中指定了简写句法'.'代替self::node()

注意以下:

  • 在Instructions列上应用nodes()方法,返回一个行集T (C)。这个行集包含了原始产品说明书文档的逻辑副本,带有/root/Location作为上下文项。
  • CROSS APPLY把nodes()应用到Instructions表中的每一行,只返回产生结果集的那些行。

    SELECT C.query('.') as result
    FROM Production.ProductModel
    CROSS APPLY Instructions.nodes('
    declare namespace MI="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
    /MI:root/MI:Location') as T(C)
    WHERE ProductModelID=7

    这是结果的一部分:

    <MI:Location LocationID="10"  ...>
       <MI:step ... />
          ...
    </MI:Location>
    <MI:Location LocationID="20"  ... >
        <MI:step ... />
          ...
    </MI:Location>
    ...

对由别的nodes()方法返回的行集应用nodes()

下面的代码针对每份产品说明书,查询了XML文档,产品说明书在ProductModel表的Instructions列中。产品返回一个行集,包含了ProductModelID、产地、生产步骤。

注意以下:

  • Instructions列上应用nodes()方法,返回T1 (Locations)行集。该行集包含了原始产品说明书文档的逻辑副本,并以/root/Location元素为项上下文。
  • T1 (Locations)行集上应用nodes(),并返回T2(steps)行集。该行集包含了原始产品说明书文档的逻辑副本,并以/root/Location/step元素为项上下文。
SELECT ProductModelID, Locations.value('./@LocationID','int') as LocID,
steps.query('.') as Step
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('
declare namespace MI="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
/MI:root/MI:Location') as T1(Locations)
CROSS APPLY T1.Locations.nodes('
declare namespace MI="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
./MI:step ') as T2(steps)
WHERE ProductModelID=7
GO

这是结果

ProductModelID LocID Step
----------------------------
7      10   <step ... />
7      10   <step ... />
...
7      20   <step ... />
7      20   <step ... />
7      20   <step ... />
...

该查询声明了MI前缀两次。作为代替,你可以使用WITH XMLNAMESPACES来声明前缀一次,并在查询中使用它:

WITH XMLNAMESPACES (
   'http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions'  AS MI)
SELECT ProductModelID, Locations.value('./@LocationID','int') as LocID,
steps.query('.') as Step
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('
/MI:root/MI:Location') as T1(Locations)
CROSS APPLY T1.Locations.nodes('
./MI:step ') as T2(steps)
WHERE ProductModelID=7
GO

如果你喜欢这篇文章,敬请给站长打赏↑

除特别注明外,本站所有文章均为本站站长原译,转载请注明出处。