FOR XML での EXPLICIT モードの使用
適用対象: SQL Server Azure SQL データベース Azure SQL Managed Instance
この記事「FOR XML を使用した XML の構築」で説明されているように、RAW モードと AUTO モードでは、クエリ結果から生成される XML の形状をあまり制御できません。 一方、EXPLICIT モードを使用すると、クエリ結果から生成される XML の構造を柔軟に制御することができます。
ただし、必要な XML に関する追加情報 (XML 内の入れ子構造など) をクエリの一部として明示的に指定するために、EXPLICIT モードのクエリを記述する際には特殊な記述方法が必要になります。 このため、要求する XML によっては、EXPLICIT モードのクエリを記述する作業が複雑になることがあります。 EXPLICIT モードのクエリを記述するよりも、 PATH モード で入れ子を使用する方が作業が容易になる場合もあります。
EXPLICIT モードでは、目的の XML をクエリによって記述するので、正しい形式で有効な XML が生成されるかどうかを確認する必要があります。
EXPLICIT モードでの行セット処理
EXPLICIT モードでは、クエリを実行した結果として生じた行セットが XML に変換されます。 EXPLICIT モードで XML ドキュメントを作成するには、特殊な形式の行セットが必要になります。 そのためには、XML を処理ロジックで生成できるように、決められた形式の行セット ( ユニバーサル テーブル) を生成できるような選択クエリを記述する必要があります。
まず、クエリで次の 2 つのメタデータ列を生成します。
1 列目は Tagという名前で、現在の要素のタグ番号 (整数型) を指定します。 行セットから構築される要素ごとに、一意のタグ番号をクエリが提供しなければなりません。
2 列目は Parentという名前で、親要素のタグ番号を指定します。 これにより、Tag 列と Parent 列の階層情報が定義されます。
XML を生成する際には、これらのメタデータ列の値が、列名の情報と共に使用されます。 クエリでは、特定の方法で列名を指定する必要があります。 Parent 列の値が 0 または NULL であれば、その要素に親要素がないことを示します。 このような要素は、最上位の要素として XML に追加されます。
クエリで生成したユニバーサル テーブルが、どのように処理され、XML として生成されるか、例を検証しましょう。ここでは、次のユニバーサル テーブルを生成するクエリを記述したとします。
このユニバーサル テーブルについて説明します。
最初の 2 列は Tag 列と Parent 列で、これらはメタデータ列です。 これらの値は、階層を決定します。
列名は、この記事で後述するように、特定の方法で指定します。
このユニバーサル テーブルから XML を生成する際、このテーブルのデータは列方向に (列グループに) パーティション分割されます。 このグループ化は、 Tag 列の値と列名によって決まります。 XML の生成時には、各行ごとに 1 つの列グループが選択され、1 つの要素が構築されます。 この処理は、この例では次のように行われます。
1 行目の Tag 列の値は 1 なので、同じタグ番号を列名に含んでいる Customer!1!cid 列と Customer!1!name列でグループが形成されます。 これらの列は行の処理に使用され、生成される要素の形状が
<Customer id=... name=...>
であることがわかります。 列名の形式については、この記事で後述します。Tag (タグ) 列の値が 2 の行の場合、列 Order!2!id と Order!2!date は、要素
<Order id=... date=... />
の構築に使用されるグループを形成します。Tag 列の値が 3 の行については、 OrderDetail!3!id!id 列と OrderDetail!3!pid!idref 列でグループが形成されます。 これらの行のそれぞれは、これらの列から要素
<OrderDetail id=... pid=...>
を生成します。
XML 階層の生成では、行は順番に処理されます。 XML 階層は、次のように決定されます。
1 行目では、 Tag 列に値 1 が指定され、 Parent 列には NULL が指定されています。 したがって、対応する
<Customer>
要素が XML の最上位要素として追加されます。<Customer cid="C1" name="Janine">
2 行目では、 Tag 列に値 2、 Parent 列に値 1 が指定されています。 したがって、
<Customer>
要素の子要素として、<Order>
要素が追加されます。<Customer cid="C1" name="Janine"> <Order id="O1" date="1/20/1996">
次の 2 行では、 Tag 列に値 3、 Parent 列に値 2 が指定されています。 したがって、
<Order>
要素の子要素として、2 つの<OrderDetail>
要素が追加されます。<Customer cid="C1" name="Janine"> <Order id="O1" date="1/20/1996"> <OrderDetail id="OD1" pid="P1"/> <OrderDetail id="OD2" pid="P2"/>
最後の行では、 Tag 列に値 2 が指定され、 Parent 列には値 1 が指定されています。 したがって、
<Customer>
親要素には、別の<Order>
子要素が追加されます。<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 モードでは、 Tag メタデータ列と Parent メタデータ列の値、各列名に提供されている情報、および列の正しい順序に基づいて、必要な XML を生成できるということになります。
ユニバーサル テーブル行の順序付け
XML の生成時、ユニバーサル テーブルの行は順番に処理されます。 そのため、親と関連付けられている適切な子インスタンスを取得するには、各親ノードの直後がその親の子ノードになるという順序で、行セットの行が並んでいる必要があります。
ユニバーサル テーブルで列名を指定する
EXPLICIT モードのクエリを記述する際に、結果の行セットの列名は、この形式を使用して指定します。 列名では、ディレクティブを使用して、要素と属性の名前や他の追加情報などを含めた変換情報を指定します。
次に一般的な形式を示します。
ElementName!TagNumber!AttributeName!Directive
各部分の説明は、次のとおりです。
ElementName
結果として得られる要素のジェネリック識別子。 たとえば、ElementName として Customers が指定されている場合、
<Customers>
要素が生成されます。TagNumber
要素に割り当てられた一意のタグ値。 この値と Tag および Parentの 2 つのメタデータ列の組み合わせにより、生成される XML 内の要素の入れ子構造が決定されます。
AttributeName
指定した ElementName要素に作成する属性の名前。 これは、Directive (ディレクティブ) を指定しない場合の動作です。
Directive に xml、 cdata、または elementのいずれかが指定されている場合、この値は ElementName要素の子要素の構築に使用され、列値がその子要素に追加されます。
Directiveを指定した場合、 AttributeName は省略できます。 たとえば、ElementName!TagNumber!!Directive という形式を指定したとします。 この場合、列値は、 ElementNameに直接格納されます。
Directive
Directive は、XML を生成するための追加情報を指定する場合に使用しますが、省略可能です。 Directive には、2 つの目的があります。
1 つ目の目的は、値を ID、IDREF、および IDREFS としてエンコードすることです。 それには、 Directivesとして、 ID、 IDREF 、および IDREFSキーワードを指定します。 これらのディレクティブを指定すると、属性の型が上書きされます。 これにより、ドキュメント内でのリンクを作成できるようになります。
Directive を使用する 2 つ目の目的は、文字列データをどのように XML にマップするかを指定することです。 Directiveとしては、 hide、 element、elementxsinil、 xml、 xmltext 、 cdataの各キーワードを使用できます。 hide ディレクティブを指定した場合は、ノードが非表示になります。 このディレクティブは、ノードを並べ替えるだけの目的で値を取得し、生成する XML にはその値を表示しない場合に役立ちます。
element ディレクティブを指定すると、属性ではなく子要素 (含まれる要素) が生成されます。 含まれる要素のデータは、エンティティとしてエンコードされます。 たとえば、文字 < は <になります。 列の値が NULL であれば、要素は生成されません。 列の値が NULL である場合にも要素を生成する場合は、 elementxsinil ディレクティブを指定します。 このディレクティブを指定すると、xsi:nil=TRUE 属性を持つ要素が生成されます。
xml ディレクティブは、 element ディレクティブと似ていますが、エンティティのエンコードが行われない点が異なります。 要素 ディレクティブは ID、IDREF、または IDREFS と組み合わせることができますが、xml ディレクティブは hide 以外の他のディレクティブでは許可されません。
cdata ディレクティブを使用した場合は、データが CDATA セクション内に取り込まれます。 CDATA セクションの内容については、エンティティのエンコードが行われません。 元のデータ型は、 varchar、 nvarchar、 text、または ntextなどのテキスト型でなければなりません。 このディレクティブと組み合わせて使用できるのは、 hideディレクティブだけです。 このディレクティブを使用する場合、 AttributeName は指定できません。
これら 2 つのグループ間のディレクティブの組み合わせは、ほとんどの場合許可されますが、同じグループ内のディレクティブを組み合わせることは許可されません。
Directive (ディレクティブ) と AttributeName が指定されていない場合を考えます。たとえば、Customer!1 の場合、Customer!1!!element のように 要素 ディレクティブが暗黙的に指定され、列のデータが ElementName に格納されます。
xmltext ディレクティブを指定すると、列の内容は 1 つのタグで囲まれ、ドキュメントの残りの部分に統合されます。 このディレクティブは、OPENXML によって列に格納されている未使用のオーバーフロー XML データを収集する場合に役に立ちます。 詳細については、「OPENXML (SQL Server)」を参照してください。
AttributeName を指定した場合、タグ名は指定した名前に置き換えられます。 それ以外の場合、属性は囲み要素の現在の属性リストに追加され、内容は囲み要素の内容として先頭に追加されます。このとき、エンティティのエンコードは行われません。 このディレクティブを指定する列は、 varchar、 nvarchar、 char、 nchar、 text、または ntextなどのテキスト型でなければなりません。 このディレクティブと組み合わせて使用できるのは、 hideディレクティブだけです。 このディレクティブは、列に格納されているオーバーフロー データを収集する場合に役立ちます。 内容が整形式の XML でない場合、動作は未定義です。
次のステップ
次の例では、EXPLICIT モードの使用方法を示します。
- 例: 従業員情報の取得
- 例 : ELEMENT ディレクティブの指定
- 例 : ELEMENTXSINIL ディレクティブの指定
- 例: EXPLICIT モードを使用した兄弟の構築
- 例 : ID ディレクティブと IDREF ディレクティブの指定
- 例 : ID ディレクティブと IDREFS ディレクティブの指定
- 例 : HIDE ディレクティブの指定
- 例 : ELEMENT ディレクティブとエンティティのエンコードを指定する
- 例 : CDATA ディレクティブの指定
- 例: XMLTEXT ディレクティブの指定