連載

.NETで簡単XML

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

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

属性の指定

 XMLには要素のほかに属性というものがある。シリアライズの際に、要素ではなく属性に情報を出力することもできる。次のリストはそれを行った例である。

 シリアライズなどの処理は前のサンプル・プログラムと同じなので、クラスだけを示す。

<XmlRoot("個人情報")> Public Class Person
  Private m_name As String = "未設定"
  Private m_age As Integer = 0

  <XmlAttributeAttribute("名前")> Public Property Name() As String
    Get
      Return m_name
    End Get
    Set(ByVal Value As String)
      m_name = Value
    End Set
  End Property

  <XmlAttributeAttribute("年齢")> Public Property Age() As Integer
    Get
      Return m_age
    End Get
    Set(ByVal Value As Integer)
      m_age = Value
    End Set
  End Property

  Public Sub Dump()
    Trace.WriteLine(m_name)
    Trace.WriteLine(m_age)
  End Sub
End Class
サンプル・プログラム2:Personクラス(VB.NET版C#版

 これを実行すると次のようになる。

山田太郎
17

 生成されたXML文書は以下のとおり。

<?xml version="1.0"?>
<個人情報 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 名前="山田太郎" 年齢="17" />
生成されたXML文書

 前のサンプル・プログラムとの相違点はXmlElementがXmlAttributeAttributeに変化しただけである。XmlElement属性が、対象を要素として出力することを指定する属性であるのに対して、XmlAttributeAttribute(XmlAttribute属性)はXMLの属性として出力することを指定する属性である。属性という言葉が繰り返し出てくるが、.NET Frameworkの属性とXMLの属性を混同しないように注意しよう。属性の引数には、XMLの属性の名前を指定する。

 余談であるが、Visual Studio.NETのIDEは、VB.NETプロジェクトの中で属性名としてXmlAttributeと入力すると自動的にXmlAttributeAttributeに置き換えてくれた。しかし、C#ではそのような置き換えは行われなかった。そのような理由で、VB.NETのソース中ではXmlAttributeAttributeと表記されているが、C#のソース中ではXmlAttributeと表記している。もちろん、どちらも同じものである。また、XmlAttributeクラス(System.Xml名前空間)と取り違えることがないように注意しよう。

参照されるオブジェクトのシリアル化

 クラスには、いろいろと複雑な情報が記憶される場合がある。シリアライズするクラスに含まれる情報として、これまでの例は、文字列や整数のような単純な型ばかりを扱ってきた。しかし、ここに別のクラスのインスタンスへの参照があったらどうなるだろうか。

 次に紹介するのは、別のクラスへの参照を含むクラスをシリアライズする例である。

 まず、シリアライズされるクラスと、そこから参照されるクラスを見ていただきたい。

Public Class PersonName
  Public FirstName As String
  Public FamilyName As String

  Public Sub New(ByVal familyName As String, ByVal firstName As String)
    Me.FirstName = firstName
    Me.FamilyName = familyName
  End Sub

  Public Sub New()
    Me.FirstName = "未設定"
    Me.FamilyName = "未設定"
  End Sub
End Class

Public Class Person
  Private m_name As PersonName = New PersonName
  Private m_age As Integer = 0

  Public Property Name() As PersonName
    Get
      Return m_name
    End Get
    Set(ByVal Value As PersonName)
      m_name = Value
    End Set
  End Property

  Public Property Age() As Integer
    Get
      Return m_age
    End Get
    Set(ByVal Value As Integer)
      m_age = Value
    End Set
  End Property

  Public Sub Dump()
    Trace.WriteLine(m_name.FamilyName)
    Trace.WriteLine(m_name.FirstName)
    Trace.WriteLine(m_age)
  End Sub
End Class
サンプル・プログラム3-1:シリアライズされるクラスと参照されるクラス(VB.NET版C#版

 これをシリアライズするメソッドを以下に示す。デシリアライズするメソッドとForm1_Loadメソッドは前の例と同じなので省略する。

Private Sub serializeSample()
  Dim person As Person = New Person
  person.Name = New PersonName("山田", "太郎")
  person.Age = 17
  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
サンプル・プログラム3-2:シリアライズを行うメソッド(VB.NET版C#版

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

山田
太郎
17

 生成されたXML文書は以下のようになる。

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

 結果を見ると、参照されたインスタンスの内容もシリアライズされて一緒に出力されていることが分かるだろう。デシリアライズも一緒に行われている。このように、参照する別のインスタンスがあるとしても、それもシリアライズ可能であることを意識してクラスを定義しておけば、シリアライズ可能である。

 ただし、デシリアライズ時に参照されるインスタンスが新規に作成されることには注意が必要である。例えば、インスタンスAを参照するインスタンスBとインスタンスCがあるとする。インスタンスAは1個しか存在しない。しかし、インスタンスBとインスタンスCをシリアライズしてからデシリアライズすると、インスタンスBとインスタンスCの双方が、参照しているインスタンスAを再現することになり、結果的にインスタンスAが2個存在する形になる。そのような参照関係までは完全に再現されないことに注意が必要である。

 さて、ここではもう1つシリアライズのポイントが示されている。PersonNameクラスを見てほしい。ここには、引数のあるコンストラクタと引数のないコンストラクタが記述されている。引数のないコンストラクタは使われていないように見えるため、取り除くことができるように思えるかも知れない。だが、引数のないコンストラクタを取り除くと、このクラスはシリアライズできなくなってしまう。デシリアライズの処理で、クラスは引数なしで生成され、そこに各々の値が設定される処理が行われているためだと思われるが、それを実現するには、引数のないコンストラクタが必要なのである。

 なお、コンストラクタのないクラスでは、暗黙的に引数のないコンストラクタがあるとして処理されるので、この場合はシリアライズ可能である。


 INDEX
  .NETで簡単XML
  第10回 オブジェクトをXMLでシリアライズ(2)
    1.要素名を指定してシリアライズする
  2.属性の指定/参照されるオブジェクトのシリアル化
    3.名前空間の指定/配列のシリアル化
 
インデックス・ページヘ  「連載 :.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 記事ランキング

本日 月間