スポンサーリンク

Linq to XML 入門 その4 結合(JOIN)

しばらく間が開いてしまいすいませんです。前回は基本的なクエリーまで説明したので、今回からはもう少し複雑なクエリー式の説明をします。

今回はJOINを説明します。

JOIN(結合)はLinqにおいてもリレーショナルデータベースの結合と同じく一定の条件の下データ同士を関連付けます。

結合(Join)の概念がちょっとわかりにくいという方はSQLの入門書で結合(Join)について勉強してみるといいと思います。このJOINあたりからが実際にはLinqの非常に強力な使用方法になっていきます。リレーショナルデータベースのデータでもないものを簡単な書式でJoinできるというのは実はすごいことなのです。

説明に当たっては、どこかにあるかもしれないレストランを想定し、メニューのカテゴリが記述されたcategory.xmlとメニューのアイテムが記述されたmenu.xmlを使用します。アプリケーションとしてはこれら二つのXMLデータを結合(JOIN)して、メニューのリストを作ります。

各XMLデータは以下の通りで、ここからダウンロードすることもできます。

menu.xml

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<menu>
<span class="angelscript"> </span><item menuid="1" categoryid="1"><span class="angelscript">
</span><name><span class="angelscript">コーラ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">250</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="2" categoryid="1"><span class="angelscript">
</span><name><span class="angelscript">アイスコーヒー</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">250</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="3" categoryid="1"><span class="angelscript">
</span><name><span class="angelscript">ブレンドコーヒー</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">250</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="4" categoryid="1"><span class="angelscript">
</span><name><span class="angelscript">生ビール</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">400</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="5" categoryid="2"><span class="angelscript">
</span><name><span class="angelscript">フレンチフライ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">400</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="6" categoryid="2"><span class="angelscript">
</span><name><span class="angelscript">湯で海老</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">800</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="7" categoryid="2"><span class="angelscript">
</span><name><span class="angelscript">チーズ盛り合わせ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">1350</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="8" categoryid="2"><span class="angelscript">
</span><name><span class="angelscript">オニオングラタンスープ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">1050</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="9" categoryid="2"><span class="angelscript">
</span><name><span class="angelscript">シェフのお任せミニサラダ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">870</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="9" categoryid="2"><span class="angelscript">
</span><name><span class="angelscript">シェフのお任せスープ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">870</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="10" categoryid="3"><span class="angelscript">
</span><name><span class="angelscript">御殿場高原で育った子羊のロースト</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">1800</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="11" categoryid="3"><span class="angelscript">
</span><name><span class="angelscript">あしたか牛のフィレ肉を使ったビーフシチュー</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">2500</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="12" categoryid="3"><span class="angelscript">
</span><name><span class="angelscript">沼津港スズキのグリル</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">2300</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="12" categoryid="3"><span class="angelscript">
</span><name><span class="angelscript">焼津マグロのカルパッチョ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">2300</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="13" categoryid="3"><span class="angelscript">
</span><name><span class="angelscript">あしたか牛のサーロインステーキ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">3200</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="14" categoryid="4"><span class="angelscript">
</span><name><span class="angelscript">韮山苺を使ったショートケーキ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">650</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="15" categoryid="4"><span class="angelscript">
</span><name><span class="angelscript">西浦みかんのババロワ</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">550</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span><item menuid="15" categoryid="4"><span class="angelscript">
</span><name><span class="angelscript">朝霧高原の牛乳から作ったティラミス</span></name><span class="angelscript">
</span><price><span class="angelscript"><span class="hljs-number">550</span></span></price><span class="angelscript">
</span></item><span class="angelscript">
</span></menu>
<menu> <span class="angelscript"> </span><item menuid="1" categoryid="1"><span class="angelscript"> </span><name><span class="angelscript">コーラ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">250</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="2" categoryid="1"><span class="angelscript"> </span><name><span class="angelscript">アイスコーヒー</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">250</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="3" categoryid="1"><span class="angelscript"> </span><name><span class="angelscript">ブレンドコーヒー</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">250</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="4" categoryid="1"><span class="angelscript"> </span><name><span class="angelscript">生ビール</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">400</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="5" categoryid="2"><span class="angelscript"> </span><name><span class="angelscript">フレンチフライ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">400</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="6" categoryid="2"><span class="angelscript"> </span><name><span class="angelscript">湯で海老</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">800</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="7" categoryid="2"><span class="angelscript"> </span><name><span class="angelscript">チーズ盛り合わせ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">1350</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="8" categoryid="2"><span class="angelscript"> </span><name><span class="angelscript">オニオングラタンスープ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">1050</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="9" categoryid="2"><span class="angelscript"> </span><name><span class="angelscript">シェフのお任せミニサラダ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">870</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="9" categoryid="2"><span class="angelscript"> </span><name><span class="angelscript">シェフのお任せスープ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">870</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="10" categoryid="3"><span class="angelscript"> </span><name><span class="angelscript">御殿場高原で育った子羊のロースト</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">1800</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="11" categoryid="3"><span class="angelscript"> </span><name><span class="angelscript">あしたか牛のフィレ肉を使ったビーフシチュー</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">2500</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="12" categoryid="3"><span class="angelscript"> </span><name><span class="angelscript">沼津港スズキのグリル</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">2300</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="12" categoryid="3"><span class="angelscript"> </span><name><span class="angelscript">焼津マグロのカルパッチョ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">2300</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="13" categoryid="3"><span class="angelscript"> </span><name><span class="angelscript">あしたか牛のサーロインステーキ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">3200</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="14" categoryid="4"><span class="angelscript"> </span><name><span class="angelscript">韮山苺を使ったショートケーキ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">650</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="15" categoryid="4"><span class="angelscript"> </span><name><span class="angelscript">西浦みかんのババロワ</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">550</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span><item menuid="15" categoryid="4"><span class="angelscript"> </span><name><span class="angelscript">朝霧高原の牛乳から作ったティラミス</span></name><span class="angelscript"> </span><price><span class="angelscript"><span class="hljs-number">550</span></span></price><span class="angelscript"> </span></item><span class="angelscript"> </span></menu>

  
    コーラ
    250
  
  
    アイスコーヒー
    250
  
  
    ブレンドコーヒー
    250
  
  
    生ビール
    400
  
  
    フレンチフライ
    400
  
  
    湯で海老
    800
  
  
    チーズ盛り合わせ
    1350
  
  
    オニオングラタンスープ
    1050
  
  
    シェフのお任せミニサラダ
    870
  
  
    シェフのお任せスープ
    870
  
  
    御殿場高原で育った子羊のロースト
    1800
  
  
    あしたか牛のフィレ肉を使ったビーフシチュー
    2500
  
  
    沼津港スズキのグリル
    2300
  
  
    焼津マグロのカルパッチョ
    2300
  
  
    あしたか牛のサーロインステーキ
    3200
  
  
    韮山苺を使ったショートケーキ
    650
  
  
    西浦みかんのババロワ
    550
  
  
    朝霧高原の牛乳から作ったティラミス
    550
  

category.xml

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<categories>
<category id="1">
<categoryname>飲料</categoryname>
</category>
<category id="2">
<categoryname>前菜</categoryname>
</category>
<category id="3">
<categoryname>主菜</categoryname>
</category>
<category id="4">
<categoryname>デザート</categoryname>
</category>
</categories>
<categories> <category id="1"> <categoryname>飲料</categoryname> </category> <category id="2"> <categoryname>前菜</categoryname> </category> <category id="3"> <categoryname>主菜</categoryname> </category> <category id="4"> <categoryname>デザート</categoryname> </category> </categories>

  
    飲料
  
  
    前菜
  
  
    主菜
  
  
    デザート
  

それではアプリケーションのコードです。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
XDocument menu = XDocument.<span class="hljs-constructor">Load(@<span class="hljs-string">"..\..\menu.xml"</span>)</span>;
XDocument category = XDocument.<span class="hljs-constructor">Load(@<span class="hljs-string">"..\..\category.xml"</span>)</span>;
var menuList = from m <span class="hljs-keyword">in</span> menu.<span class="hljs-constructor">Descendants(<span class="hljs-string">"item"</span>)</span>
join c <span class="hljs-keyword">in</span> category.<span class="hljs-constructor">Descendants(<span class="hljs-string">"Category"</span>)</span>
on
(<span class="hljs-built_in">string</span>)m.<span class="hljs-constructor">Attribute(<span class="hljs-string">"CategoryId"</span>)</span>
equals
(<span class="hljs-built_in">string</span>)c.<span class="hljs-constructor">Attribute(<span class="hljs-string">"id"</span>)</span>
select <span class="hljs-keyword">new</span> {
MenuId = (<span class="hljs-built_in">string</span>)m.<span class="hljs-constructor">Attribute(<span class="hljs-string">"MenuId"</span>)</span>,
MenuName = (<span class="hljs-built_in">string</span>)m.<span class="hljs-constructor">Element(<span class="hljs-string">"name"</span>)</span>,
CategoryName = (<span class="hljs-built_in">string</span>)c.<span class="hljs-constructor">Element(<span class="hljs-string">"CategoryName"</span>)</span>,
Price = (<span class="hljs-built_in">int</span>)m.<span class="hljs-constructor">Element(<span class="hljs-string">"price"</span>)</span>
};
foreach (var m <span class="hljs-keyword">in</span> menuList) {
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"お料理\t\t{0}"</span>, <span class="hljs-params">m</span>.MenuName)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"お料理の種類\t{0}"</span>, <span class="hljs-params">m</span>.CategoryName)</span>;
Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"お値段\t\t{0}"</span>, <span class="hljs-params">m</span>.Price.ToString()</span>);
}
Console.<span class="hljs-constructor">ReadLine()</span>;
XDocument menu = XDocument.<span class="hljs-constructor">Load(@<span class="hljs-string">"..\..\menu.xml"</span>)</span>; XDocument category = XDocument.<span class="hljs-constructor">Load(@<span class="hljs-string">"..\..\category.xml"</span>)</span>; var menuList = from m <span class="hljs-keyword">in</span> menu.<span class="hljs-constructor">Descendants(<span class="hljs-string">"item"</span>)</span> join c <span class="hljs-keyword">in</span> category.<span class="hljs-constructor">Descendants(<span class="hljs-string">"Category"</span>)</span> on (<span class="hljs-built_in">string</span>)m.<span class="hljs-constructor">Attribute(<span class="hljs-string">"CategoryId"</span>)</span> equals (<span class="hljs-built_in">string</span>)c.<span class="hljs-constructor">Attribute(<span class="hljs-string">"id"</span>)</span> select <span class="hljs-keyword">new</span> { MenuId = (<span class="hljs-built_in">string</span>)m.<span class="hljs-constructor">Attribute(<span class="hljs-string">"MenuId"</span>)</span>, MenuName = (<span class="hljs-built_in">string</span>)m.<span class="hljs-constructor">Element(<span class="hljs-string">"name"</span>)</span>, CategoryName = (<span class="hljs-built_in">string</span>)c.<span class="hljs-constructor">Element(<span class="hljs-string">"CategoryName"</span>)</span>, Price = (<span class="hljs-built_in">int</span>)m.<span class="hljs-constructor">Element(<span class="hljs-string">"price"</span>)</span> }; foreach (var m <span class="hljs-keyword">in</span> menuList) { Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"お料理\t\t{0}"</span>, <span class="hljs-params">m</span>.MenuName)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"お料理の種類\t{0}"</span>, <span class="hljs-params">m</span>.CategoryName)</span>; Console.<span class="hljs-constructor">WriteLine(<span class="hljs-string">"お値段\t\t{0}"</span>, <span class="hljs-params">m</span>.Price.ToString()</span>); } Console.<span class="hljs-constructor">ReadLine()</span>;
XDocument menu = XDocument.Load(@"..\..\menu.xml");
XDocument category = XDocument.Load(@"..\..\category.xml");
 
