共用方式為


XML 建構 (XQuery)

適用於:SQL Server

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

注意

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

使用直接建構函式

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

建構項目

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

  • 文字節點。

  • 兩個元素節點: <摘要> 和 <功能>。

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

    • Features 元素有三個元素節點子系:<Color>、<Weight> 和<保固>。> < 每個節點都有一個文字節點子節點,且分別具有 Red、25、2 年元件和人力的值。

declare @x 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>) 的專案。 元素的值 <e> 是藉由在大括弧內指定路徑表示式來計算 (“{ ... }” 。

DECLARE @x 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 xml;  
SET @x='<root>5</root>';  
DECLARE @y xml;  
SET @y = (SELECT @x.query('  
                           <NewRoot>  
                             <e> { data(/root) } </e>  
                           </NewRoot>' ));  
SELECT @y;  

以下是結果:

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

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

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

    DECLARE @x 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 xml  
set @x ='<x>5</x>'  
select @x.query( '  
  <a xmlns="a">  
    <b xmlns=""/>  
  </a>' )   

以下是結果:

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

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

declare @x 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 建構中取消宣告預設命名空間,但無法取消宣告命名空間前置詞。 下列查詢會傳回錯誤,因為您無法取消宣告元素建構 <b>中指定的前置詞。

declare @x 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  

請注意,以此方式建立新的命名空間前置詞將會覆寫此前置詞的任何預先存在的命名空間宣告。 例如,查詢初構中的命名空間宣告 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  

使用 Prolog 新增命名空間

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

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

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

以下是結果:

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

XML 建構和空格符處理

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

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

    • 開始和結尾的任何空格符會修剪。

    • 內部空格元值會折疊成單一空格符

  • 屬性內容內的換行字元會由空格取代。 所有其他空格符都會保持原狀。

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

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

-- line feed is replaced by space.  
declare @x 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 來建構文字節點。

注意 如需使用明確文字節點建構函式的範例,請參閱 insert (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>  
  

使用計算建構函式

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

  • 項目

  • 屬性

  • text

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

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

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

declare @x xml  
set @x=''  
select @x.query('element root   
               {   
                  element ProductModel  
     {  
attribute PID { 5 },  
text{"Some text "},  
    element summary { "Some Summary" }  
 }  
               } ')  
  

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

declare @x 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 不支援下列計算建構函式:

  • 計算的檔案節點建構函式

  • 計算處理指令建構函式

  • 計算批注建構函式

另請參閱

XQuery 表達式