XML の構築 (XQuery)

適用対象:SQL Server

XQuery では、 直接 コンストラクターと 計算された コンストラクターを使用して、クエリ内に XML 構造を構築できます。

注意

直接コンストラクターと計算されたコンストラクターには違いはありません。

ダイレクト コンストラクターの使用

直接コンストラクターを使用する場合は、XML を構築するときに XML に似た構文を指定します。 次の例では、直接コンストラクターを使用した XML 構築を示しています。

要素の構築

XML の表記法を使用して要素を構築できます。 次の例では、ダイレクト要素コンストラクター式を使用し、ProductModel> 要素を<作成します。 構築される要素には、次の 3 つの子要素があります。

  • テキスト ノード。

  • [概要]> と <[機能]> の 2 つの要素ノード<。

    • <Summary> 要素には、値が "Some description" である 1 つのテキスト ノード子があります。

    • <Features> 要素には、Color<>、Weight>、<および <Warranty> の 3 つの要素ノードの子があります。 これらの各ノードには 1 つのテキスト ノード子があり、それぞれ 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 では、式はその値に置き換えられます。 たとえば、次のクエリは、1 つの子要素 (><e) を持つ要素を構築<NewRoot>します。 要素 <e> の値は、中かっこ ("{ ... }") 内のパス式を指定することによって計算されます。

DECLARE @x xml;  
SET @x='<root>5</root>';  
SELECT @x.query('<NewRoot><e> { /root } </e></NewRoot>');  

中かっこはコンテキスト切り替えトークンとして機能し、クエリを XML 構築からクエリ評価に切り替えます。 この場合、中かっこ内の XQuery パス式 () が評価され、 /root結果が代わりに使用されます。

結果を次に示します。

<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>  

次のクエリは、ダイレクト要素コンストラクターを使用して要素を構築するもう 1 つの例です。 また、要素の <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 の構築での要素の内容

次の例は、ダイレクト要素コンストラクターを使用して要素コンテンツを構築するときの式の動作を示しています。 次の例では、直接要素コンストラクターで 1 つの式が指定されています。 この式では、構築される XML に 1 つのテキスト ノードが作成されます。

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>');  
  

式の評価に起因するアトミック値シーケンスは、結果に示すように、隣接するアトミック値の間にスペースが追加されたテキスト ノードに追加されます。 構築された要素には 1 つの子があります。 これは、結果に表示される値を含むテキスト ノードです。

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

1 つの式の代わりに、3 つのテキスト ノードを生成する 3 つの個別の式を指定した場合、隣接するテキスト ノードは、結果の XML で連結によって 1 つのテキスト ノードにマージされます。

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>');  

構築された要素ノードには 1 つの子があります。 これは、結果に表示される値を含むテキスト ノードです。

<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 という子テキスト ノードが 1 つあります。

属性を構築する場合は、中かっこで式を使用してその値を指定できます。 この場合、式の結果が属性値として返されます。

次の例では、 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 式) 属性式はサポートされていません。 たとえば、次のクエリに示すように、 は定数で、値5はクエリ式を評価することによって取得される XML をItem構築します。

    <a attr="Item 5" />  
    

    定数文字列と式 ({/x}) が混在しており、これがサポートされていないため、次のクエリはエラーを返します。

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

    その場合は、次のいずれかの方法で対処します。

    • 2 つのアトミック値を連結して属性値を形成します。 この 2 つのアトミック値は、間に空白が挿入されて 1 つの属性値へとシリアル化されます。

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

      結果を次に示します。

      <a attr="Item 5" />  
      
    • concat 関数を使用して、2 つの文字列引数を結果の属性値に連結します。

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

      この場合、2 つの文字列値の間に空白が追加されません。 2 つの文字列値の間に空白が必要な場合は、明示的に空白を指定する必要があります。

      結果を次に示します。

      <a attr="Item5" />  
      
  • 属性値としての複数の式はサポートされていません。 たとえば、次のクエリではエラーが返されます。

    DECLARE @x xml  
    SET @x ='<x>5</x>'  
    SELECT @x.query( '<a attr="{/x}{/x}"/>' )  
    
  • 異種シーケンスはサポートされません。 次の例に示すように、1 つの属性値として異種シーケンスを割り当てようとすると、エラーが返されます。 この例では、異種シーケンス (文字列 "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 として扱われます。 具体的には、空白文字は次のように処理されます。

    • 最初と最後にある空白文字は切り捨てられます。

    • 内部空白文字の値が 1 つのスペースに折りたたまれる

  • 属性コンテンツ内の改行文字はスペースに置き換えられます。 他のすべての空白文字はそのまま残ります。

  • 要素内の空白は保持されます。

次の例は、XML 構築での空白処理を示しています。

-- line feed is repaced 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 に要素、2 つの属性、コメント、および処理命令が含まれています。 シーケンスが構築されているため、 <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>  
  

計算コンストラクターの使用

. このコンストラクターを使用する場合は、構築するノードの種類を特定するキーワードを指定します。 サポートされているキーワードは次のとおりです。

  • 要素

  • 属性 (attribute)

  • テキスト

要素ノードと属性ノードの場合、これらのキーワードの後にノード名が続き、そのノードのコンテンツを生成する式が中かっこで囲まれます。 この後に示す例では、次の 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 式