連載

.NETで簡単XML

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

株式会社ピーデー 川俣 晶
2004/02/18
Page1 Page2 Page3 Page4

XmlSerializerを使ってSOAP形式でシリアライズする方法

 実は、XmlSerializerクラスは、SOAP形式でシリアライズする機能を持っている。といっても、SoapFormatterクラスと同等の機能を発揮できるというわけではない。最大の相違は、シリアライズされる対象(メンバ)である。SOAP形式を指定してシリアライズしても、XmlSerializerクラスはパブリック・フィールドとパブリック・プロパティのみを扱い、すべてのフィールドを扱うわけではない。

 では実際に、XmlSerializerクラスでSOAP形式のシリアライズを行うサンプル・ソースを作成してみよう。

 ソース・コードの先頭には以下のコードを追加しておく。

Imports System.IO
Imports System.Xml.Serialization
サンプル・プログラム6:XmlSerializerクラスでSOAP形式のシリアライズを行うサンプル・ソースの先頭に追加するコード(VB.NET版C#版

 シリアライズされる対象となるクラスは以下のとおりである。本当はほかのサンプル・ソースと同じクラスでもよいのだが、いくつかの属性についての解説を行いたいので、それを追加してある。

Public Class Person
  Private m_name As String = "未設定"
  Private m_address As String = "未設定"
  <SoapAttributeAttribute()> _
    Public Age As Integer = 0
  Private m_temporaryID As String = "未設定"
  <SoapElement()> _
  Public Property Name() As String
    Get
      Return m_name
    End Get
    Set(ByVal Value As String)
      m_name = Value
    End Set
  End Property
  Public ReadOnly Property Address() As String
    Get
      Return m_address
    End Get
  End Property
  Public Sub SetTemporaryID(ByVal temporaryID As String)
    m_temporaryID = temporaryID
  End Sub
  Public Sub Dump()
    System.Diagnostics.Trace.WriteLine(m_name)
    System.Diagnostics.Trace.WriteLine(m_address)
    System.Diagnostics.Trace.WriteLine(Age)
    System.Diagnostics.Trace.WriteLine(m_temporaryID)
  End Sub
End Class
サンプル・プログラム7:XmlSerializerクラスでSOAP形式のシリアライズを行うPersonクラス(VB.NET版C#版

 以下はシリアライズ、デシリアライズを行うメソッドである。これまでの例にはなかったcreateSoapOverriderというメソッドが増えていることに注意していただきたい。

Private Function createSoapOverrider() As XmlSerializer
  Dim soapOverrides As SoapAttributeOverrides = New SoapAttributeOverrides
  Dim myTypeMapping As XmlTypeMapping = (New SoapReflectionImporter(soapOverrides)).ImportTypeMapping(GetType(Person))
  Return New XmlSerializer(myTypeMapping)
End Function

Private Sub serializeSample()
  Dim person As Person = New Person
  person.Name = "山田太郎"
  person.Age = 17
  person.SetTemporaryID(DateTime.Now.ToString())
  Dim serializer As XmlSerializer = createSoapOverrider()
  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 = createSoapOverrider()
  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
サンプル・プログラム8:XmlSerializerクラスでSOAP形式のシリアライズを行うメソッド(VB.NET版C#版

 これを実行すると、以下のような出力が得られる。

山田太郎
未設定
17
未設定
サンプル・プログラム8の出力結果

 また、同時に以下のような内容のXMLファイルが「c:\sample.xml」に生成される。

<?xml version="1.0"?>
<Person xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="id1" Age="17">
  <Name xsi:type="xsd:string">山田太郎</Name>
</Person>
サンプル・プログラム8で生成されるXML文書

 ここで出力されているXML文書の内容も、SoapFormatterクラスを使ってシリアライズした場合と同じではないことが分かるだろう。しかし、xsi:type属性が付いているなど、確かにSOAP形式らしい部分がある。

 ここで重要なのは、そのことよりも、どうやってXmlSerializerクラスにSOAP形式を扱うように命じられるかである。注目していただきたいのは、これまでただ単に、XmlSerializerクラスのインスタンスを作成していたのに対して、その処理が複雑化しているところである。この処理は、シリアライズとデシリアライズで2回必要とされるので、独立したcreateSoapOverriderというメソッドにまとめている。このメソッドで作成されたXmlSerializerクラスのインスタンスを使えば、SOAP形式でシリアライズされるわけである。

 createSoapOverriderメソッドで使用されているSoapAttributeOverridesクラス(System.Xml.Serialization名前空間)は、シリアライズする方法をオーバーライドして置き換えるために使われるものである。これと似たものに、XmlAttributeOverridesクラス(System.Xml.Serialization名前空間)がある。これは、SOAP形式ではない通常の形式でオーバーライドするためのものである。

 また、XmlTypeMappingクラス(System.Xml.Serialization名前空間)は、1つの型から別の型への割り当てを格納するクラスである。これは、エンコード済みのSOAP XMLとしてオブジェクトをシリアル化するときに使用するものである。

 これらのクラスは、意味を完全に理解するとかなり大変なので、このような一連の流れで使うパターンとして覚えておくとよいだろう。

 このサンプル・プログラムでは、もう1つ、別の話題を扱っている。シリアライズされるクラスの中に、SoapAttribute属性(System.Xml.Serialization名前空間)やSoapElement属性(System.Xml.Serialization名前空間)が書き込まれている。これらの属性は、すでに解説したシリアライズ内容をコントロールするためのXmlAttribute属性(System.Xml.Serialization名前空間)や、XmlElement属性(System.Xml.Serialization名前空間)と同様の機能を持っている。例えば、SoapAttribute属性を指定した「Age」は、シリアライズ時に属性として出力されていることが分かるだろう。ここで注意すべき点は、同じXmlSerializerクラスによってシリアライズする場合でも、SOAP形式を使う場合とそうではない場合で、異なる属性を使わねばならないことである。これは裏を返すと、シリアライズする形式が異なるときに、異なる条件でシリアライズを制御することが容易であることを意味する。例えば、同じフィールドに、SoapAttribute属性とXmlAttribute属性を付けて、それぞれに異なる引数を設定してもよい。

作成済みクラスのシリアライズ方法の変更

 話は少しそれるが、SoapAttributeOverridesクラスを活用すると、ただ単にシリアライズをSOAP形式にするだけでなく、シリアライズ内容そのものを制御することができる。その例を参考までに取り上げておく。

 それを行うには、先ほどのcreateSoapOverriderメソッドを変更する必要がある。変更した内容を以下に示す。

Private Function createSoapOverrider() As XmlSerializer
  Dim soapAttrs As SoapAttributes = New SoapAttributes
  Dim soapOverrides As SoapAttributeOverrides = New SoapAttributeOverrides
  soapAttrs.SoapElement = New SoapElementAttribute("Nenrei")
  soapOverrides.Add(GetType(Person), "Age", soapAttrs)
  Dim myTypeMapping As XmlTypeMapping = (New SoapReflectionImporter(soapOverrides)).ImportTypeMapping(GetType(Person))
  Return New XmlSerializer(myTypeMapping)
End Function
サンプル・プログラム9:SoapAttributeOverridesクラスを使ってシリアライズを制御するコード(VB.NET版C#版

 これを実行すると、以下のような出力が得られる。

山田太郎
未設定
17
未設定
サンプル・プログラム9の実行結果

 また、以下のような内容のXMLファイルが「c:\sample.xml」に生成される。

<?xml version="1.0"?>
<Person xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="id1">
  <Nenrei xsi:type="xsd:int">17</Nenrei>
  <Name xsi:type="xsd:string">山田太郎</Name>
</Person>
サンプル・プログラム9で生成されるXML文書

 見てのとおり、本来Ageという要素名で出力されるはずであった要素が、Nenreiという名前で出力されていることが分かるだろう。要素名の変更は、属性を使って実現できることをすでに紹介しているが、それとは機能性が異なっている。属性を使って要素名を変更することは、シリアライズされる側のクラスの変更によって実現できる。しかし、ここで行っている要素名の変更は、シリアライズする側の変更によって実現したものである。

 この違いは極めて大きい。例えば、既存のクラス・ライブラリに含まれるクラスなど、ソース・コードを変更できないクラスのインスタンスをシリアライズするときに、要素名などを変更したいと思うことがあるかもしれない。そのような場合には、属性を使う方法では対処できず、ここで紹介しているようなオーバーライドという手段を取る必要がある。

 具体的なコードを説明する。ここでポイントとなるのは、SoapElementAttributeクラスのインスタンスを作成し、登録しているところである。SoapElementAttributeクラスとは属性を実現するクラスであるが、ここでは属性ではなく通常のクラスとしてインスタンスを作成している。このクラスの役割は属性として使った場合と同じで、メンバが要素としてシリアライズされることを指定する。そして、コンストラクタの引数の文字列が要素名を示す。この属性は、SoapAttributesクラスのインスタンスのSoapElementプロパティに設定されることで、シリアライズを制御するオブジェクトに関連付けられる。そして、それをSoapAttributeOverridesクラスのAddメソッドで登録する。登録する際に「Age」という名前を指定することにより、この属性クラスのインスタンスは、Ageというフィールドに関連付けられることになる。

 これらの一連の処理により、指定された属性が付加されているかのようにシリアライズ処理が行われるわけである。

 さて、今回はここまでである。次回からは連載を締めくくるために、筆者なりのXMLプログラミングの定石(パターン)について書いてみたいと考えている。こういうケースではこのような技術を選択すると良い結果になった、というような筆者の経験に基づく話を予定している。この連載では、多くの技術を紹介したため、どれを使ったらよいか迷ってしまう、というような読者もいると思うので、それに対するフォローという意味合いもある。請うご期待である。End of Article


 INDEX
  .NETで簡単XML
  第14回 オブジェクトをXMLでシリアライズ(6)
    1.ISerializableインターフェイスを用いたシリアライズ制御
    2.ISerializableインターフェイスを使ったクラスの継承
    3.XML Webサービス経由で使われるシリアライズの種類
  4.XmlSerializerを使ってSOAP形式でシリアライズする方法
 
インデックス・ページヘ  「連載 :.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 記事ランキング

本日 月間