トピックで説明されているように、FOR XML、RAW、AUTO モード を使用した XML の構築では、クエリ結果から生成される XML の形状をあまり制御できません。 ただし、EXPLICIT モードでは、クエリ結果から必要な XML を生成する際に最も柔軟性が高くなります。
EXPLICIT モードのクエリは、必要な XML に関する追加情報 (XML の入れ子など) がクエリの一部として明示的に指定されるように、特定の方法で記述する必要があります。 要求する XML によっては、EXPLICIT モードクエリの記述が煩雑になる場合があります。 入れ子に PATH モードを使用 する方が、EXPLICIT モードクエリを記述するより簡単な代替方法である場合があります。
クエリの一部として必要な XML を EXPLICIT モードで記述するため、生成された XML が整形式で有効であることを確認する必要があります。
EXPLICIT モードでの行セット処理
EXPLICIT モードでは、クエリの実行結果の行セットが XML ドキュメントに変換されます。 EXPLICIT モードで XML ドキュメントを生成するには、行セットに特定の形式が必要です。 そのためには、SELECT クエリを記述して、特定の形式の行セット ( ユニバーサル テーブル) を作成し、処理ロジックで必要な XML を生成できるようにする必要があります。
最初に、クエリで次の 2 つのメタデータ列を生成する必要があります。
最初の列には、現在の要素のタグ番号、整数型、および列名を Tag にする必要があります。 クエリでは、行セットから構築される要素ごとに一意のタグ番号を指定する必要があります。
2 番目の列は親要素のタグ番号を指定する必要があり、この列名は Parent である必要があります。 このようにして、タグと親列は階層情報を提供します。
これらのメタデータ列の値と列名の情報は、目的の XML を生成するために使用されます。 クエリでは、特定の方法で列名を指定する必要があることに注意してください。 また、 Parent 列の 0 または NULL は、対応する要素に親がないことを示します。 要素は、最上位要素として XML に追加されます。
クエリによって生成されたユニバーサル テーブルが XML 結果を生成するためにどのように処理されるかを理解するには、次のユニバーサル テーブルを生成するクエリを作成したとします。
このユニバーサル テーブルについては、次の点に注意してください。
最初の 2 つの列は Tag と Parent で、メタ列です。 これらの値によって階層が決まります。
列名は、このトピックで後述するように、特定の方法で指定します。
このユニバーサル テーブルから XML を生成する場合、このテーブル内のデータは列グループに垂直方向にパーティション分割されます。 グループ化は、 タグ 値と列名に基づいて決定されます。 XML を構築する場合、処理ロジックは行ごとに列の 1 つのグループを選択し、要素を構築します。 この例では、次のことが適用されます。
最初の行の タグ 列値 1 の場合、名前に同じタグ番号 Customer!1!cid と Customer!1!name が含まれる列は、グループを形成します。 これらの列は行の処理に使用され、生成された要素の形状が <
Customer id=... name=...
>されていることに気付いたかもしれません。 列名の形式については、このトピックの後半で説明します。タグ列の値が 2 の行の場合、列 Order!2!id と Order!2!date は、要素の構築に使用されるグループを形成<
Order id=... date=... /
>。タグ列の値が 3 の行の場合、列 OrderDetail!3!id!id と OrderDetail!3!pid!idref はグループを形成します。 これらの各行は、これらの列から要素 <
OrderDetail id=... pid=...
>を生成します。
XML 階層の生成では、行が順番に処理されることに注意してください。 XML 階層は、次のように決定されます。
最初の行は 、タグ 値 1 と 親 値 NULL を指定します。 したがって、対応する要素 <
Customer
> 要素は、XML の最上位要素として追加されます。<Customer cid="C1" name="Janine">
2 番目の行は 、タグ 値 2 と 親 値 1 を識別します。 したがって、要素 <
Order
> 要素は、 <Customer
> 要素の子として追加されます。<Customer cid="C1" name="Janine"> <Order id="O1" date="1/20/1996">
次の 2 つの行は 、タグ 値 3 と 親 値 2 を識別します。 したがって、2 つの要素 <
OrderDetail
> 要素は、 <Order
> 要素の子として追加されます。<Customer cid="C1" name="Janine"> <Order id="O1" date="1/20/1996"> <OrderDetail id="OD1" pid="P1"/> <OrderDetail id="OD2" pid="P2"/>
最後の行は、 タグ 番号として 2 を識別し、1 を 親 タグ番号として識別します。 したがって、別の <
Order
> 要素の子が <Customer
> 親要素に追加されます。<Customer cid="C1" name="Janine"> <Order id="O1" date="1/20/1996"> <OrderDetail id="OD1" pid="P1"/> <OrderDetail id="OD2" pid="P2"/> </Order> <Order id="O2" date="3/29/1997"> </Customer>
要約すると、 タグ および 親 メタ列の値、列名に指定された情報、および行の正しい順序によって、EXPLICIT モードを使用するときに必要な XML が生成されます。
普遍的なテーブル行の順序付け
XML を構築する場合、ユニバーサル テーブル内の行は順番に処理されます。 したがって、親に関連付けられている正しい子インスタンスを取得するには、各親ノードの直後に子が続くように、行セット内の行を並べ替える必要があります。
ユニバーサル テーブルでの列名の指定
EXPLICIT モードのクエリを記述する場合、結果の行セット内の列名は、この形式を使用して指定する必要があります。 これらは、要素名や属性名などの変換情報と、ディレクティブを使用して指定されたその他の追加情報を提供します。
これは一般的な形式です。
ElementName!TagNumber!AttributeName!Directive
形式の部分の説明を次に示します。
ElementName
結果として得られる要素のジェネリック識別子です。 たとえば、 Customers が ElementName として指定されている場合、 <Customers> 要素が生成されます。
TagNumber
要素に割り当てられた一意のタグ値です。 この値は、 タグ と 親の 2 つのメタデータ列の助けを借りて、結果の XML 内の要素の入れ子を決定します。
AttributeName
指定した ElementName で構築する属性の名前を提供します。
ディレクティブが指定されていない場合の動作です。
ディレクティブが指定され、xml、cdata、または要素である場合、この値は ElementName の要素の子を構築するために使用され、列の値が追加されます。
ディレクティブを指定した場合、AttributeName は空にすることができます。 たとえば、ElementName!TagNumber!!指令。 この場合、列の値は ElementName に直接含まれます。
指令
ディレクティブ は省略可能であり、これを使用して XML の構築に関する追加情報を提供できます。
ディレクティブ には 2 つの目的があります。
目的の 1 つは、値を ID、IDREF、および IDREFS としてエンコードすることです。 ID、IDREF、および IDREFS キーワードをディレクティブとして指定できます。 これらのディレクティブは、属性の種類を上書きします。 これにより、ドキュメント内リンクを作成できます。
また、 ディレクティブ を使用して、文字列データを XML にマップする方法を指定することもできます。 hide、element、elementxsinil、xml、xmltext、および cdata キーワードをディレクティブとして使用できます。 hide ディレクティブはノードを非表示にします。 これは、並べ替えの目的でのみ値を取得するが、結果の XML には含めないようにする場合に便利です。
要素ディレクティブは、属性の代わりに包含要素を生成します。 含まれているデータはエンティティとしてエンコードされます。 たとえば、 < 文字は <になります。 NULL 列の値の場合、要素は生成されません。 null 列の値に対して要素を生成する場合は、 elementxsinil ディレクティブを指定できます。 これにより、属性 xsi:nil=TRUE を持つ要素が生成されます。
xml ディレクティブは要素ディレクティブと同じですが、エンティティ エンコードは行われません。 要素ディレクティブは ID、IDREF、または IDREFS と組み合わせることができますが、xml ディレクティブは hide 以外の他のディレクティブでは使用できません。
cdata ディレクティブには、CDATA セクションでラップすることでデータが含まれます。 コンテンツはエンティティエンコードされていません。 元のデータ型は、varchar、nvarchar、text、ntext などのテキスト型である必要があります。 このディレクティブは hide でのみ使用できます。 このディレクティブを使用する場合は、 AttributeName を 指定しないでください。
ほとんどの場合、これら 2 つのグループ間でディレクティブを組み合わせることは許可されますが、それらの間でディレクティブを組み合わせることは許可されません。
ディレクティブとAttributeNameが指定されていない場合、例えばCustomer!1があると、要素ディレクティブが暗黙のうちに指定された形となります。その結果、Customer!1!!elementのようになり、列データはElementNameに含まれています。
xmltext ディレクティブが指定されている場合、列の内容は、ドキュメントの残りの部分と統合された 1 つのタグでラップされます。 このディレクティブは、OPENXML によって列に格納されたオーバーフローの、未使用の XML データをフェッチする場合に便利です。 詳細については、「 OPENXML (SQL Server)」を参照してください。
AttributeName が指定されている場合、タグ名は指定した名前に置き換えられます。 それ以外の場合は、エンティティ エンコードなしでコンテインメントの先頭にコンテンツを配置することで、外側の要素の属性の現在のリストに属性が追加されます。 このディレクティブを持つ列は、varchar、nvarchar、char、nchar、text、ntext などのテキスト型である必要があります。 このディレクティブは hide でのみ使用できます。 このディレクティブは、列に格納されているオーバーフロー データをフェッチする場合に便利です。 コンテンツが整形式 XML でない場合、動作は未定義です。
このセクションにて
次の例は、EXPLICIT モードの使用方法を示しています。
こちらもご覧ください
FOR XML で RAW モードを使用する
FOR XML で AUTO モードを使用する
FOR XML で PATH モードを使用する
SELECT (Transact-SQL)
FOR XML (SQL Server)