var menuList = from m in menu.Descendants("item")
               join c in category.Descendants("Category")
               on
                (string)m.Attribute("CategoryId")
               equals
                (string)c.Attribute("id")
               select new {
                   MenuId = (string)m.Attribute("MenuId"),
                   MenuName = (string)m.Element("name"),
                   CategoryName = (string)c.Element("CategoryName"),
                   Price = (int)m.Element("price")
               };

foreach (var m in menuList) {
    Console.WriteLine("お料理\t\t{0}", m.MenuName);
    Console.WriteLine("お料理の種類\t{0}", m.CategoryName);
    Console.WriteLine("お値段\t\t{0}", m.Price.ToString());
}
 
Console.ReadLine();

1,2行目でXML文書を読み込みます。

5行目から今回新しく説明するポイントです。

5行目のjoin句で、4行目のfrom句でmenu.xmlから取り出したxmlのエレメントに結合するcategory.xmlのエレメントを指定します。

6行目からon句から始まり9行目までが結合条件で、この場合にはmenu.xml側が持つCategoryIdアトリビュートの値とcategory.xmlがもつidアトリビュートの一致をもって結合するようにしています。アトリビュート同士の値が同値であることの確認には"="(オペレータ)ではなくequals句を使う必要があります。正確には

from <左辺XML>

join <右辺XML>

on <左辺条件> equals <右辺条件>

となります。

今回示した例は内部結合(Inner Join)と呼ばれる結合方法です。左辺側(今回であればmenu.xml)と右辺側(Categoryxml)の両方で条件が一致したデータのみが結果として返されます。これ以外にLinqでは右辺のデータと一致するものが無くても左辺のデータをすべて返す左外部結合(Outer Join)もサポートしています。左外部結合に関しては以下のMSDNドキュメントを参考にしてください。

join 句 - C# reference
join 句 - C# リファレンス

それではまた次回!

これまでの記事:

参考図書:

Essential LINQ (Microsoft .NET Development Series)
Essential LINQ (Microsoft .NET Development Series) Charlie Calvert

Addison-Wesley Professional 2009-03-22

売り上げランキング : 109833

Amazonで詳しく見る by G-Tools

プログラミングMicrosoft LINQ (マイクロソフト公式解説書 Microsoft Visual Studi)
プログラミングMicrosoft LINQ (マイクロソフト公式解説書 Microsoft Visual Studi) 小高 太郎 (株)オーパス・ワン

日経BPソフトプレス 2009-05-25

売り上げランキング : 43591

Amazonで詳しく見る by G-Tools

コメント

  1. OPC Diary より:

    Linq to XML 入門その1 (XML文書の作り方)

    準備 これから数回に分けてLinq to XMLの基礎的な使い方についてまとめ…

タイトルとURLをコピーしました