ここではXmlSerializerを使ってシリアライズする場合の動作の制御について解説します。

なお、この文章ではXMLスキーマ定義ツールについては踏み込みません。 必要に応じて他のドキュメントを参照してください。

シリアライズ対象からの除外 (XmlIgnoreAttribute)

XmlIgnoreAttributeを使用すると、フィールドをシリアライズ対象から除外することが出来ます。 XmlSerializerではパブリックなフィールド・プロパティをシリアライズしようとしますが、シリアライズする必要の無いフィールドや実行時のみに使用されるフィールドなどは、この属性を使用することでシリアライズしないようにすることが出来ます。

以下の例では、Account.LastLoginフィールドにXmlIgnoreAttributeを付与しています。 デシリアライズ後にAccount.LastLoginフィールドの値が復元されていない点に注目してください。

using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

public class Account {
  public int ID;
  public string Name;

  [XmlIgnore]
  public DateTime LastLogin;

  // デフォルトコンストラクタ
  public Account() {}

  public override string ToString()
  {
    return string.Format("{0}:{1} LastLogin={2}", ID, Name, LastLogin);
  }
}

class Sample {
  static void Main()
  {
    Account alice = new Account();

    alice.ID = 2;
    alice.Name = "Alice";
    alice.LastLogin = new DateTime(2010, 10, 20);

    Console.WriteLine(alice);

    // シリアライズ
    using (Stream stream = File.OpenWrite("alice.xml")) {
      XmlSerializer serializer = new XmlSerializer(alice.GetType());

      serializer.Serialize(stream, alice);
    }

    // デシリアライズ
    using (Stream stream = File.OpenRead("alice.xml")) {
      XmlSerializer serializer = new XmlSerializer(typeof(Account));

      Account deserialized = (Account)serializer.Deserialize(stream);

      Console.WriteLine(deserialized);
    }
  }
}
Imports System
Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization

Public Class Account
  Public ID As Integer
  Public Name As String

  <XmlIgnore> _
  Public LastLogin As DateTime

  ' デフォルトコンストラクタ
  Public Sub New()
  End Sub

  Public Overrides Function ToString() As String
    Return String.Format("{0}:{1} LastLogin={2}", ID, Name, LastLogin)
  End Function
End Class

Class Sample
  Shared Sub Main()
    Dim alice As New Account()

    alice.ID = 2
    alice.Name = "Alice"
    alice.LastLogin = New DateTime(2010, 10, 20)

    Console.WriteLine(alice)

    ' シリアライズ
    Using stream As Stream = File.OpenWrite("alice.xml")
      Dim serializer As New XmlSerializer(alice.GetType())

      serializer.Serialize(stream, alice)
    End Using

    ' デシリアライズ
    Using stream As Stream = File.OpenRead("alice.xml")
      Dim serializer As New XmlSerializer(GetType(Account))

      Dim deserialized As Account = CType(serializer.Deserialize(stream), Account)

      Console.WriteLine(deserialized)
    End Using
  End Sub
End Class
実行結果
2:Alice LastLogin=2010/10/20 0:00:00
2:Alice LastLogin=0001/01/01 0:00:00
alice.xmlに出力される内容
<?xml version="1.0"?>
<Account xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ID>2</ID>
  <Name>Alice</Name>
</Account>

クラス・フィールドのXML要素名の指定 (XmlElementAttribute, XmlTypeAttribute, XmlRootAttribute)

XmlElementAttributeElementNameを指定することで、シリアライズの際に出力されるフィールドのXML要素の名前を指定することが出来ます。 この属性を指定しない場合は、フィールド名が要素名のデフォルトとして使用されます。

また、XmlTypeAttributeTypeNameもしくはXmlRootAttributeElementNameを指定することで、型のXML要素の名前を指定することが出来ます。 この属性を指定しない場合は、型名が要素名のデフォルトとして使用されます。 XmlRootAttributeとXmlTypeAttributeの違いは、XmlRootAttributeは型がルート要素となったときの要素名を指定するのに対し、XmlTypeAttributeは型がルート要素となるかどうかに関わらず要素名を指定するという点です。 なお、これらのプロパティはいずれも、名前付きパラメータとして指定することも属性のコンストラクタで指定することも出来ます。

