質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

2回答

2716閲覧

C# XMLファイルの特定要素の最大値

uppi

総合スコア6

XML

XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2020/01/08 08:00

前提・実現したいこと

XMLファイルをインポートし、teammembers要素の数値が最大の要素を抽出し、コンソール画面に表示させたいのですが、エラーが出てしまい、実行中に例外が発生しました。
XMLファイル内に、ballsport要素が3つあり、そのそれぞれに、teammembers要素が含まれています。
やりたいことは、teammembers要素の数値が最大のballsport要素を抽出し、name要素とteammembers要素をコンソール画面に表示することです。
Maxメソッドがあるので、それを使って上手くクラスやディクショナリークラスを経ずにXDocumentクラスやXElementクラスを使って上記操作を実現したいです。
よろしくお願いします。

発生している問題・エラーメッセージ

System.NullReferenceException: 'Object reference not set to an instance of an object.' MaxMembers が null でした。

該当のソースコード

C#

1 static void Main(string[] args) 2 { 3 var xdoc = XDocument.Load(@"C:\Users\lifeg\Desktop\ballsports.xml"); 4 5 var MaxMembers = xdoc.Root.Elements("teammembers").Max(); 6 7 Console.WriteLine("{0} {1}",MaxMembers.Element("name").Value,MaxMembers.Element("teammembers").Value); 8 }

XML

1<?xml version="1.0" encoding="UTF-8"?> 2<ballSports> 3 <ballsport> 4 <name kanji="籠球">バスケットボール</name> 5 <teammembers>5</teammembers> 6 <firstplayed>1891</firstplayed> 7 </ballsport> 8 <ballsport> 9 <name kanji="排球">バレーボール</name> 10 <teammembers>6</teammembers> 11 <firstplayed>1895</firstplayed> 12 </ballsport> 13 <ballsport> 14 <name kanji="野球">ベースボール</name> 15 <teammembers>9</teammembers> 16 <firstplayed>1846</firstplayed> 17 </ballsport> 18</ballSports>

試したこと

匿名クラスに一度格納してから、並べ替えることはできましたが、XML自体がすでに構造化されているので、なんとかXDocumentクラスやXElementクラスで表示する方法を模索しています。

補足情報(FW/ツールのバージョンなど)

Microsoft Visual Studio Community 2019
Version 16.4.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2020/01/08 08:44

最大の要素が複数個あった場合はどうしますか?
uppi

2020/01/08 09:17

追記ありがとうございます。 その場合は、最初に見つかった要素だけとかではなく、すべてコンソールに画面に表示したいです。
guest

回答2

0

ベストアンサー

csharp

1var maxVal = xdoc.Descendants("teamnumber").Select(e=>int.Parse(e.Value)).Max().ToString(); 2xdoc.Descendants("ballsports").Where(e=>e.Element("teamnumber").Value == maxVal).ToList().ForEach(e=>Console.WriteLine(e));

投稿2020/01/08 09:31

編集2020/01/08 09:42
papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

papinianus

2020/01/08 09:42

ForEachがListだったきがする、を他の回答みて思った。ぱくりました
TN8001

2020/01/08 09:46

あぁなるほど別々に探せばいいんですね^^; var maxVal = xdoc.Descendants("teammembers").Select(e => int.Parse(e.Value)).Max().ToString(); xdoc.Descendants("ballsport").Where(e => e.Element("teammembers").Value == maxVal).ToList().ForEach(e => Console.WriteLine("{0} {1}", e.Element("name").Value, e.Element("teammembers").Value));
papinianus

2020/01/08 10:00

他にはOrderByDescendingして、出力時に前の要素と比較して最大値である間出力とかですかね。 必ずteamnumberの種類が2種類あることが保証されるならOrderByDeacendingしたものをOrderByDescendingして1つSkipしたものをZipすればスコープ外の変数を参照しなくて済みそうですがトリッキーすぎるかと思いました。
uppi

2020/01/08 10:45

papinianusさん 回答ありがとうございます。 シンプルかつ分かりやすいコードが気に入りました。 ベストアンサーにさせていただきます。 私も早く、このようなコードが、さささっと書けるようになりたいです。
uppi

2020/01/08 12:20

上記回答を参考にして下記の通りコードが完成しました。 自分への備忘録を兼ねてここに掲載します。 var xdoc = XDocument.Load(filepath); var MaxNumber = xdoc.Descendants("teammembers").Select(e => int.Parse(e.Value)).Max().ToString(); var MaxMembers= xdoc.Root.Elements().Where(e => e.Element("teammembers").Value == MaxNumber); foreach (var item in MaxMembers) { Console.WriteLine("{0} {1}", item.Element("name").Value, item.Element("teammembers").Value); }
guest

0

大げさすぎる気がしますが、本体部分はすっきりしていますよね?w
LINQを駆使すれば拡張メソッド部分なしで何とかなるとは思いますが、私は苦手なのでわかりません^^;

cs

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Xml.Linq; 5 6namespace Questions233905 7{ 8 class Program 9 { 10 static void Main() 11 { 12 var xdoc = XDocument.Load(@"ballsports.xml"); 13 var MaxMembers = xdoc.Root.Elements().MaxBy(x => int.Parse(x.Element("teammembers").Value)); 14 MaxMembers.ToList().ForEach(x => Console.WriteLine("{0} {1}", x.Element("name").Value, x.Element("teammembers").Value)); 15 } 16 } 17 18 // https://qiita.com/Zuishin/items/95e171eccc128bdd6429 19 static class IEnumerableExtensions 20 { 21 //public static IEnumerable<T> MinBy<T, U>(this IEnumerable<T> source, Func<T, U> selector) 22 // => SelectBy(source, selector, (a, b) => Comparer<U>.Default.Compare(a, b) < 0); 23 public static IEnumerable<T> MaxBy<T, U>(this IEnumerable<T> source, Func<T, U> selector) 24 => SelectBy(source, selector, (a, b) => Comparer<U>.Default.Compare(a, b) > 0); 25 private static IEnumerable<T> SelectBy<T, U>(IEnumerable<T> source, Func<T, U> selector, Func<U, U, bool> comparer) 26 { 27 var list = new LinkedList<T>(); 28 var prevKey = default(U); 29 foreach(var item in source) 30 { 31 var key = selector(item); 32 if(list.Count == 0 || comparer(key, prevKey)) 33 { 34 list.Clear(); 35 list.AddLast(item); 36 prevKey = key; 37 } 38 else if(Comparer<U>.Default.Compare(key, prevKey) == 0) 39 { 40 list.AddLast(item); 41 } 42 } 43 return list; 44 } 45 } 46}

投稿2020/01/08 09:36

編集2023/08/15 15:26
TN8001

総合スコア9326

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

uppi

2020/01/08 10:43

TN8001さん 回答ありがとうございます。 特にMaxbyメソッドについては知らなかったので参考になりました。 やはり、Linqやラムダ式は便利だとはおもうのですが、難しいですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問