共用方式為


XML 建構 (XQuery)

適用於:SQL Server

在 XQuery 中,您可以使用 直接計算的 建構函式來建構查詢內的 XML 結構。

注意

直接建構函式和計算建構函式之間沒有差異。

使用直接建構函式

當您使用直接建構函式時,您可以在建構 XML 時指定類似 XML 的語法。 下列範例說明直接建構函式的 XML 建構。

建構元素

在使用 XML 表示法時,您可以建構元素。 下列範例會使用直接元素建構函式,並建立元素 <ProductModel> 。 建構的專案有三個子元素

  • 文字節點。

  • 兩個元素節點, <Summary> 以及 <Features>.

    • 元素 <Summary> 有一個文字節點子系,其值為 "Some description"

    • 元素有 <Features> 三個元素節點子項 、 <Color><Weight><Warranty>。 這些節點中的每一個都有一個文字節點子項,並分別具有值 Red252 years parts and labor, 。

DECLARE @x AS XML;

SET @x = '';

SELECT @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
<Features>
  <Color>Red</Color>
  <Weight>25</Weight>
  <Warranty>2 years parts and labor</Warranty>
</Features></ProductModel>');

以下是產生的 XML:

<ProductModel ProductModelID="111">
  This is product model catalog description.
  <Summary>Some description</Summary>
  <Features>
    <Color>Red</Color>
    <Weight>25</Weight>
    <Warranty>2 years parts and labor</Warranty>
  </Features>
</ProductModel>

雖然從常數表達式建構元素,如本範例所示,但這個 XQuery 語言功能的真正威力是建構可動態從資料庫擷取數據的 XML 的能力。 您可以使用大括弧來指定查詢表達式。 在產生的 XML 中,表示式會由其值取代。 例如,下列查詢會建構具有 <NewRoot> 一個子元素 (<e>) 的元素。 element <e> 的值是透過在大括弧內指定路徑運算式 (“{ ... }”) 來計算的。

DECLARE @x AS XML;

SET @x = '<root>5</root>';

SELECT @x.query('<NewRoot><e> { /root } </e></NewRoot>');

大括弧會作為內容切換令牌,並將查詢從 XML 建構切換至查詢評估。 在此情況下,會評估大括弧 /root內的 XQuery 路徑表達式,並取代結果。

結果如下︰

<NewRoot>
  <e>
    <root>5</root>
  </e>
</NewRoot>

下列查詢與上一個查詢類似。 不過,大括弧中的運算式會指定函數來 data() 擷取元素的 <root> 原子值,並將其指派給建構的元素 <e>

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('
                           <NewRoot>
                             <e> { data(/root) } </e>
                           </NewRoot>'));

SELECT @y;

結果如下︰

<NewRoot>
  <e>5</e>
</NewRoot>

如果您想要使用大括弧做為文字的一部分,而不是內容切換令牌,您可以將它們逸出為 “}}” 或 “{{”,如下列範例所示:

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('
<NewRoot> Hello, I can use {{ and  }} as part of my text</NewRoot>'));

SELECT @y;

結果如下︰

<NewRoot> Hello, I can use { and  } as part of my text</NewRoot>

下列查詢是使用直接元素建構函式建構元素的另一個範例。 此外,元素的 <FirstLocation> 值是透過執行大括號中的表達式來取得的。 查詢表達式會從 Production.ProductModel 數據表的 Instructions 數據行,傳回第一個工作中心位置的製造步驟。

SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        <FirstLocation>
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

結果如下︰

<FirstLocation>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">
      Insert <AWMI:material>aluminum sheet MS-2341</AWMI:material> into the <AWMI:tool>T-85A framing tool</AWMI:tool>.
  </AWMI:step>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">
      Attach <AWMI:tool>Trim Jig TJ-26</AWMI:tool> to the upper and lower right corners of the aluminum sheet.
  </AWMI:step>
   ...
</FirstLocation>

XML 建構中的元素內容

下列範例說明使用直接專案建構函式建構項目內容時表達式的行為。 在下列範例中,直接元素建構函式會指定一個表達式。 針對此表達式,會在產生的 XML 中建立一個文字節點。

DECLARE @x AS XML;
SET @x = '
<root>
  <step>This is step 1</step>
  <step>This is step 2</step>
  <step>This is step 3</step>
</root>';

SELECT @x.query('
<result>
 { for $i in /root[1]/step
    return string($i)
 }
</result>');

表達式評估所產生的不可部分完成值序列會新增至文字節點,並在相鄰不可部分完成值之間新增空格,如結果所示。 建構的專案有一個子系。 這是包含結果中所顯示值的文字節點。

<result>This is step 1 This is step 2 This is step 3</result>

如果您指定三個不同的表達式來產生三個文字節點,則相鄰的文字節點會藉由串連合併成單一文字節點,而不是一個表達式。

DECLARE @x AS XML;
SET @x = '
<root>
  <step>This is step 1</step>
  <step>This is step 2</step>
  <step>This is step 3</step>
</root>';

SELECT @x.query('
<result>
 { string(/root[1]/step[1]) }
 { string(/root[1]/step[2]) }
 { string(/root[1]/step[3]) }
</result>');

建構的項目節點有一個子系。 這是包含結果中所顯示值的文字節點。

<result>This is step 1This is step 2This is step 3</result>

建構屬性

當您使用直接元素建構函式建構元素時,您也可以使用類似 XML 的語法來指定元素的屬性,如下列範例所示:

DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('<ProductModel ProductModelID="111">;
This is product model catalog description.
<Summary>Some description</Summary>
</ProductModel>');

以下是產生的 XML:

<ProductModel ProductModelID="111">
  This is product model catalog description.
  <Summary>Some description</Summary>
</ProductModel>

建構的元素 <ProductModel> 具有 ProductModelID 屬性和下列子節點:

  • 文字節點, This is product model catalog description.

  • 元素節點 . <Summary> 此節點有文字節點子節點, Some description

當您建構屬性時,您可以使用大括弧中的運算式來指定其值。 在此情況下,表達式的結果會當做屬性值傳回。

在下列範例中,並非絕對需要函 data() 式。 因為您要將運算式值指派給屬性, data() 所以會隱含套用來擷取指定運算式的型別值。

DECLARE @x AS XML;
SET @x = '<root>5</root>';

DECLARE @y AS XML;
SET @y = (SELECT @x.query('<NewRoot attr="{ data(/root) }" ></NewRoot>'));

SELECT @y;

結果如下︰

<NewRoot attr="5" />

以下是針對 LocationID 和 SetupHrs 屬性建構指定表達式的另一個範例。 這些表達式會根據指令數據行中的 XML 進行評估。 表達式的具型別值會指派給屬性。

SELECT Instructions.query('
    declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
        <FirstLocation
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

這是部分結果:

<FirstLocation LocationID="10" SetupHours="0.5" >
  <AWMI:step ...
  </AWMI:step>
  ...
</FirstLocation>

實作限制

以下是限制:

  • 不支援多個或混合 (字串和 XQuery 運算式) 屬性運算式。 例如,如下列查詢所示,您可以建構 XML,其中 Item 是常數,而值 5 是透過評估查詢表達式來取得:

    <a attr="Item 5" />
    

    下列查詢會傳回錯誤,因為您正在將常數字串與運算式 ({/x}) 混合使用,而且不支援此專案:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="Item {/x}"/>');
    

    在這種情況下,您有下列選項:

    • 透過兩個不可部分完成值的串連,形成屬性值。 這些不可部分完成的值會以不可部分完成值之間的空格串行化為屬性值:

      SELECT @x.query('<a attr="{''Item'', data(/x)}"/>');
      

      結果如下︰

      <a attr="Item 5" />
      
    • 使用 concat 函式,將兩個字串自變數串連至產生的屬性值:

      SELECT @x.query('<a attr="{concat(''Item'', /x[1])}"/>');
      

      在此情況下,兩個字串值之間不會新增空格。 如果您想要兩個值之間的空格,您必須明確提供它。

      結果如下︰

      <a attr="Item5" />
      
  • 不支援將多個運算式作為屬性值。 例如,下列查詢會傳回錯誤:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="{/x}{/x}"/>');
    
  • 不支援異質序列。 任何嘗試將異質序列指派為屬性值都會傳回錯誤,如下列範例所示。 在此範例中,異質序列、字串「Item」和元素 <x>被指定為屬性值:

    DECLARE @x AS XML;
    SET @x = '<x>5</x>';
    
    SELECT @x.query('<a attr="{''Item'', /x }" />');
    

    如果您套用函數 data() ,查詢會運作,因為它會擷取運算式的不可部分完成值, /x該值會與字串串連。 以下是不可部分完成值的序列:

    SELECT @x.query('<a attr="{''Item'', data(/x)}"/>');
    

    結果如下︰

    <a attr="Item 5" />
    
  • 屬性節點順序會在串行化期間強制執行,而不是在靜態類型檢查期間強制執行。 例如,下列查詢失敗,因為它嘗試在非屬性節點之後新增屬性。

    SELECT CONVERT (XML, '').query('
        element x { attribute att { "pass" }, element y { "Element text" }, attribute att2 { "fail" } }
        ');
    GO
    

    上一個查詢傳回下列錯誤:

    XML well-formedness check: Attribute cannot appear outside of element declaration. Rewrite your XQuery so it returns well-formed XML.
    

新增命名空間

使用直接建構函式建構 XML 時,建構的專案和屬性名稱可以使用命名空間前置詞來限定。 您可以透過下列方式將前置詞系結至命名空間:

  • 使用命名空間宣告屬性。
  • 通過使用子 WITH XMLNAMESPACES 句。
  • 在 XQuery 初構中。

使用命名空間宣告屬性來新增命名空間

下列範例會在建構元素 <a> 中使用命名空間宣告屬性來宣告預設命名空間。 子元素 <b> 的建構會復原父元素中宣告的預設命名空間宣告。

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <a xmlns="a">
    <b xmlns=""/>
  </a>');

結果如下︰

<a xmlns="a">
  <b xmlns="" />
</a>

您可以將前置詞指派給命名空間。 前綴在元素 <a>的構造中指定。

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <x:a xmlns:x="a">
    <b/>
  </x:a>');

結果如下︰

<x:a xmlns:x="a">
  <b />
</x:a>

您可以在 XML 建構中取消宣告預設命名空間,但無法取消宣告命名空間前置詞。 下列查詢會傳回錯誤,因為您無法取消宣告建構 element <b>中指定的前置詞。

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
  <x:a xmlns:x="a">
    <b xmlns:x=""/>
  </x:a>');

新建構的命名空間可用於查詢內。 例如,下列查詢會在建構元素時宣告命名空間, <FirstLocation>並在 LocationID 和 SetupHrs 屬性值的運算式中指定前置詞。

SELECT Instructions.query('
        <FirstLocation xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

以這種方式建立新的命名空間前置詞會覆寫此前置詞的任何預先存在的命名空間宣告。 例如,查詢 Prolog 中的命名空間宣告 AWMI="https://someURI",會由元素中的 <FirstLocation> 命名空間宣告覆寫。

SELECT Instructions.query('
declare namespace AWMI="https://someURI";
        <FirstLocation xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions"
         LocationID="{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
         SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
           { /AWMI:root/AWMI:Location[1]/AWMI:step }
        </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

使用序言新增命名空間

此範例說明如何將命名空間新增至建構的 XML。 默認命名空間會在查詢初構中宣告。

DECLARE @x AS XML;
SET @x = '<x>5</x>';

SELECT @x.query('
           declare default element namespace "a";
            <a><b xmlns=""/></a>');

在element <b>的建構中,命名空間宣告屬性以空字串作為其值來指定。 這會取消宣告父系中宣告的預設命名空間。

結果如下︰

<a xmlns="a">
  <b xmlns="" />
</a>

XML 建構和空格處理

XML 建構中的元素內容可以包含空格符。 這些字元會以下欄取:

  • 命名空間 URI 中的空格字元會被視為 XSD 類型 anyURI。 具體來說,這是它們的處理方式:

    • 開始和結尾的任何空格符會修剪。
    • 內部空格元值會折疊成單一空格符
  • 屬性內容內的換行字元會由空格取代。 所有其他空格符都會保持原狀。

  • 會保留元素內的空格符。

下列範例說明 XML 建構中的空格符處理:

-- line feed is replaced by space.
DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('

declare namespace myNS="   https://
 abc/
xyz

";
<test attr="    my
test   attr
value    " >

<a>

This     is  a

test

</a>
</test>
') AS XML_Result;

結果如下︰

-- result
<test attr="<test attr="    my test   attr  value    "><a>

This     is  a

test

</a></test>
"><a>

This     is  a

test

</a></test>

其他直接 XML 建構函式

用於處理指令和 XML 註解的建構函式使用與對應 XML 建構語法相同的語法。 也支援文字節點的計算建構函式,但主要用於 XML DML 建構文字節點。

注意

如需使用明確文字節點建構函式的範例,請參閱 插入 (XML DML) 中的特定範例。

在下列查詢中,建構的 XML 包含元素、兩個屬性、批注和處理指令。 逗號會在 之前 <FirstLocation>使用,因為正在建構序列。

SELECT Instructions.query('
  declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   <?myProcessingInstr abc="value" ?>,
   <FirstLocation
        WorkCtrID = "{ (/AWMI:root/AWMI:Location[1]/@LocationID)[1] }"
        SetupHrs = "{ (/AWMI:root/AWMI:Location[1]/@SetupHours)[1] }" >
       <!-- some comment -->
       <?myPI some processing instructions ?>
       { (/AWMI:root/AWMI:Location[1]/AWMI:step) }
    </FirstLocation>
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

這是部分結果:

<?myProcessingInstr abc="value" ?>
<FirstLocation WorkCtrID="10" SetupHrs="0.5">
  <!-- some comment -->
  <?myPI some processing instructions ?>
  <AWMI:step xmlns:AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions">I
  nsert <AWMI:material>aluminum sheet MS-2341</AWMI:material> into the <AWMI:tool>T-85A framing tool</AWMI:tool>.
  </AWMI:step>
    ...
</FirstLocation>

使用計算建構函式

在此情況下,您可以指定可識別您要建構之節點類型的關鍵詞。 僅支援下列關鍵詞:

  • 元素
  • 屬性
  • 收發簡訊

對於元素和屬性節點,這些關鍵詞後面接著節點名稱,後面還有以大括弧括住的表達式,以產生該節點的內容。 在下列範例中,您要建構此 XML:

<root>
  <ProductModel PID="5">Some text <summary>Some Summary</summary></ProductModel>
</root>

以下是使用計算建構函式產生 XML 的查詢:

DECLARE @x AS XML;
SET @x = '';

SELECT @x.query('element root
               {
                  element ProductModel
     {
attribute PID { 5 },
text{"Some text "},
    element summary { "Some Summary" }
 }
               } ');

產生節點內容的表示式可以指定查詢表達式。

DECLARE @x AS XML;
SET @x = '<a attr="5"><b>some summary</b></a>';

SELECT @x.query('element root
               {
                  element ProductModel
     {
attribute PID { /a/@attr },
text{"Some text "},
    element summary { /a/b }
 }
               } ');

如 XQuery 規格中所定義的計算元素及屬性建構函式,可讓您計算節點名稱。 當您在 SQL Server 中使用直接建構函式時,必須將節點名稱 (例如元素和屬性) 指定為常數常值。 因此,元素和屬性的直接建構函式和計算建構函式沒有差異。

在下列範例中,建構節點的內容是從 ProductModel 數據表中 xml 數據類型之 Instructions 數據行中儲存的 XML 製造指令取得。

SELECT Instructions.query('
  declare namespace AWMI="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
   element FirstLocation
     {
        attribute LocationID { (/AWMI:root/AWMI:Location[1]/@LocationID)[1] },
        element   AllTheSteps { /AWMI:root/AWMI:Location[1]/AWMI:step }
     }
') AS Result
FROM Production.ProductModel
WHERE ProductModelID = 7;

這是部分結果:

<FirstLocation LocationID="10">
  <AllTheSteps>
    <AWMI:step> ... </AWMI:step>
    <AWMI:step> ... </AWMI:step>
    ...
  </AllTheSteps>
</FirstLocation>

其他實作限制

計算屬性建構函式無法用來宣告新的命名空間。 此外,SQL Server 不支援下列計算建構函式:

  • 計算的檔案節點建構函式
  • 計算處理指令建構函式
  • 計算批注建構函式