WITH XMLNAMESPACES を使用してクエリに名前空間を追加する

適用対象:yesSQL Server (サポートされているすべてのバージョン) YesAzure SQL Database YesAzure SQL Managed Instance

WITH XMLNAMESPACES (Transact-SQL) は、次の方法で名前空間 URI のサポートを提供します。

FOR XML クエリで WITH XMLNAMESPACES を使用する

WITH XMLNAMESPACES を使用すると、FOR XML クエリに XML 名前空間を含めることができます。 たとえば、次の FOR XML クエリについて考えてみます。

SELECT ProductID, Name, Color
FROM   Production.Product
WHERE  ProductID IN (316, 317)
FOR XML RAW;

結果を次に示します。

<row ProductID="316" Name="Blade" />
<row ProductID="317" Name="LL Crankarm" Color="Black" />

FOR XML クエリにより構築された XML に名前空間を追加するには、まず WITH NAMESPACES 句を使用して URI マッピングの名前空間プレフィックスを指定します。 次に、名前空間プレフィックスを使用して、次に示す変更後のクエリのように、クエリに名前を指定します。 WITH XMLNAMESPACES 句は、名前空間プレフィックス () から URI (ns1uri) へのマッピングを指定します。 FOR XML クエリにより構築された要素名と属性名を指定する際に ns1 プレフィックスを使用します。

WITH XMLNAMESPACES ('uri' as ns1)
SELECT ProductID as 'ns1:ProductID',
       Name      as 'ns1:Name',
       Color     as 'ns1:Color'
FROM  Production.Product
WHERE ProductID IN (316, 317)
FOR XML RAW ('ns1:Prod'), ELEMENTS;

結果の XML には、指定した名前空間プレフィックスが含まれています。

<ns1:Prod xmlns:ns1="uri">
  <ns1:ProductID>316</ns1:ProductID>
  <ns1:Name>Blade</ns1:Name>
</ns1:Prod>
<ns1:Prod xmlns:ns1="uri">
  <ns1:ProductID>317</ns1:ProductID>
  <ns1:Name>LL Crankarm</ns1:Name>
  <ns1:Color>Black</ns1:Color>
</ns1:Prod>

WITH XMLNAMESPACES 句には、次の制約があります。

  • FOR XML クエリの RAW、AUTO、PATH モードしかサポートしていません。 EXPLICIT モードはサポートされていません。

  • FOR XML クエリの名前空間プレフィックスおよび xml データ型メソッドにしか影響しません。XML パーサーには影響しません。 たとえば、次のクエリは、XML ドキュメントで myNS プレフィックスの名前空間が宣言されていないため、エラーを返します。

  • WITH XMLNAMESPACES 句が使用されている場合は、FOR XML ディレクティブ、XMLSCHEMA、XMLDATA を使用できません。

    CREATE TABLE T (x xml);
    GO
    WITH XMLNAMESPACES ('https://abc' as myNS )
    INSERT INTO T VALUES('<myNS:root/>');
    GO
    

XSINIL ディレクティブを使用する

ELEMENTS XSINIL ディレクティブを使用している場合、WITH XMLNAMESPACES 句で xsi プレフィックスを定義することはできません。 代わりに、ELEMENTS XSINIL を使用すると自動的に追加されます。 次のクエリは、要素中心型の XML を生成する ELEMENTS XSINIL を使用しています。生成された XML では、NULL 値が xsi:nil 属性が True に設定されている要素にマップされます。

WITH XMLNAMESPACES ('uri' as ns1)
SELECT ProductID as 'ns1:ProductID',
       Name      as 'ns1:Name',
       Color     as 'ns1:Color'
FROM Production.Product
WHERE ProductID = 316
FOR XML RAW, ELEMENTS XSINIL;

結果を次に示します。

<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns1="uri">
  <ns1:ProductID>316</ns1:ProductID>
  <ns1:Name>Blade</ns1:Name>
  <ns1:Color xsi:nil="true" />
</row>

既定の名前空間を指定する

名前空間プレフィックスを宣言する代わりに、DEFAULT キーワードを使用して既定の名前空間を宣言することもできます。 DEFAULT キーワードは、FOR XML クエリ中で、既定の名前空間を結果の XML の XML ノードにバインドします。 次の例では、WITH XMLNAMESPACES によって、2 つの名前空間プレフィックスを同時に 1 つの既定の名前空間に定義しています。

WITH XMLNAMESPACES ('uri1' as ns1,
                    'uri2' as ns2,
                    DEFAULT 'uri2')
SELECT ProductID,
      Name,
      Color
FROM Production.Product
WHERE ProductID IN (316, 317)
FOR XML RAW ('ns1:Product'), ROOT('ns2:root'), ELEMENTS;

