の続きです。
@ch3cooh たびたびもうしわけないのですが、例えば
- の配下の要素のみを変数に代入する方法はあるのでしょうか?属性値が一致する要素のみを抜き出したいのです <<
LINQを使いましょう!
XML内に
得られる型がIEnumerable
|cs| // item要素の属性が"2"であるもの全てを取り出す IEnumerable
selItems = items.Where(el => el.Attribute("no") != null && el.Attribute("no").Value == "2"); foreach (var item in selItems) { var name = item.Element("name").Value; System.Diagnostics.Debug.WriteLine(name); } ||<
先ほどIEnumerable
|cs| // item要素の属性が"2"のうち最初のものを取り出す XElement item = items.Where(el => el.Attribute("no") != null && el.Attribute("no").Value == "2").First(); var name = item.Element("name").Value; System.Diagnostics.Debug.WriteLine(name); ||<
条件に一致する要素が1件しかないと決まっている場合は、Singleメソッドで取り出すのも良いかもしれません。
取得時に結果が1件では無い場合に例外が発生しますので、上手く例外を拾って対応してください。
|cs| // item要素の属性が"2"であるものを1つだけ取り出す XElement selectItem = null; try { selectItem = items.Single(item => item.Attribute("no") != null && item.Attribute("no").Value == "2"); } catch { // 1つもない場合、2つ以上ある場合は例外が発生する } var name = selectItem.Element("name").Value; ||<
** 10/17 追記
MS MVP for VC#の@neuecc先生に教えて頂きました。
LINQ to XMLちょっとTips。 el.Attributet("no").Value == "2" じゃなくて (string)el.Attribute("no") == "2" と比較するとnullチェックが不要になるのだ! http://t.co/59dSggJr
— neuecc (@neuecc) 2011年10月14日
テストに使ったのは以下のXMLテキストです。
|cs| string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + "
"; ||< - " + "
割りと普通 しばやん
な、なんだってー!「el.Attribute("no") != null」でチェックしている理由です。
全てのitem要素にno属性が含まれている場合は問題ないのですが、下記のように最初のitem要素のno属性を削った場合、el.Attribute("no")でnullが返ってきます。
結果的にnullオブジェクトのValueプロパティを参照してしまい、NullReferenceExceptionが発生します。それを回避する為に属性の値を取得する前に「el.Attribute("no") != null」で、no属性が存在しているかどうかをチェックしていました。
|cs| // item要素の属性が"2"であるもの全てを取り出す IEnumerable
selItems = items.Where(el => (string)el.Attribute("no") == "2"); ||<
おぉ、コードがシンプルになった……さらにno属性をint型で比較したい場合についてのテクニックも教えてもらえました。
ちなみにNoなんかだと直接intに戻したかったりする場合も多いと思いますが、(int)el.Attribute("no") とやる場合はnullチェックが必要になるのでその辺はまぁ適当に。
— neuecc (@neuecc) 2011年10月14日
あ、もし0にしたい場合でも、 items.Select(el => (int?)el.Attribute("no") ?? 0) とすればint[]になるので、int?じゃなくてintが欲しい時でも、これがベストですね。気づいてなかったけど今度から採用で。
— neuecc (@neuecc) 2011年10月14日
??演算子を使って、no属性が無い場合に0として扱い、int型の2と比較しています。
|cs| // item要素の属性が"2"であるもの全てを取り出す IEnumerable
selItems = items.Where(el => ((int?)el.Attribute("no") ?? 0) == 2); ||<
今までのプロジェクトのコードでも、xmlを扱っている箇所は沢山あるので、もう少しシンプルなコードが書けそうです。