XmlSerializerはオブジェクトをXML形式にシリアライズすることができる便利なシリアライザです。シリアライズできないクラスの場合は、IXmlSerializableを実装する必要があります。クラスのフィールドにリストのリスト(ArrayListのリストやList<T>のリスト)やIDictionary型等が含まれている場合はそのままではシリアライズできません。今回はクラスのフィールドにIDictionaryを実装した、SortedList<TKey,TVal>を含めているのでIXmlSerizableを実装したサンプルを掲載します。
確認環境
- Windows Vista Enterprise Edition
- 開発環境:Visual Studio 2008 Professional 英語版
- .NET 3.5(.NET 2.0以上)
1. シリアライズ対象クラスの作成
Visual Studio 2008 を起動し、コンソールプロジェクトを作成します。名前はXmlSerializerTestとしました。
1.1 UserInfoクラスの作成
UserInfo.csクラスファイルを作成し、以下のように編集します。XmlSerialzerは規定ではパブリックなフィールドやプロパティを属性としてシリアライズします。シリアライズするプロパティやフィールドを要素とするか、属性とするか、名前を指定する場合などは、XmlElement,XmlAttributeで指定します。XmlRootを指定すると、ルート要素がシリアライズされるときに要素名を指定できます。サンプルに掲載されていませんが、配列の要素名を変更する場合はXmlArrayAttributeを指定します。詳細はMSDNドキュメントを参照願います。
namespace XmlSerializerTest { [XmlRoot("user", Namespace="urn:Handcraft.UserInfo")] public class UserInfo { public UserInfo() { ApplicationName = "/"; UserName = string.Empty; IsApproved = false; IsLockedOut = false; Comment = string.Empty; Email = string.Empty; CreationDate = MinumDateTime(); LastActivityDate = MinumDateTime(); LastLockoutDate = MinumDateTime(); LastLoginDate = MinumDateTime(); LastPasswordChangedDate = MinumDateTime(); PasswordQuestion = string.Empty; PasswordAnswer = string.Empty; EncodedPassword = string.Empty; PasswordSalt = string.Empty; } /// <summary>アプリケーション名</summary> [XmlAttribute("applicationName")] public string ApplicationName { get; set; } /// <summary>ユーザID</summary> [XmlAttribute("name")] public string UserName { get; set; } /// <summary>承認済みか</summary> [XmlElement("approved")] public bool IsApproved { get; set; } /// <summary>ロックアウト中か</summary> [XmlElement("lockouted")] public bool IsLockedOut { get; set; } /// <summary>コメント</summary> [XmlElement("comment")] public string Comment { get; set; } /// <summary>email</summary> [XmlElement("email")] public string Email { get; set; } [XmlElement("creationDate")] public DateTime CreationDate { get; set; } /// <summary>最終活動日時</summary> [XmlElement("lastActivityDate")] public DateTime LastActivityDate { get; set; } /// <summary>最終ロックアウト日時</summary> [XmlElement("lastLockoutDate")] public DateTime LastLockoutDate { get; set; } /// <summary>最終ログイン日時</summary> [XmlElement("lastLoginDate")] public DateTime LastLoginDate { get; set; } /// <summary>最終パスワード変更日時</summary> [XmlElement("lastPasswordChangedDate")] public DateTime LastPasswordChangedDate { get; set; } /// <summary>パスワードの質問</summary> [XmlElement("passwordQuestion")] public string PasswordQuestion { get; set; } /// <summary>パスワードの答え</summary> [XmlElement("passwordAnswer")] public string PasswordAnswer { get; set; } /// <summary>パスワード</summary> [XmlElement("password")] public string EncodedPassword { get; set; } /// <summary>パスワードサルト</summary> [XmlElement("passwordSalt")] public string PasswordSalt { get; set; } public virtual MembershipUser CreateMembershipUser(string providerName, object providerUserKey) { return new MembershipUser(providerName, UserName, providerUserKey, Email, PasswordQuestion, Comment, IsApproved, IsLockedOut, CreationDate, LastLoginDate, LastActivityDate, LastPasswordChangedDate, LastLockoutDate); } public virtual MembershipUser CreatemembershipUser(string providerName) { return CreateMembershipUser(providerName, null); } protected virtual DateTime MinumDateTime() { return new DateTime(1754, 1, 1, 0, 0, 0, 0); } } }
1.2 UserInfoListクラスの作成
UserInfoクラスをコンテナの要素として含むUserInfoList.csを作成し、以下のように編集しました。UserInfoListはIXmlSerializableを実装して、独自にシリアライズするようにしています。
namespace XmlSerializerTest { [XmlRoot("users", Namespace = "urn:Handcraft.UserInfoList")] public class UserInfoList : IXmlSerializable { /// <summary> /// ユーザ情報を格納するコレクション /// キーにUserInfo.UserNameを使用する /// </summary> private SortedList<string, UserInfo> _users = new SortedList<string, UserInfo>(); /// <summary> /// UserInfoを追加する /// </summary> /// <param name="userInfo"></param> public void AddUserInfo(UserInfo userInfo) { _users.Add(userInfo.UserName, userInfo); } public UserInfo GetUserInfo(string name) { return _users[name]; } public bool RemoveUserInfo(string name) { return _users.Remove(name); } #region IXmlSerializable Membersの実装 public System.Xml.Schema.XmlSchema GetSchema() { return null; } /// <summary> /// 独自でデシリアライズを行う /// </summary> /// <param name="reader"></param> public void ReadXml(System.Xml.XmlReader reader) { XmlSerializer s = new XmlSerializer(typeof(UserInfo)); reader.Read(); while (reader.NodeType != System.Xml.XmlNodeType.EndElement) { UserInfo o = s.Deserialize(reader) as UserInfo; AddUserInfo(o); } } /// <summary> /// 独自でシリアライズを行う /// </summary> /// <param name="writer"></param> public void WriteXml(System.Xml.XmlWriter writer) { XmlSerializer s = new XmlSerializer(typeof(UserInfo)); foreach (UserInfo val in _users.Values) { s.Serialize(writer, val); } } #endregion } }
2 テストプログラムの作成
プロジェクト作成時に既定で作成されるProgram.csのMainを以下のように編集してテストプログラムを記述します。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; using System.IO; namespace XmlSerializerTest { class Program { static void Main(string[] args) { XmlSerializer serializer = new XmlSerializer(typeof(UserInfoList)); UserInfoList list = new UserInfoList(); UserInfo info = new UserInfo(); info.UserName = "test"; list.AddUserInfo(info); info = new UserInfo(); info.UserName = "kitakore"; list.AddUserInfo(info); using (FileStream fs = new FileStream(@"D:\temp\test.xml", FileMode.Create)) { serializer.Serialize(fs, list); } using (FileStream fs = System.IO.File.OpenRead(@"D:\temp\test.xml")) { UserInfoList o = serializer.Deserialize(fs) as UserInfoList; Console.WriteLine(o.GetUserInfo("test").UserName); } //そのほかいろいろ List<UserInfo> glist = new List<UserInfo>(); glist.Add(info); XmlSerializer s = new XmlSerializer(typeof(List<UserInfo>)); using (FileStream fs = new FileStream(@"D:\temp\test2.xml", FileMode.Create)) { s.Serialize(fs, glist); } UserInfo[] arrayList = new UserInfo[1]; arrayList[0] = info; XmlSerializer s1 = new XmlSerializer(typeof(UserInfo[])); using (FileStream fs = new FileStream(@"D:\temp\test3.xml", FileMode.Create)) { s1.Serialize(fs, arrayList); } } } }
test.xmlの内容は次のようになります。
<?xml version="1.0"?> <users xmlns="urn:Handcraft.UserInfoList"> <user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" applicationName="/" name="kitakore" xmlns="urn:Handcraft.UserInfo"> <approved>false</approved> <lockouted>false</lockouted> <comment /> <email /> <creationDate>1754-01-01T00:00:00</creationDate> <lastActivityDate>1754-01-01T00:00:00</lastActivityDate> <lastLockoutDate>1754-01-01T00:00:00</lastLockoutDate> <lastLoginDate>1754-01-01T00:00:00</lastLoginDate> <lastPasswordChangedDate>1754-01-01T00:00:00</lastPasswordChangedDate> <passwordQuestion /> <passwordAnswer /> <password /> <passwordSalt /> </user> <user xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" applicationName="/" name="test" xmlns="urn:Handcraft.UserInfo"> <approved>false</approved> <lockouted>false</lockouted> <comment /> <email /> <creationDate>1754-01-01T00:00:00</creationDate> <lastActivityDate>1754-01-01T00:00:00</lastActivityDate> <lastLockoutDate>1754-01-01T00:00:00</lastLockoutDate> <lastLoginDate>1754-01-01T00:00:00</lastLoginDate> <lastPasswordChangedDate>1754-01-01T00:00:00</lastPasswordChangedDate> <passwordQuestion /> <passwordAnswer /> <password /> <passwordSalt /> </user> </users> <password /> <passwordSalt /> </user> </users>
3. その他の情報
XmlSerializerはシリアライズするクラスを動的にコンパイル処理を行うのにcsc.exeを使います。このとき、csc.exeが停止することがあるそうです。詳細は以下のリンク参照。回避方法としてプリコンパイルを行うようsgen.exeツールを使うようにします。
-XmlSerializer クラスから起動された csc.exe が一定時間応答を停止する場合がある
http://support.microsoft.com/kb/899153/ja
-Windows Vista で XmlSerializer クラスを使用するアプリケーションの動作により、リムーバブル ディスクが安全に取り外せないことがある
http://support.microsoft.com/kb/957190/ja
XMLのシリアル化を細かく制御する属性については次のリンクを参照
XML シリアル化を制御する属性
http://msdn.microsoft.com/ja-jp/library/83y7df3e(VS.80).aspx
説明は以上です。間違い、誤り等があればご連絡ください。
さんのコメント: さんのコメント: