1. はじめに
XML — eXtensible Markup Language の略。とても厳格でおしゃべりな JSON を想像してみて。何度も「構造化されてるよ、信じて!」って言い続けるタイプのフォーマットだ。XML はデータをタグで囲むテキストフォーマットだ:
<Player>
<Name>Aragorn</Name>
<Health>100</Health>
</Player>
なぜ今 XML にオブジェクトをシリアライズするのか?
- XML は大規模な(しばしばレガシーな)システム間の統合で今でも広く使われていて、構造だけでなく厳密なスキーマ(XSD)によるバリデーションが必要な場面がある。
- 企業向け設定では XML がよく使われる(例: App.config や Web.config、古い世代の .NET など)。
- データ構造の「自己記述性」が重要な用途には XML が向いている。
興味深い事実: XML は最初から「拡張可能」でバリデーションしやすいように設計されている。だから名前にそれが表れているんだ。JSON には標準で同じレベルのスキーマ検査がない、という違いがあるよ。
XmlSerializer: 主役
.NET ではオブジェクトを XML にシリアライズするのはクラス System.Xml.Serialization.XmlSerializer が担当している。
- public なプロパティやフィールドを XML の要素に変換し、逆に XML からオブジェクトを復元する。
- 公開された型とメンバーだけを扱う(オープンな型/メンバーにしか対応しない)。
- private なフィールドやプロパティはシリアライズされない — 公開されているものだけだ。
- シリアライズ対象のクラスには、動作のためにパラメータなしの public コンストラクタが必要になる。
注意: クラスがこれらの要件に合致していないと、XmlSerializer はシリアライズ/デシリアライズの際に例外を投げて動作しないよ。
2. シンプルな例 — オブジェクトを XML にシリアライズする
まずはおなじみの Player クラスを XML にシリアライズする例を見てみよう。
ステップ 1. クラスを定義する
public class Player
{
public string Name { get; set; }
public int Health { get; set; }
public bool IsAlive { get; set; }
// 重要: パラメータなしの public コンストラクタが必要!
public Player() { }
// オプション: 便利のためのコンストラクタ
public Player(string name, int health, bool isAlive)
{
Name = name;
Health = health;
IsAlive = isAlive;
}
}
ステップ 2. ファイルにシリアライズする
using System.Xml.Serialization;
Player aragorn = new Player("Aragorn", 100, true);
// 1. Player 型用のシリアライザを作る
XmlSerializer serializer = new XmlSerializer(typeof(Player));
// 2. 書き込み用にファイルを開く(存在しなければ作成される)
using FileStream fs = new FileStream("player.xml", FileMode.Create);
// 3. オブジェクトを XML にシリアライズする
serializer.Serialize(fs, aragorn);
結果 (player.xml):
<?xml version="1.0"?>
<Player xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Aragorn</Name>
<Health>100</Health>
<IsAlive>true</IsAlive>
</Player>
簡単な処理の流れ図
メモリ上のオブジェクト ---> XmlSerializer.Serialize() ---> ディスク上の XML ファイル
3. デシリアライズ — XML からオブジェクトを復活させる
以前シリアライズしたオブジェクトを読み戻すときは、処理は逆になるよ:
using FileStream fs = new FileStream("player.xml", FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(Player));
Player player = (Player)serializer.Deserialize(fs);
Console.WriteLine($"名前: {player.Name}, 体力: {player.Health}, 生存: {player.IsAlive}");
結果はプログラムが次のように出力する: 名前: Aragorn, 体力: 100, 生存: True
4. 文字列へのシリアライズ — ファイルだけじゃない
文字列にシリアライズする
必ずしもファイルに書き出す必要はない。例えば XML をネットワークで送ったり、画面に表示したりしたいときは文字列にシリアライズすることが多い。
using System.IO;
using System.Xml.Serialization;
Player player = new Player("Frodo", 42, true);
XmlSerializer serializer = new XmlSerializer(typeof(Player));
StringWriter stringWriter = new StringWriter();
serializer.Serialize(stringWriter, player);
string xmlString = stringWriter.ToString();
Console.WriteLine(xmlString); // XML 全体の文字列が画面に出る!
文字列からのデシリアライズ
同様に、ファイルではなく文字列からデシリアライズすることもできる:
string xml = "<Player Name=\"Frodo\"><HP>42</HP></Player>";
XmlSerializer serializer = new XmlSerializer(typeof(Player));
using StringReader stringReader = new StringReader(xml);
Player frodo = (Player)serializer.Deserialize(stringReader);
Console.WriteLine(frodo.Name); // Frodo
5. XML のカスタマイズ:構造を制御するための属性
標準の振る舞いで満足できないこともある。生成される XML が冗長すぎたり、タグ名が期待と違ったりする場合、いくつかの「魔法の」属性を使ってシリアライザにどう表現するかを指示できる。
よく使うもの:
— 要素の名前を指定する。[XmlElement]
— フィールドを要素ではなく XML の属性にする。[XmlAttribute]
— プロパティをシリアライズから除外する。[XmlIgnore]
と[XmlArray]
— コレクションの包み方を制御する。[XmlArrayItem]
使用例:
public class Player
{
[XmlAttribute]
public string Name { get; set; }
[XmlElement("HP")]
public int Health { get; set; }
[XmlIgnore]
public bool IsTempSessionPlayer { get; set; }
}
生成される XML:
<Player Name="Aragorn">
<HP>100</HP>
</Player>
シリアライズでよく使う属性一覧
| 属性 | 影響 | 使用例 |
|---|---|---|
|
プロパティを XML の属性にする | |
|
タグ名を変更する | のように を置き換える |
|
そのプロパティをシリアライズから完全に除外する | — |
|
コレクションのラッパー名を変更する | |
|
コレクション内の各要素の名前を変更する | |
コレクションの複雑なシリアライズ例:
public class GameWorld
{
[XmlArray("Heroes")]
[XmlArrayItem("Hero")]
public List<Player> Players { get; set; } = new List<Player>();
}
XML:
<GameWorld>
<Heroes>
<Hero Name="Legolas">
<HP>90</HP>
</Hero>
<!-- ... -->
</Heroes>
</GameWorld>
XML のカスタマイズについては次回の講義でさらに詳しく扱うよ! :P
GO TO FULL VERSION