次の方法で共有


XML 構築 (XQuery)

適用対象:SQL Server

XQuery では、 direct および computed コンストラクターを使用して、クエリ内に XML 構造体を構築できます。

Note

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

ダイレクト コンストラクターを使用する

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

要素を構築する

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

  • テキスト ノード。

  • <Summary><Features>の 2 つの要素ノード。

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

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

DECLARE @x AS XML;

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

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

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

結果は次のとおりです。

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

次に示すクエリは先ほどのクエリと似ています。 ただし、中かっこ内の式は、<root>要素のアトミック値を取得するdata()関数を指定し、構築された要素<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>

次のクエリは、ダイレクト要素コンストラクターを使用して要素を構築するもう 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 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>');

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

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

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

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

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

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

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

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

    <a attr="Item 5" />
    

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

    DECLARE @x AS 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 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 構築では既定の名前空間を宣言解除できますが、名前空間プレフィックスの宣言を解除することはできません。 次のクエリでは、要素 <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;

この方法で新しい名前空間プレフィックスを作成すると、このプレフィックスの既存の名前空間宣言がオーバーライドされます。 たとえば、クエリ プロローグ内の名前空間宣言 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>');

要素 <b>の構築では、名前空間宣言属性を値として空の文字列で指定します。 これにより、親要素で宣言されている既定の名前空間の宣言が解除されます。

結果は次のとおりです。

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

XML の構築と空白の処理

XML 構築の要素コンテンツには、空白文字を含めることができます。 これらの文字は、次の方法で処理されます。

  • 名前空間 URI の空白文字は、XSD 型 anyURIとして扱われます。 具体的には、次の方法で処理されます。

    • 最初と最後にある空白文字は切り捨てられます。
    • 内部空白文字の値は 1 つのスペースに折りたたまれます
  • 属性コンテンツ内の改行文字はスペースに置き換えられます。 他のすべての空白文字はそのまま残ります。

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

次の例は、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 で使用されます。

Note

明示的なテキスト ノード コンストラクターの使用例については、 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>

計算されたコンストラクターを使用する

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

  • 要素
  • 属性
  • SMS 送信

要素ノードと属性ノードの場合、これらのキーワードの後にノード名が続き、そのノードのコンテンツを生成する式が中かっこで囲まれます。 次の例では、この 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 では、次の計算コンストラクターはサポートされていません。

  • 計算されたドキュメント ノードコンストラクター
  • 計算された処理命令コンストラクター
  • 計算されたコメント コンストラクター