連載

.NETで簡単XML

第9回 オブジェクトをXMLでシリアライズ(1)

株式会社ピーデー 川俣 晶
2003/10/15
Page1 Page2 Page3

 次は、このクラスをシリアライズする部分である。フォームのクラス内に記述する内容を示す。ここでは、シリアライズしてファイルに書き込むserializeSampleメソッドと、シリアライズされたファイルを読み込んでオブジェクトを得るdeserializeSampleメソッドを用意している。(このあとの例も、すべてこのパターンで記述している)

Private Sub serializeSample()
  Dim person As Person = New Person
  person.Name = "山田太郎"
  person.Age = 17
  person.SetTemporaryID(DateTime.Now.ToString())
  Dim serializer As XmlSerializer = New XmlSerializer(GetType(Person))
  Dim stream As FileStream = New FileStream("c:\sample.xml", FileMode.Create)
  Try
    serializer.Serialize(stream, person)
  Finally
    stream.Close()
  End Try
End Sub

Private Sub deserializeSample()
  Dim serializer As XmlSerializer = New XmlSerializer(GetType(Person))
  Dim person As Person
  Dim stream As FileStream = New FileStream("c:\sample.xml", FileMode.Open)
  Try
    person = CType(serializer.Deserialize(stream), Person)
  Finally
    stream.Close()
  End Try
  person.Dump()
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  serializeSample()
  deserializeSample()
End Sub
サンプル・プログラム1-2:シリアライズ/デシリアライズを行うメソッド(VB.NET版C#版

 これを実行すると出力は以下のようになる。

山田太郎
未設定
17
未設定
サンプル・プログラム1-2の出力

 生成されたXML文書は以下のようになる(ルート要素に付加された2つの名前空間URIはXML Schemaのためのものである。ここでは特に意味を持っていないので無視して構わない。以降の例も同様)。

<?xml version="1.0"?>
<Person xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Age>17</Age>
  <Name>山田太郎</Name>
</Person>
生成されたXML文書

 まず、serializeSampleメソッドから見ていこう。Personクラスのインスタンスを作成し、そこに値を入れていく。Nameプロパティは"山田太郎"に、Ageは17に、temporaryIDは現在時刻を文字列に直したものを格納している。ここまではまったく問題なく理解できるだろう。

Dim person As Person = New Person
person.Name = "山田太郎"
person.Age = 17
person.SetTemporaryID(DateTime.Now.ToString())

 次に、XmlSerializerクラスのインスタンスを作成している。

New XmlSerializer(GetType(Person))

 ここで注意すべき点は、コンストラクタの引数にシリアライズするクラスの型情報を指定する必要がある点である。ここで型を指定することで、それぞれの型に即したシリアライザ(シリアライズを実行するオブジェクト)が作成される。つまり、シリアライザはどんな型でもシリアライズできる汎用品ではなく、固有の型(クラス)に対応するものが生成されるわけである。

 次に、FileStreamクラスを用いてファイルのストリームを作成している。そして、そのストリームを指定して、シリアライザのSerializeメソッドを呼び出している。

serializer.Serialize(stream, person)

 第1引数は、シリアライズした結果を出力する先。第2引数は、シリアライズする対象のインスタンスである。

 シリアライズ後にストリームを閉じれば、これでインスタンスの内容が指定ファイルに書き出されているはずである。

 次に、deserializeSampleメソッドを見てみよう。基本的な流れはserializeSampleメソッドと似ている。違っているのは、Serializeメソッドではなく、Deserializeメソッドを使用している点である。このメソッドは、シリアライズされたデータを、逆変換(デシリアライズ)してインスタンスを作成する。使い方に難しいところはないが、Deserializeメソッドの戻り値はobject型であるため、キャストをしておく必要がある(VB.NETならCTypeを使う)。デシリアライズが終わったら、Dumpメソッドを呼び出して、内容をIDEの出力ウィンドウに出力させている。

 さて、以上がプログラムの説明だが、これで話が終わりというわけではない。出力結果と、書き出されたXML文書と、ソース・コードに記述したインスタンスの初期値に相違があることに注意していただきたい。

初期値 XML文書に書き出された内容 デシリアライズした内容
m_name="山田太郎" m_name="山田太郎" m_name="山田太郎"
m_address="未設定" m_address="未設定"
Age=17 Age=17 Age=17
m_temporaryID=現在時刻 m_temporaryID="未設定"
シリアライズされる変数とされない変数

 この表を見て分かるとおり、インスタンスが持つすべての変数がシリアライズされたわけではない。いったい、シリアライズされたデータと、そうではないデータの間には、どんな違いがあるのだろうか。

 結論を述べると、XmlSerializerクラスによって行う“XMLシリアル化”は、パブリック・フィールドとパブリック・プロパティのみを扱う。Personクラスには4つの変数があるが、この中で条件を満たすものは、「Age」のみである。これ以外の3つの変数は処理の対象になっていない。しかし、名前が出力されているのは、変数m_nameに対応するパブリック・プロパティ「Name」が存在するためである。つまり、名前は、変数ではなくプロパティを経由して出力されたのである。しかしメソッドは対象にならないので、SetTemporaryIDのようなメソッドが存在していても、それは扱われない。もう1つ注意する点は、Addressプロパティである。これもパブリック・プロパティではあるが、処理の対象には含まれていない。これは、読み取り専用のプロパティも処理の対象にできないことによる制限といえる。読み取り専用では、デシリアライズができないためである。読み取り専用ならシリアライズだけはできるではないかと思うかもしれないが、シリアライズとは一方通行の変換ではない。シリアライズした結果をデシリアライズして戻すことができなければ意味がないものなのである。

 さて、もう一度、サンプル・プログラムをじっくり眺めていただきたい。これまでいろいろなやり方を紹介してきたが、XML文書を読み書きする手段としては、かなりシンプルだと思わないだろうか。シリアライズは、読み書きするXML文書の構造を具体的に指定することなく処理することができる。これにより、いちいち、ここは属性を書き込め、といった指示をすることなく、XML文書の読み書きが実現されている。しかし逆にいえば、XML文書の構造をシステム任せで決定しているともいえる。シンプルなコーディングで実現できる特徴を活かしつつ、読み書きされるXML文書の構造を意識的に指定していくことも可能である。では、それについて解説しよう。


 INDEX
  .NETで簡単XML
  第9回 オブジェクトをXMLでシリアライズ(1)
    1.シリアライズによるオブジェクトの永続化
  2.シリアライズ/デシリアライズを行う例
    3..XmlIgnoreAttribute属性を使用したシリアル化の防止
 
インデックス・ページヘ  「連載 :.NETで簡単XML」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間