|  |  | 
 
| 連載:[完全版]究極のC#プログラミングChapter18 LINQ to XML川俣 晶2010/05/06
 |  | 
| 
 | 
18.5 LINQ to XMLというブレークスルー
 その答えは、ズバリ「LINQ to XML」ということになる。LINQ to XMLとは、LINQというフレームワークをXMLに対応させたもの……という理解では不十分である。それは、単なるクエリのフレームワークを超えて、XML文書を扱うAPIそのものの大幅な改善手段として用意されている。
 ただし、E4Xのように、言語仕様にXML対応を組み込むほどの過激さは見せていない。言語仕様はあくまでXMLに対して、独立を貫いている。だが、その範囲内で可能な限りコンパクトにソースコードを記述できるように、さまざまな工夫が凝らされている。
 実際に、上記のリスト18.1やリスト18.2と同じ機能を記述したサンプルコード、リスト18.5を見てみよう。
| 
 
| using System;using System.Collections.Generic;
 using System.Linq;
 using System.Xml.Linq;
 
 class Program
 {
 (XML文書の定義はリスト18.1と同じなので省略)
 
 static void Main(string[] args)
 {
 var doc = XElement.Parse(xmldoc);
 XNamespace ex =
 "http://www.piedey.co.jp/example/linqtoxml200811";
 
 var query = from n in doc.Descendants(ex + "name")
 where n.Attribute("id").Value == "M"
 select n;
 
 foreach (var elem in query)
 {
 Console.WriteLine(elem.Value);
 }
 }
 }
 
 |  | 
| リスト18.5 LINQ to XMLでリスト18.1を書き直した例 | 
 まず、長い名前がコード上から消えたことを確認しよう。最も長いものが「Descendants」の11文字、次が「XNamespace」の10文字である。この程度なら、長さで苦痛を感じることはない。ちなみに、Descendantsメソッドは、子孫要素のうち指定された名前の要素を列挙する機能を持つ。この場合は、ドキュメントのルート要素以外のすべての要素が対象になる。
 次に、暗黙の型変換や演算子のオーバーロードが活用されている点に注意を払おう。たとえば、次の行はURIが含まれている文字列をXNamespace型オブジェクト(XML名前空間を保持するオブジェクト)に変換するXNamespaceクラスのImplicit演算子によって動作する。
| 
 
| XNamespace ex = "http://www.piedey.co.jp/example/linqtoxml200811";
 |  | 
 この記述のメリットは、XPath式を使った例で、これに相当する次のような行と比較するとわかるだろう。
| 
 
| nsmgr.AddNamespace("ex", "http://www.piedey.co.jp/example/linqtoxml200811");
 
 |  | 
 そう。ここでexというキーワードは、文字列ではなく変数名になったのである。ということは、名前の不整合はコンパイル時にチェック可能となったのである。
 もう1つ、リスト18.5の「ex + "name"」という部分にも注目してほしい。これは足し算を行っているわけではなく、XNamespaceオブジェクトとローカル名を結合して、XName(XMLで使われる名前を保持するオブジェクト)を作成するXNamespaceクラスのAddition演算子を実行させているものである。つまり、「名前空間URI+ローカル名」を持つ名前オブジェクトを作り出しているわけである。
 これを見て、「加算を意味する『+』をそれ以外の目的で使うのはソースコードの直感的なわかりやすさを損なうからイカン」と怒り心頭の読者も多いと思うが、そのように脊髄反射的に怒るのは早計というものだ。
 なぜなら、この「名前の生成」という処理は大量に書き込む可能性が高いからだ。それゆえに次のことが要求される。
- 出現回数が多いので、書く手間が少なく、簡潔な表現が望ましい
- 扱う回数が多いので、プログラマーはすぐに表記に慣れる。予備知識なしで見たときのわかりやすさよりも、簡潔さが優先される
- 頻出する表記なので書き間違いが入り込む可能性も高い。より的確なエラーチェックができるとよい
- 名前の生成はたいていの場合、本質的に重要な処理ではない。したがって、重要な処理が目立つよう、シンプルな表記が好ましい
 具体的に次ページのリスト18.6の例を見ると、このような説明の趣旨がなんとなくわかるのではないかと思う。これは、LINQ to XMLのAPIを用いてXML文書を生成するサンプルである。
| 
 
| using System;using System.Xml.Linq;
 
 class Program
 {
 static void Main(string[] args)
 {
 XNamespace ex =
 "http://www.piedey.co.jp/example/linqtoxml200811";
 
 XElement doc =new XElement(ex + "person",
 new XElement(ex + "name", "Wong Fei Fong"),
 new XElement(ex + "age", "18"),
 new XElement(ex + "address", "Village of Lahan")
 );
 Console.WriteLine(doc.ToString());
 }
 }
 
 |  | 
| リスト18.6 名前を生成する「+」の多用 | 
| 
 
| <person xmlns="http://www.piedey.co.jp/example/linqtoxml200811"><name>Wong Fei Fong</name>
 <age>18</age>
 <address>Village of Lahan</address>
 </person>
 
 |  | 
| リスト18.6の実行結果 | 
 名前を生成する「+」は4回出現しているが、いずれも異なる結果を得るためのもので、生成した値を使い回すことはできない。つまり、名前の生成処理の回数そのものは減らすことはできない。逆に、これらの名前生成は、あくまで主役ではなく「new XElement」で生成される要素の名前指定としての役割を果たすだけである。簡潔に目立たず、書き間違えれば確実にエラーを出力する役割を担って記述されている。
 このように、実際に手を動かしてコードを記述し続けるという状況から見れば、+演算子で名前を生成する仕掛けは使い勝手が良いのである。
 しかし、このサンプルコードにはもう1つ別の見どころがある。おそらく、DOMに精通したプログラマーであれば、このコードはかなり意外性があると思う。この結果を得るにしては、あまりにも簡潔すぎるのである。
 
 
 
	
		Insider.NET 記事ランキング
		
		
			本日
			月間