注意:ここではXmlSerializerクラスを使った方法を紹介します。DataContractSerializerクラスを使った方法は、「DataContractSerializerを使って、Object配列やArrayListをXMLシリアル化する」で説明しています。
「オブジェクトの内容をファイルに保存、復元する」で説明した方法でObject型の配列やArrayListオブジェクトなどをシリアル化すると、例外InvalidOperationException(XML ドキュメントを生成中にエラーが発生しました)がスローされる場合があります。例えば、次のようなケースです。
Public Class SampleItem Public Number As Integer Public Message As String Public Sub New() Number = 0 Message = "" End Sub Public Sub New(num As Integer, msg As String) Number = num Message = msg End Sub End Class Public Class MainClass 'エントリポイント Public Shared Sub Main() 'XMLシリアル化するArrayList Dim al As New System.Collections.ArrayList() al.Add(New SampleItem(12, "こんにちは")) al.Add("こんばんは") 'XMLファイルに保存する Dim serializer As New System.Xml.Serialization.XmlSerializer( _ GetType(System.Collections.ArrayList)) Dim sw As New System.IO.StreamWriter( _ "C:\test\sample.xml", False, New System.Text.UTF8Encoding(False)) 'エラーが発生する serializer.Serialize(sw, al) '閉じる sw.Close() End Sub End Class
using System; public class SampleItem { public int Number; public string Message; public SampleItem() { Number = 0; Message = ""; } public SampleItem(int num, string msg) { Number = num; Message = msg; } } public class MainClass { //エントリポイント public static void Main() { //XMLシリアル化するArrayList System.Collections.ArrayList al = new System.Collections.ArrayList(); al.Add(new SampleItem(12, "こんにちは")); al.Add("こんばんは"); //XMLファイルに保存する System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer( typeof(System.Collections.ArrayList)); System.IO.StreamWriter sw = new System.IO.StreamWriter( @"C:\test\sample.xml", false, new System.Text.UTF8Encoding(false)); //エラーが発生する serializer.Serialize(sw, al); //閉じる sw.Close(); } }
ここでは、これを解決する方法を幾つか紹介します。
なおここでは「オブジェクトの内容をファイルに保存、復元する」で説明している事柄については一切説明しませんので、基本的な部分が分からないという場合は、まずそちらをご覧ください。
まずは、XmlSerializerのコンストラクタでArrayListに追加される可能性のあるすべてのオブジェクトの型を通知する方法を紹介します。例えば上記の例では、SampleItemクラス型とString型を通知します。復元する時も同様に型を通知する必要があります。
この方法を使って上記の例を修正すると次のようになります。(SampleItemクラスは前と同じですので、省略します。)
Public Class MainClass 'エントリポイント Public Shared Sub Main() 'XMLシリアル化するArrayList Dim al As New System.Collections.ArrayList() al.Add(New SampleItem(12, "こんにちは")) al.Add("こんばんは") 'ArrayListに追加されているオブジェクトの型の配列を作成 Dim et As Type() = New Type() {GetType(SampleItem)} 'ArrayListに追加されているオブジェクトを指定してXMLファイルに保存する Dim serializer As New System.Xml.Serialization.XmlSerializer( _ GetType(System.Collections.ArrayList), et) Dim sw As New System.IO.StreamWriter( _ "C:\test\sample.xml", False, New System.Text.UTF8Encoding(False)) serializer.Serialize(sw, al) '閉じる sw.Close() End Sub End Class
public class MainClass { //エントリポイント public static void Main() { //XMLシリアル化するArrayList System.Collections.ArrayList al = new System.Collections.ArrayList(); al.Add(new SampleItem(12, "こんにちは")); al.Add("こんばんは"); //ArrayListに追加されているオブジェクトの型の配列を作成 Type[] et = new Type[] { typeof(SampleItem) }; //ArrayListに追加されているオブジェクトを指定してXMLファイルに保存する System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer( typeof(System.Collections.ArrayList), et); System.IO.StreamWriter sw = new System.IO.StreamWriter( @"C:\test\sample.xml", false, new System.Text.UTF8Encoding(false)); serializer.Serialize(sw, al); //閉じる sw.Close(); } }
書き込まれたXMLファイルの内容は次のようになります。
<?xml version="1.0" encoding="utf-8"?> <ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <anyType xsi:type="SampleItem"> <Number>12</Number> <Message>こんにちは</Message> </anyType> <anyType xsi:type="xsd:string">こんばんは</anyType> </ArrayOfAnyType>
Object型の配列やArrayListがクラスのメンバで、そのクラスのインスタンスをシリアル化する場合は、そのメンバにXmlArrayItemAttribute属性を適用する方法があります。この方法はシリアル化するクラスに手を加えるだけで、あとは「オブジェクトの内容をファイルに保存、復元する」方法とまったく同じやり方でシリアル化できます。
以下に、ArrayListをメンバに持つSampleClassクラスのインスタンスをシリアル化する例を示します。
Public Class SampleItem Public Number As Integer Public Message As String Public Sub New() Number = 0 Message = "" End Sub Public Sub New(num As Integer, msg As String) Number = num Message = msg End Sub End Class 'シリアル化するクラス Public Class SampleClass 'ArrayListに追加される型を指定する <System.Xml.Serialization.XmlArrayItem(GetType(SampleItem)), _ System.Xml.Serialization.XmlArrayItem(GetType(String))> _ Public Items As System.Collections.ArrayList End Class Public Class MainClass 'エントリポイント Public Shared Sub Main() 'XMLシリアル化するオブジェクト Dim obj As New SampleClass() obj.Items = New System.Collections.ArrayList() obj.Items.Add(New SampleItem(12, "こんにちは")) obj.Items.Add("こんばんは") 'ArrayListに追加されているオブジェクトを指定してXMLファイルに保存する Dim serializer As New System.Xml.Serialization.XmlSerializer( _ GetType(SampleClass)) Dim sw As New System.IO.StreamWriter( _ "C:\test\sample.xml", False, New System.Text.UTF8Encoding(False)) serializer.Serialize(sw, obj) '閉じる sw.Close() End Sub End Class
using System; public class SampleItem { public int Number; public string Message; public SampleItem() { Number = 0; Message = ""; } public SampleItem(int num, string msg) { Number = num; Message = msg; } } //シリアル化するクラス public class SampleClass { //ArrayListに追加される型を指定する [System.Xml.Serialization.XmlArrayItem(typeof(SampleItem)), System.Xml.Serialization.XmlArrayItem(typeof(string))] public System.Collections.ArrayList Items; } public class MainClass { //エントリポイント public static void Main() { //XMLシリアル化するオブジェクト SampleClass obj = new SampleClass(); obj.Items = new System.Collections.ArrayList(); obj.Items.Add(new SampleItem(12, "こんにちは")); obj.Items.Add("こんばんは"); //ArrayListに追加されているオブジェクトを指定してXMLファイルに保存する System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(SampleClass)); System.IO.StreamWriter sw = new System.IO.StreamWriter( @"C:\test\sample.xml", false, new System.Text.UTF8Encoding(false)); serializer.Serialize(sw, obj); //閉じる sw.Close(); } }
このコードによって書き込まれたXMLファイルの内容は次のようになります。
<?xml version="1.0" encoding="utf-8"?> <SampleClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Items> <SampleItem> <Number>12</Number> <Message>こんにちは</Message> </SampleItem> <string>こんばんは</string> </Items> </SampleClass>
例えば上記のシリアル化されたXMLで、<Items>や<SampleItem>、<string>の要素名を変更することもできます。それには、次のようにSampleClassクラスを書き換えます。
'シリアル化するクラス Public Class SampleClass <System.Xml.Serialization.XmlArray("リスト")> _ <System.Xml.Serialization.XmlArrayItem("サンプル", GetType(SampleItem)), _ System.Xml.Serialization.XmlArrayItem("文字列", GetType(String))> _ Public Items As System.Collections.ArrayList End Class
//シリアル化するクラス public class SampleClass { [System.Xml.Serialization.XmlArray("リスト")] [System.Xml.Serialization.XmlArrayItem("サンプル", typeof(SampleItem)), System.Xml.Serialization.XmlArrayItem("文字列", typeof(string))] public System.Collections.ArrayList Items; }
すると、XMLは次のようになります。
<?xml version="1.0" encoding="utf-8"?> <SampleClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <リスト> <サンプル> <Number>12</Number> <Message>こんにちは</Message> </サンプル> <文字列>こんばんは</文字列> </リスト> </SampleClass>
要素名を変更する方法については、「オブジェクトの内容をファイルに保存、復元する」でさらに詳しく説明しています。