以下の例では、AccountクラスにXmlRootAttribute、Account.NameフィールドとLastLoginフィールドにXmlElementAttributeを付与しています。 シリアライザが出力するXMLファイルの要素名が指定した名前に変わっている点に注目してください。

using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

[XmlRoot("アカウント情報")]
public class Account {
  public int ID;

  [XmlElement("名前")]
  public string Name;

  [XmlElement("最終ログイン日時")]
  public DateTime LastLogin;

  // デフォルトコンストラクタ
  public Account() {}

  public override string ToString()
  {
    return string.Format("{0}:{1} LastLogin={2}", ID, Name, LastLogin);
  }
}

class Sample {
  static void Main()
  {
    Account alice = new Account();

    alice.ID = 2;
    alice.Name = "Alice";
    alice.LastLogin = new DateTime(2010, 10, 20);

    Console.WriteLine(alice);

    // シリアライズ
    using (Stream stream = File.OpenWrite("alice.xml")) {
      XmlSerializer serializer = new XmlSerializer(alice.GetType());

      serializer.Serialize(stream, alice);
    }

    // デシリアライズ
    using (Stream stream = File.OpenRead("alice.xml")) {
      XmlSerializer serializer = new XmlSerializer(typeof(Account));

      Account deserialized = (Account)serializer.Deserialize(stream);

      Console.WriteLine(deserialized);
    }
  }
}
Imports System
Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization

<XmlRoot("アカウント情報")> _
Public Class Account
  Public ID As Integer

  <XmlElement("名前")> _
  Public Name As String

  <XmlElement("最終ログイン日時")> _
  Public LastLogin As DateTime

  ' デフォルトコンストラクタ
  Public Sub New()
  End Sub

  Public Overrides Function ToString() As String
    Return String.Format("{0}:{1} LastLogin={2}", ID, Name, LastLogin)
  End Function
End Class

Class Sample
  Shared Sub Main()
    Dim alice As New Account()

    alice.ID = 2
    alice.Name = "Alice"
    alice.LastLogin = New DateTime(2010, 10, 20)

    Console.WriteLine(alice)

    ' シリアライズ
    Using stream As Stream = File.OpenWrite("alice.xml")
      Dim serializer As New XmlSerializer(alice.GetType())

      serializer.Serialize(stream, alice)
    End Using

    ' デシリアライズ
    Using stream As Stream = File.OpenRead("alice.xml")
      Dim serializer As New XmlSerializer(GetType(Account))

      Dim deserialized As Account = CType(serializer.Deserialize(stream), Account)

      Console.WriteLine(deserialized)
    End Using
  End Sub
End Class
alice.xmlに出力される内容
<?xml version="1.0"?>
<アカウント情報 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <ID>2</ID>
  <名前>Alice</名前>
  <最終ログイン日時>2010-10-20T00:00:00</最終ログイン日時>
</アカウント情報>

クラス・フィールドのXML名前空間の指定 (XmlElementAttribute, XmlTypeAttribute, XmlRootAttribute)

XML要素名の他に、XmlElementAttribute.NamespaceXmlTypeAttribute.NamespaceXmlRootAttribute.Namespaceを指定することで、シリアライズの際に出力されるXML要素の名前空間を指定することが出来ます。 これらのプロパティはコンストラクタでは指定出来ないため、いずれも名前付きパラメータとして指定する必要があります。 また、これらの属性で指定した名前空間のプレフィックスを制御するには、XmlSerializerNamespacesを使用します。 名前空間のプレフィックスは、XmlSerializer.SerializeメソッドにXmlSerializerNamespacesを指定することで有効になります。

以下の例では、Accountクラスに対して上記の属性を付与し、シリアライズの際のXML名前空間を指定しています。 先の例とは異なり、Listに格納したAccountをシリアライズするため、XmlRootAttributeではなくXmlTypeAttributeを指定しています。 また、XmlSerializerNamespacesを使って名前空間のプレフィックスを指定しています。 シリアライザが出力するXMLファイルの各要素の名前空間が指定した値に変わっている点に注目してください。

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

[XmlType("アカウント情報", Namespace = "http://example.com/ns/account")]
public class Account {
  [XmlElement(Namespace = "http://example.com/ns/account")]
  public int ID;

  [XmlElement("名前", Namespace = "http://example.com/ns/account")]
  public string Name;

