T-SQL: 名前空間が指定された XML からデータを取得する
名前空間が指定された XML
前回 「 T-SQL クエリーで XML をテーブル形式に変換する 」 では、名前空間の指定されていないシンプルな XML から値を取得する方法をご紹介しました。
XML に名前空間の指定があると、XML データ型メソッドを使う際にも、名前空間の指定が必要になります。
ここでは、名前空間が指定された XML からデータを取得する方法をご紹介します。
XML にデフォルトの名前空間のみが指定されているケース
まずは、XML デフォルトの名前空間のみが指定されているケースです。
「 T-SQL クエリーで XML をテーブル形式に変換する 」 で使った XML の Students エレメントに、デフォルトの名前空間 xmlns="https://sql55.com/Schemas/Students" を追加します。
<Students xmlns="https://sql55.com/Schemas/Students"> <Student ID="1"> <StudentInfo> <FirstName>Saki</FirstName> <LastName>Suzuki</LastName> </StudentInfo> <TestResultCount>2</TestResultCount> <ScoreAverage>92.00</ScoreAverage> </Student> <Student ID="2"> <StudentInfo> <FirstName>Miki</FirstName> <LastName>Sato</LastName> </StudentInfo> <TestResultCount>3</TestResultCount> <ScoreAverage>89.50</ScoreAverage> </Student> </Students>
接頭辞のついていない要素はデフォルトの名前空間に属していることになります。
XML にデフォルトの名前空間が宣言されていると、「 T-SQL クエリーで XML をテーブル形式に変換する 」 でご紹介したクエリーのままでは、XML からデータを取得できません。
デフォルトの名前空間を指定して、XML から値を取得するクエリーは次の通りです。
DECLARE @XMLData1 XML = '<Students xmlns="https://sql55.com/Schemas/Students"> <Student ID="1"> <StudentInfo> <FirstName>Saki</FirstName> <LastName>Suzuki</LastName> </StudentInfo> <TestResultCount>2</TestResultCount> <ScoreAverage>92.00</ScoreAverage> </Student> <Student ID="2"> <StudentInfo> <FirstName>Miki</FirstName> <LastName>Sato</LastName> </StudentInfo> <TestResultCount>3</TestResultCount> <ScoreAverage>89.50</ScoreAverage> </Student> </Students>'; WITH XMLNAMESPACES (DEFAULT 'https://sql55.com/Schemas/Students') SELECT T.C.value('@ID', 'INT') AS StudentID, T.C.value('(StudentInfo/FirstName)[1]', 'NVARCHAR(MAX)') AS FirstName, T.C.value('(StudentInfo/LastName)[1]', 'NVARCHAR(MAX)') AS LastName, T.C.value('TestResultCount[1]', 'INT') AS TestResultCount, T.C.value('ScoreAverage[1]', 'DECIMAL(5,2)') AS ScoreAverage FROM @XMLData1.nodes('/Students/Student') AS T(C);
[ 実行結果 ]
デフォルトの名前空間を指定するには WITH XMLNAMESPACES (DEFAULT 'XML名前空間のURI') を使います。
XML データ型メソッドの value() や nodes() の説明は 「 T-SQL クエリーで XML をテーブル形式に変換する 」 をご覧ください。
XML に複数の名前空間が指定されているケース
次は XML に複数の名前空間が指定されているケースです。
例えば、この XML では、デフォルトの名前空間 xmlns="https://sql55.com/Schemas/Students" の他に、ns1 という接頭辞で xmlns:ns1="https://test.com/Student" が指定されています。
1 個目と 3 個目の Student 要素は接頭辞がついていないのでデフォルトの名前空間 "https://sql55.com/Schemas/Students" に、 2 個目の Student は要素の前に ns1: がついているので "https://test.com/Student" の名前空間に属します。
<Students xmlns="https://sql55.com/Schemas/Students" xmlns:ns1="https://test.com/Student"> <Student ID="1"> <StudentInfo> <FirstName>Saki</FirstName> <LastName>Suzuki</LastName> </StudentInfo> <TestResultCount>2</TestResultCount> <ScoreAverage>92.00</ScoreAverage> </Student> <ns1:Student> <ns1:FirstName>Jun</ns1:FirstName> <ns1:LastName>Taguchi</ns1:LastName> <ns1:Gender>M</ns1:Gender> <ns1:ScoreAverage>85.64</ns1:ScoreAverage> </ns1:Student> <Student ID="2"> <StudentInfo> <FirstName>Miki</FirstName> <LastName>Sato</LastName> </StudentInfo> <TestResultCount>3</TestResultCount> <ScoreAverage>89.50</ScoreAverage> </Student> </Students>
この XML から名前空間を指定して、データを取得するクエリーは以下の通りです。
DECLARE @XMLData2 XML = '<Students xmlns="https://sql55.com/Schemas/Students" xmlns:ns1="https://test.com/Student"> <Student ID="1"> <StudentInfo> <FirstName>Saki</FirstName> <LastName>Suzuki</LastName> </StudentInfo> <TestResultCount>2</TestResultCount> <ScoreAverage>92.00</ScoreAverage> </Student> <ns1:Student> <ns1:FirstName>Jun</ns1:FirstName> <ns1:LastName>Taguchi</ns1:LastName> <ns1:Gender>M</ns1:Gender> <ns1:ScoreAverage>85.64</ns1:ScoreAverage> </ns1:Student> <Student ID="2"> <StudentInfo> <FirstName>Miki</FirstName> <LastName>Sato</LastName> </StudentInfo> <TestResultCount>3</TestResultCount> <ScoreAverage>89.50</ScoreAverage> </Student> </Students>'; WITH XMLNAMESPACES (DEFAULT 'https://sql55.com/Schemas/Students') SELECT T.C.value('@ID', 'INT') AS StudentID, T.C.value('(StudentInfo/FirstName)[1]', 'NVARCHAR(MAX)') AS FirstName, T.C.value('(StudentInfo/LastName)[1]', 'NVARCHAR(MAX)') AS LastName, T.C.value('TestResultCount[1]', 'INT') AS TestResultCount, T.C.value('ScoreAverage[1]', 'DECIMAL(5,2)') AS ScoreAverage FROM @XMLData2.nodes('/Students/Student') AS T(C); WITH XMLNAMESPACES ('https://test.com/Student' AS NS, DEFAULT 'https://sql55.com/Schemas/Students') SELECT T.C.value('NS:FirstName[1]', 'NVARCHAR(MAX)') AS FirstName, T.C.value('NS:LastName[1]', 'NVARCHAR(MAX)') AS LastName, T.C.value('NS:Gender[1]', 'NVARCHAR(1)') AS TestResultCount, T.C.value('NS:ScoreAverage[1]', 'DECIMAL(5,2)') AS ScoreAverage FROM @XMLData2.nodes('/Students/NS:Student') AS T(C);
[ 実行結果 ]
一つ目のクエリーはデフォルトの名前空間のみが指定されている時のクエリーと同じです。
名前空間の接頭辞がついていない 1 個目と 3 個目の Student 要素の値のみが取得されます。 2 個目の Student は名前空間がマッチしないので取得されません。
二つ目のクエリーは WITH XMLNAMESPACES で、名前空間を二つ指定しています。 AS NS の NS 部分はエイリアスなので他の文字でも大丈夫です。
XQuery のパス式を指定する際に ns1: の接頭辞のついている要素には NS: を指定します。
@XMLData2.nodes('/Students/NS:Student') で NS の名前空間の Student 要素を行セットとして取得しています。
'https://test.com/Student' 名前空間に属する、2 個目の Student 要素の値のみが取得されていますね。