.NET(C#)でXMLを扱うにはいくつかの方法があるが、'LINQ to XML'を使うと簡潔に書けそうだ。
今回、Unity上で'LINK to XML'を動かしてみた。Unityバージョンは、2017.2。
XMLサンプルファイル
XMLのサンプルは、次を使う。
<?xml version="1.0" encoding="utf-8"?> <persons> <person> <name yomi="はりそんふぉーど">Harrison Ford</name> <birth>1942-07-13</birth> <works> <title>Star Wars</title> <title>Blade Runner</title> </works> </person> <person> <name yomi="みふねとしろう">三船敏郎</name> <birth>1920-04-01</birth> <works> <title>七人の侍</title> <title>天国と地獄</title> <title>羅生門</title> </works> </person> <person> <name yomi="じゃんぎゃばん">Jean Gabin</name> <birth>1904-05-17</birth> <works> <title>ヘッドライト</title> <title>地下室のメロディー</title> <title>暗黒街のふたり</title> </works> </person> </persons>
LINQ to XML
をUsingしておく。
手順としては、
XDocument
クラスのLoad
静的メソッドでXMLファイルを読み込む。XDocument
インスタンスのRoot.Elements()
メソッドで、トップ階層のタグ要素のコレクション(IEnumerable)を作成する。- さらに下層の要素を取り出すには、
Elements(タグ名)
orElement(タグ名)
メソッドを入れ子にし、タグ要素クラス(XElement)を取得する。 - アトリビュートがある場合は、XElementインスタンスの
Attribute(アトリビュート名)
メソッドで、アトリビュートクラスを取得する。 - タグ要素、アトリビュート要素ともに、
Value
プロパティで、値を文字列として取り出す
となる。
文章で書くとわかりにくいが、次のサンプルコードを見れば理解するのはそう難しくないと思う。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Linq; using System.Xml.Linq; namespace XOOMS.IO { public class XMLLinq : MonoBehaviour { //LINQを使ってXMLファイルを解析する [SerializeField] string xmlFileName = "actors.xml"; [SerializeField] string tagName0 = "name"; [SerializeField] string attribute01 = "yomi"; [SerializeField] string tagName1 = "birth"; [SerializeField] string tagName2 = "works"; [SerializeField] string tagName20 = "title"; void Start() { XDocument xdoc = XDocument.Load(Application.dataPath + "/" + xmlFileName); IEnumerable<XElement> xelements = xdoc.Root.Elements(); //ルート直下の要素のコレクション foreach (var xelement in xelements) { XElement xelem0 = xelement.Element(tagName0); //タグtagNames[0]の要素 XAttribute xattr01 = xelem0.Attribute(attribute01); //タグ0のアトリビュートを取り出す XElement xelem1 = xelement.Element(tagName1); //タグtagNames[1]の要素 //XElement.Valueで値を取り出す Debug.Log(string.Format("{0}:{1} ({2}), {3}:{4}", tagName0, xelem0.Value, xattr01.Value, tagName1, xelem1.Value )); } } } }
これを実行すると、次のように出力される。
name:Harrison Ford (はりそんふぉーど), birth:1942-07-13 name:三船敏郎 (みふねとしろう), birth:1920-04-01 name:Jean Gabin (じゃんぎゃばん), birth:1904-05-17
なお、対応するタグやアトリビュートがない場合、XElement, XAttributeはnullになる。nullオブジェクトの.Valueプロパティにアクセスするとエラーになるので、実際の利用では各要素を取り出した後にnullチェックを入れたほうがいい。
取得条件を加える
ある条件を満たす要素だけを取り出すことも、LINQ to XMLを使えば簡潔に書ける。
条件の記述は、Where
メソッドを使う。
たとえば、生年が1920年以降の人物だけを抽出するには、xelementsの抽出箇所に、次のように条件を追記する。
IEnumerable<XElement> xelements = xdoc.Root.Elements() .Where(x => ((DateTime)x.Element(tagName1)).Year >= 1920); //生年が1920年以降の要素のみ抽出する
要素を並べ替える
ある要素の値で並べ替えるには、OrderBy
メソッドを使う。
たとえば、よみがな順に並べ替えるには、
IEnumerable<XElement> xelements = xdoc.Root.Elements() .OrderBy(x => (string)(x.Element(tagName0).Attribute(attribute01))); //よみがなで並べ替え
OrderBy()
は昇順に並べ替える。降順に並べ借るには、.OrderByDescending()
メソッドを使う。
入れ子になった要素を取得する
入れ子になった要素の取得は、Element(親要素の名前).Elements(子要素の名前)と数珠繋ぎにしていけばいい。
上のXMLサンプルファイルで、各俳優の代表作はworksの子のtitleに書かれている。これを取得するには次のようにする。
foreach (var xelement in xelements) { //入れ子になった要素を取得 IEnumerable<string> selems2 = xelement.Element(tagName2) //works要素 .Elements(tagName20) //works要素の下のtitle要素 .Select(x => x.Value) ; //title要素の値のコレクション foreach (string selem2 in selems2) { Debug.Log(string.Format("title: {0}", selem2)); } }
上の例では、LINQのSelect
メソッドを使って、一挙に作品名のstringまで取得しているが、先の例のようにIEnumerable<XElement>
の取得をして、その後のforeach内でValueを取り出してもよい。
XMLの階層構造を考えずに子孫要素を取り出す
前の例では、「works要素の子のtitle要素」と階層構造が分かったうえで要素を取り出したが、このような階層構造を考えずに、とにかくある名前の要素をすべて取り出すこともできる。これには、Descendants
メソッドを使う。
IEnumerable<XElement> xtitles = xdoc.Root.Descendants(tagName20); //Root下の"title'タグを再帰的にすべて取り出す foreach(XElement xtitle in xtitles) { Debug.Log(string.Format("title: {0}", xtitle.Value)); }
LINQのSelect
メソッドを使って、次のようにも書ける。
IEnumerable<string> titles = xdoc.Root.Descendants(tagName20) .Select(x => x.Value); foreach(string title in titles) { Debug.Log(string.Format("title: {0}", title)); }
参考資料
今回の記事は、出井秀行著「実戦で役立つC#プログラミングのイデオム/定石&パターン」の第11章、「XMLファイルの操作」を参考にした。
実戦で役立つ C#プログラミングのイディオム/定石&パターン
- 作者: 出井秀行
- 出版社/メーカー: 技術評論社
- 発売日: 2017/02/18
- メディア: 大型本
- この商品を含むブログ (1件) を見る