この FOR XML クエリは、要素中心の XML を生成します。 このクエリでは、名前付けノードで両方の名前空間プレフィックスが使用されます。 SELECT 句では、ProductID、Name、Color にプレフィックスが付いた名前は指定されません。 その結果、結果の XML の対応する要素は、既定の名前空間に属することになります。

<ns2:root xmlns="uri2" xmlns:ns2="uri2" xmlns:ns1="uri1">
  <ns1:Product>
    <ProductID>316</ProductID>
    <Name>Blade</Name>
  </ns1:Product>
  <ns1:Product>
    <ProductID>317</ProductID>
    <Name>LL Crankarm</Name>
    <Color>Black</Color>
  </ns1:Product>
</ns2:root>

次のクエリは前のクエリとほぼ同じですが、FOR XML AUTO モードが指定されています。

WITH XMLNAMESPACES ('uri1' as ns1,  'uri2' as ns2,DEFAULT 'uri2')
SELECT ProductID,
      Name,
      Color
FROM Production.Product as "ns1:Product"
WHERE ProductID IN (316, 317)
FOR XML AUTO, ROOT('ns2:root'), ELEMENTS;

定義済みの名前空間の使用

事前定義された名前空間を使用する場合は、ELEMENTS XSINIL 使用時の xml 名前空間と xsi 名前空間を除き、WITH XMLNAMESPACES を使用して名前空間のバインドを明示的に指定する必要があります。 次のクエリは、事前定義された名前空間 (urn:schemas-microsoft-com:xml-sql) 用に、URI の名前空間プレフィックスのバインドを明示的に定義しています。

WITH XMLNAMESPACES ('urn:schemas-microsoft-com:xml-sql' as sql)
SELECT 'SELECT * FROM Customers FOR XML AUTO, ROOT("a")' AS "sql:query"
FOR XML PATH('sql:root');

結果は次のとおりです。 SQLXML では、この XML テンプレートがよく使用されます。 詳細については、「 SQLXML 4.0 のプログラミング概念」を参照してください。

<sql:root xmlns:sql="urn:schemas-microsoft-com:xml-sql">
  <sql:query>SELECT * FROM Customers FOR XML AUTO, ROOT("a")</sql:query>
</sql:root>

次の PATH モード クエリで示すように、WITH XMLNAMESPACES を使用して明示的に定義せずに使用できる名前空間プレフィックスは xml のみです。 また、プレフィックスが宣言されている場合は、 http://www.w3.org/XML/1998/namespace 名前空間にバインドする必要があります。 SELECT 句で指定された名前は、WITH XMLNAMESPACES を使用して明示的に定義されていない xml 名前空間プレフィックスを参照します。

SELECT 'en'    as "English/@xml:lang",
       'food'  as "English",
       'ger'   as "German/@xml:lang",
       'Essen' as "German"
FOR XML PATH ('Translation');
GO

@xml:lang 属性は、事前定義された xml 名前空間を使用します。 XML バージョン 1.0 では xml 名前空間バインディングの明示的な宣言は必要ないため、結果には名前空間バインディングの明示的な宣言は含まれません。

結果を次に示します。

<Translation>
  <English xml:lang="en">food</English>
  <German xml:lang="ger">Essen</German>
</Translation>

XML データ型メソッドで WITH XMLNAMESPACES を使用する

SELECT クエリで指定された xml データ型メソッド 、またはメソッドの場合は modify() UPDATE で指定された xml データ型メソッドは、すべてプロローグで名前空間宣言を繰り返す必要があります。 この作業には時間のかかる場合があります。 たとえば、次のクエリでは、カタログの説明に仕様が含まれる製品モデル ID を取得します。 つまり、要素が <Specifications> 存在します。

SELECT ProductModelID, CatalogDescription.query('
declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
    <Product
        ProductModelID= "{ sql:column("ProductModelID") }"
        />
') AS Result
FROM Production.ProductModel
WHERE CatalogDescription.exist('
    declare namespace  pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";
     /pd:ProductDescription[(pd:Specifications)]'
    ) = 1;

前のクエリでは、両方のexist()メソッドがquery()プロローグで同じ名前空間を宣言しています。 次に例を示します。

declare namespace pd="https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription";

代わりに、WITH XMLNAMESPACES を最初に宣言して、名前空間プレフィックスをクエリで使用することもできます。 この場合、メソッド query()exist() メソッドは、プロローグに名前空間宣言を含める必要はありません。

WITH XMLNAMESPACES ('https://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelDescription' as pd)
SELECT ProductModelID, CatalogDescription.query('
    <Product
        ProductModelID= "{ sql:column("ProductModelID") }"
        />
') AS Result
FROM Production.ProductModel
WHERE CatalogDescription.exist('
     /pd:ProductDescription[(pd:Specifications)]'
    ) = 1;
GO

XQuery プロローグの明示的な宣言は、WITH 句で定義されている名前空間プレフィックスと既定の要素名前空間をオーバーライドします。

関連項目