  [XmlElement("最終ログイン日時", Namespace = "http://example.com/ns/account/extensions")]
  public DateTime LastLogin;

  // デフォルトコンストラクタ
  public Account() {}

  public override string ToString()
  {
    return string.Format("{0}:{1} LastLogin={2}", ID, Name, LastLogin);
  }
}

class Sample {
  static void Main()
  {
    List<Account> accounts = new List<Account>();

    accounts.Add(new Account() {ID = 2, Name = "Alice",   LastLogin = new DateTime(2010, 10, 20)});
    accounts.Add(new Account() {ID = 0, Name = "Charlie", LastLogin = new DateTime(2010, 11, 20)});
    accounts.Add(new Account() {ID = 1, Name = "Eve",     LastLogin = new DateTime(2010, 12, 20)});

    foreach (Account e in accounts) {
      Console.WriteLine(e);
    }

    // シリアライズ
    using (Stream stream = File.OpenWrite("accounts.xml")) {
      XmlSerializer serializer = new XmlSerializer(accounts.GetType());
      XmlSerializerNamespaces ns = new XmlSerializerNamespaces();

      ns.Add("ac", "http://example.com/ns/account");
      ns.Add("acex", "http://example.com/ns/account/extensions");

      serializer.Serialize(stream, accounts, ns);
    }

    // デシリアライズ
    using (Stream stream = File.OpenRead("accounts.xml")) {
      XmlSerializer serializer = new XmlSerializer(typeof(List<Account>));

      List<Account> deserialized = (List<Account>)serializer.Deserialize(stream);

      Console.WriteLine("[deserialized]");

      foreach (Account e in deserialized) {
        Console.WriteLine(e);
      }
    }
  }
}
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization

<XmlType("アカウント情報", Namespace := "http://example.com/ns/account")> _
Public Class Account
  <XmlElement(Namespace := "http://example.com/ns/account")> _
  Public ID As Integer

  <XmlElement("名前", Namespace := "http://example.com/ns/account")> _
  Public Name As String

  <XmlElement("最終ログイン日時", Namespace := "http://example.com/ns/account/extensions")> _
  Public LastLogin As DateTime

  ' デフォルトコンストラクタ
  Public Sub New()
  End Sub

  Public Overrides Function ToString() As String
    Return String.Format("{0}:{1} LastLogin={2}", ID, Name, LastLogin)
  End Function
End Class

Class Sample
  Shared Sub Main()
    Dim accounts As New List(Of Account)

    accounts.Add(New Account() With {.ID = 2, .Name = "Alice",   .LastLogin = New DateTime(2010, 10, 20)})
    accounts.Add(New Account() With {.ID = 0, .Name = "Charlie", .LastLogin = New DateTime(2010, 11, 20)})
    accounts.Add(New Account() With {.ID = 1, .Name = "Eve",     .LastLogin = New DateTime(2010, 12, 20)})

    For Each e As Account In accounts
      Console.WriteLine(e)
    Next

    ' シリアライズ
    Using stream As Stream = File.OpenWrite("accounts.xml")
      Dim serializer As New XmlSerializer(accounts.GetType())
      Dim ns As New XmlSerializerNamespaces()

      ns.Add("ac", "http://example.com/ns/account")
      ns.Add("acex", "http://example.com/ns/account/extensions")

      serializer.Serialize(stream, accounts, ns)
    End Using

    ' デシリアライズ
    Using stream As Stream = File.OpenRead("accounts.xml")
      Dim serializer As New XmlSerializer(GetType(List(Of Account)))

      Dim deserialized As List(Of Account) = CType(serializer.Deserialize(stream), List(Of Account))

      Console.WriteLine("deserialized")

      For Each e As Account In accounts
        Console.WriteLine(e)
      Next
    End Using
  End Sub
End Class
accounts.xmlに出力される内容
<?xml version="1.0"?>
<ArrayOfアカウント情報 xmlns:ac="http://example.com/ns/account" xmlns:acex="http://example.com/ns/account/extensions">
  <アカウント情報>
    <ac:ID>2</ac:ID>
    <ac:名前>Alice</ac:名前>
    <acex:最終ログイン日時>2010-10-20T00:00:00</acex:最終ログイン日時>
  </アカウント情報>
  <アカウント情報>
    <ac:ID>0</ac:ID>
    <ac:名前>Charlie</ac:名前>
    <acex:最終ログイン日時>2010-11-20T00:00:00</acex:最終ログイン日時>
  </アカウント情報>
  <アカウント情報>
    <ac:ID>1</ac:ID>
    <ac:名前>Eve</ac:名前>
    <acex:最終ログイン日時>2010-12-20T00:00:00</acex:最終ログイン日時>
  </アカウント情報>
