C# で XML を手軽に読み込み

2020年1月14日

過去の記事「XML のすすめ」では、膨大な Excel のテーブルを XML に置き換えることのメリットについてお話ししました。ここで決め手となるのが、C# です。

今回は、C# で XML を読み込むコードがいかにシンプルかということをお見せします。

XML の例

Excel で表現された、次のような仕様書があったとします。

これを素直に XML に置き換えるなら、たとえば次のような表現になるでしょう。

<?xml version="1.0" encoding="UTF-8"?>
<価格表>
  <データ>
    <商品 言語="日本語">りんご</商品>
    <商品 言語="英語">Apple</商品>
    <単価>120</単価>
  </データ>
  <データ>
    <商品 言語="日本語">みかん</商品>
    <商品 言語="英語">Orange</商品>
    <単価>250</単価>
  </データ>
  <データ>
    <商品 言語="日本語">いちご</商品>
    <商品 言語="英語">Strawberry</商品>
    <単価>400</単価>
  </データ>
</価格表>

今回は、この XML を例にとって C# のコードを紹介していきます。

C# のコード

XML の取り扱いは、XDocument というクラスを使うのが最適です。コードの冒頭に、次の using 宣言を追加しておいてください。

using System.Xml.Linq;

.NET Framework には他にも XMLDocument や XMLReader といったクラスがありますが、後発の XDocument の使いやすさは断トツです。名前が似ていてややこしいので、ここは注意してください。

XML を読むのに必要なのは、次に挙げる5つの操作だけです。

1. XML をロードする

特定の XML ファイルをロードするコードは、こうです。

XDocument xml = XDocument.Load(@"C:\test.xml");

以降はこのインスタンスに対する操作が、XML に対する操作になります。面倒なファイルのオープン・クローズは要りません。

2. テーブルを読み込む

今回の例では、ルートに存在するテーブルの名前は「価格表」です。まずはこれを丸ごと読み込んでしまいましょう。そのコードがこちらです。

XElement table = xml.Element("価格表");

XElement とはその名の通り XML の一要素を表します。

3. 要素を読み込む

XML が再帰的な構造を持つのと同様、XElement クラスも再帰的な構造を持ちます。つまり、XElement のインスタンスから、その子要素である XElement が取り出せるのです。

ここで、「価格表」テーブルにぶら下がっている「データ」要素は複数ありますから、まずはこれらを複数のまま取り出します。

var rows = table.Elements("データ");

メソッド名が Elements と複数形になっている点に注意してください。これで、「データ」要素を並べたものが取り出せました。ということは、foreach 文を使うことで要素の数だけ回るループを書くことができます。

foreach (XElement row in rows)
{
  XElement item = row.Element("商品");
  XElement rate = row.Element("単価");
}

4. 値を取り出す

要素に付随する値そのもの、つまり今回の例でいう “りんご" や “120" の部分を取り出すには、XElement の Value というプロパティを使います。

string name = item.Value;   // "りんご"
string price = rate.Value;  // "120"

5. 属性を取り出す

今回の例では、「商品」要素に「言語」という属性が付いています。これを取り出すには Attribute というメソッドを使います。

XAttribute attr = item.Attribute("言語");

属性の右辺、すなわち “日本語" や “英語" に相当する部分は、このインスタンスの Value というプロパティに収められています。

string lang = attr.Value;  // "日本語"

まとめ

たったこれだけです。XDocument クラスが XML の面倒な部分を全部引き受けてくれていることがわかりますね。

これまでのコードを応用して一つにしたものを載せておきます。

var table = XDocument.Load(@"C:\test.xml").Element("価格表");

foreach (var row in table.Elements("データ"))
{
    foreach (var item in row.Elements("商品"))
    {
        switch (item.Attribute("言語").Value)
        {
        case "日本語":
            string jpn = item.Value;
            /* TODO */
            break;
        case "英語":
            string eng = item.Value;
            /* TODO */
            break;
        }
    }
    string price = row.Element("単価").Value;
    /* TODO */
}

XML の構造が複雑になるほど、このコードの構造も複雑になっていきますが、これらの操作の組み合わせであるという点は変わりません。

もう少し変わったことがやりたい場合は別のメソッドやプロパティが必要になりますが、Visual Studio に備わっているインテリセンスを駆使すれば何とかなってしまいます。ぜひ、試してみてください。