</ArrayOfアカウント情報>

フィールドを属性としてシリアライズする (XmlAttributeAttribute)

フィールドに対してXmlAttributeAttributeを指定することで、そのフィールドをXML属性として出力させるようにすることが出来ます。 コンストラクタ・パラメータで指定しなかった場合はデフォルトでフィールド名が属性名となります。 また、Namespaceプロパティを指定することで属性の名前空間を指定することも出来ます。

以下の例では、Account.IDフィールドに対して上記の属性を付与し、シリアライズの際に属性として出力するようにし、また同時に属性の名前も指定しています。 シリアライザが出力するXMLファイルにおいて、Account.IDフィールドの値が属性として出力されている点に注目してください。

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

[XmlType("アカウント情報")]
public class Account {
  [XmlAttribute("アカウントID")]
  public int ID;

  [XmlElement("名前")]
  public string Name;

  [XmlElement("最終ログイン日時")]
  public DateTime LastLogin;

  // デフォルトコンストラクタ
  public Account() {}

  public override string ToString()
  {
    return string.Format("{0}:{1} LastLogin={2}", ID, Name, LastLogin);
  }
}

class Sample {
  static void Main()
  {
    List<Account> accounts = new List<Account>();

    accounts.Add(new Account() {ID = 2, Name = "Alice",   LastLogin = new DateTime(2010, 10, 20)});
    accounts.Add(new Account() {ID = 0, Name = "Charlie", LastLogin = new DateTime(2010, 11, 20)});
    accounts.Add(new Account() {ID = 1, Name = "Eve",     LastLogin = new DateTime(2010, 12, 20)});

    foreach (Account e in accounts) {
      Console.WriteLine(e);
    }

    // シリアライズ
    using (Stream stream = File.OpenWrite("accounts.xml")) {
      XmlSerializer serializer = new XmlSerializer(accounts.GetType());

      serializer.Serialize(stream, accounts);
    }

    // デシリアライズ
    using (Stream stream = File.OpenRead("accounts.xml")) {
      XmlSerializer serializer = new XmlSerializer(typeof(List<Account>));

      List<Account> deserialized = (List<Account>)serializer.Deserialize(stream);

      Console.WriteLine("[deserialized]");

      foreach (Account e in deserialized) {
        Console.WriteLine(e);
      }
    }
  }
}
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization

<XmlType("アカウント情報")> _
Public Class Account
  <XmlAttribute("アカウントID")> _
  Public ID As Integer

  <XmlElement("名前")> _
  Public Name As String

  <XmlElement("最終ログイン日時")> _
  Public LastLogin As DateTime

  ' デフォルトコンストラクタ
  Public Sub New()
  End Sub

  Public Overrides Function ToString() As String
    Return String.Format("{0}:{1} LastLogin={2}", ID, Name, LastLogin)
  End Function
End Class

Class Sample
  Shared Sub Main()
    Dim accounts As New List(Of Account)

    accounts.Add(New Account() With {.ID = 2, .Name = "Alice",   .LastLogin = New DateTime(2010, 10, 20)})
    accounts.Add(New Account() With {.ID = 0, .Name = "Charlie", .LastLogin = New DateTime(2010, 11, 20)})
    accounts.Add(New Account() With {.ID = 1, .Name = "Eve",     .LastLogin = New DateTime(2010, 12, 20)})

    For Each e As Account In accounts
      Console.WriteLine(e)
    Next

    ' シリアライズ
    Using stream As Stream = File.OpenWrite("accounts.xml")
      Dim serializer As New XmlSerializer(accounts.GetType())

      serializer.Serialize(stream, accounts)
    End Using

    ' デシリアライズ
    Using stream As Stream = File.OpenRead("accounts.xml")
      Dim serializer As New XmlSerializer(GetType(List(Of Account)))

      Dim deserialized As List(Of Account) = CType(serializer.Deserialize(stream), List(Of Account))

      Console.WriteLine("deserialized")

      For Each e As Account In accounts
        Console.WriteLine(e)
      Next
    End Using
  End Sub
End Class
accounts.xmlに出力される内容
<?xml version="1.0"?>
<ArrayOfアカウント情報 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <アカウント情報 アカウントID="2">
    <名前>Alice</名前>
    <最終ログイン日時>2010-10-20T00:00:00</最終ログイン日時>
  </アカウント情報>
  <アカウント情報 アカウントID="0">
    <名前>Charlie</名前>
    <最終ログイン日時>2010-11-20T00:00:00</最終ログイン日時>
  </アカウント情報>
  <アカウント情報 アカウントID="1">
    <名前>Eve</名前>
    <最終ログイン日時>2010-12-20T00:00:00</最終ログイン日時>
  </アカウント情報>
</ArrayOfアカウント情報>

出力フォーマットの設定 (XmlWriter + XmlWriterSettings)

XmlSerializerクラスとXmlWriterクラスXmlWriterSettingsクラスを組み合わせることにより、シリアライズ時に出力されるXMLのフォーマットを変更することができます。 XmlWriterSettingsでは、インデントの有無や改行処理などを細かく設定できるようになっています。

以下の例では、インデントにタブを用いるようにし、また属性を改行して出力するようにXmlWriterSettingsを設定してシリアライズしています。

XmlWriterとXmlWriterSettingsを用いてXmlSerializerが生成するXMLのフォーマットを設定する
using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

public class Account {
  [XmlAttribute]
  public int ID;

  public string Name;

  [XmlAttribute]
  public DateTime LastLogin;

  // デフォルトコンストラクタ
  public Account() {}
}

class Sample {
  static void Main()
  {
    Account alice = new Account();

    alice.ID = 2;
    alice.Name = "Alice";
    alice.LastLogin = new DateTime(2010, 10, 20);


    XmlWriterSettings settings = new XmlWriterSettings();

    settings.Indent = true; // インデントを行う
    settings.IndentChars = "\t"; // インデントにタブ文字を用いる
    settings.NewLineOnAttributes = true; // 属性にも改行を行う

    // 上記の設定を使用し、alice.xmlに出力するXmlWriterを作成
    using (XmlWriter writer = XmlWriter.Create("alice.xml", settings)) {
      XmlSerializer serializer = new XmlSerializer(alice.GetType());

      // 作成したXmlWriterを使ってシリアライズする
      serializer.Serialize(writer, alice);
    }
  }
}
XmlWriterとXmlWriterSettingsを用いてXmlSerializerが生成するXMLのフォーマットを設定する
Imports System
Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization

Public Class Account
  <XmlAttribute> _
  Public ID As Integer

  Public Name As String

  <XmlAttribute> _
  Public LastLogin As DateTime

  ' デフォルトコンストラクタ
  Public Sub New()
  End Sub
End Class

Class Sample
  Shared Sub Main()
    Dim alice As New Account()

    alice.ID = 2
    alice.Name = "Alice"
    alice.LastLogin = New DateTime(2010, 10, 20)

    Dim settings As New XmlWriterSettings()

    settings.Indent = True ' インデントを行う
    settings.IndentChars = ControlChars.Tab ' インデントにタブ文字を用いる
    settings.NewLineOnAttributes = True ' 属性にも改行を行う

    ' 上記の設定を使用し、alice.xmlに出力するXmlWriterを作成
    Using writer As XmlWriter = XmlWriter.Create("alice.xml", settings)
      Dim serializer As New XmlSerializer(alice.GetType())

      ' 作成したXmlWriterを使ってシリアライズする
      serializer.Serialize(writer, alice)
    End Using
  End Sub
End Class
alice.xmlに出力される内容
<?xml version="1.0" encoding="utf-8"?>
<Account xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	ID="2"
	LastLogin="2010-10-20T00:00:00">
	<Name>Alice</Name>
</Account>

XmlWriterSettingsで設定できる内容についてより詳しくはXmlWriterSettingsで解説しています。

その他のシリアライズ動作の制御

XmlSerializerでもISerializableを使ったシリアライズ動作の制御を行うことが出来ます。 詳しくはISerializableの解説を参照してください。

また、ここまでで解説した以外にもシリアライズのための属性が存在します。 詳しくは以下のドキュメントを参照してください。