ステップ 7 ハンズオン : XML を利用したプログラミング形式の永続化

マイクロソフト株式会社 デベロッパーマーケティング本部
デベロッパーエバンジェリスト 辻郷 隆史

目標 XML を利用したプログラミング形式の永続化
使用技術
  • XmlTextReader / XmlTextWriter ( TextReader / TextWriter )
  • XmlDocument
  • Visual Basic .NET / Windows フォーム
取り上げるトピックス
  • XmlTextReader / XmlTextWriter による永続化および復元方法
  • XmlDocument による永続化および復元方法
前提知識
関連記事

プログラミング形式によるデータの永続化

System.Xml 名前空間内のXml 関連クラスを使用することにより、 XML を利用したプログラミング形式の永続化を行うことが可能です。
今回のサンプル アプリケーションでは、下記の 2種類のプログラミング形式の永続化と復元の実装を行います。

図 1. サンプル アプリケーション

  1. XmlTextReader / XmlTextWriter による永続化と復元
  2. XmlDocument による永続化と復元

 

プロジェクトの種類
プロジェクトテンプレート
プロジェクト名
[Visual Basic プロジェクト] [Windows アプリケーション] ProgramToXmlApp

ツールボックスから、 Button コントロールを 4 つ、フォーム上に配置し以下のようにプロパティを設定します。

図 2. アプリケーションのデザイン

コントロール ID
プロパティ名
設定値
Button1 Text XmlTextWriter 永続化
Button2 Text XmlTextReader 復元
Button3 Text XmlDocument 永続化
Button4 Text XmlDocument 復元

永続化を行うデータとして 「 ステップ 7 ハンズオン : XML を利用したオブジェクトの永続化」にて使用した 2つのクラス ( Employee / Team )を作成します。
プロジェクトへ 1つ目のクラスを追加( Employee.vb )し、クラスを下記の通り実装します。

Imports System.Xml.Serialization

<XmlRoot(ElementName:="Emp")> _
Public Class Employee
    <XmlElement(ElementName:="ID")> _
    Public EmployeeID As Integer
    Private mFullName As String
    Private mBirthDate As DateTime

    Public Property FullName() As String
        Get
            Return Me.mFullName
        End Get
        Set(ByVal Value As String)
            Me.mFullName = Value
        End Set
    End Property

    Public Sub New()
    End Sub

    Public Sub New(ByVal id As Integer, ByVal name As String, ByVal bDate As DateTime)
        Me.EmployeeID = id
        Me.mFullName = name
        Me.mBirthDate = bDate
    End Sub
End Class

プロジェクトへ 2つ目のクラスを追加( Team.vb )し、クラスを下記の通り実装します。

Imports System.Xml.Serialization

Public Class Team
    GetType(Employee))> _
    Public Employees As New ArrayList
End Class

フォーム( Form1.vb )のコードを表示し、先頭に名前空間のインポートを追加します。

Imports System.Xml

Public Class Form1
    Inherits System.Windows.Forms.Form
…

Button1 / Click イベント ハンドラへ XmlTextWriter を使用した永続化処理を実装します。

Private Sub Button1_Click(…) Handles Button1.Click
    Dim myTeam As New Team          ' 永続化するオブジェクト

    For i As Integer = 1 To 3       ' 永続化するオブジェクトへデータ設定
        myTeam.Employees.Add(New Employee(i, "社員" + CStr(i), New DateTime(1970, 1, 1)))
    Next

    ' XmlTextWriter を使用した永続化
    Dim myWriter As New XmlTextWriter("ReadWriter.xml", System.Text.Encoding.UTF8)
    myWriter.WriteStartDocument()
    myWriter.WriteStartElement("Team")                          ' <Team>
    For Each emp As Employee In myTeam.Employees
        myWriter.WriteStartElement("Emp")                       ' <Emp>
        myWriter.WriteElementString("ID", CStr(emp.EmployeeID)) ' <ID>x</ID>
        myWriter.WriteElementString("FullName", emp.FullName)   ' <FullName>xxxx</FullName>
        myWriter.WriteEndElement()                              ' </Emp>
    Next
    myWriter.WriteEndElement()                                  ' </Team>
   myWriter.WriteEndDocument()
    myWriter.Close()
End Sub

ここでは、 XmlTextWriter を使用し、ReadWriter.xml へ XML ドキュメントを永続化しています。
XmlTextWriter では、永続化する XML の形式を考慮し、順番にタグやデータなどの書き込みを行い、永続化を実施しています。

Button4 / Click イベント ハンドラへ XmlDocument を使用した復元処理を実装します。

Private Sub Button2_Click(…) Handles Button2.Click
    Dim  myTeam As Team              ' 復元するオブジェクト

    ' XmlTextReader を使用した復元
    Dim  myReader As New   XmlTextReader("ReadWriter.xml")
    Dim  objEmp As Employee      ' Employee オブジェクト
    Dim  path As String            ' カレントパス格納用
    While myReader.Read()                           ' 次ノード(要素/属性/テキストなど)の読込
        Select Case  myReader.NodeType
            Case XmlNodeType.Element                            ' 要素の開始
                path &= "/" & myReader.Name                         ' パスへ要素名を追加
                Select Case  path
                    Case "/Team"
                        myTeam = New  Team
                    Case "/Team/Emp"
                        objEmp = New  Employee
                End Select
            Case XmlNodeType.EndElement                         ' 要素の終了
                Select Case  path
                    Case "/Team/Emp"
                        myTeam.Employees.Add(objEmp)
                End Select
                path = path.Substring(0, path.LastIndexOf("/"))     ' パスから最下位要素を削除
            Case XmlNodeType.Text                               ' テキスト(データ)
                Select Case  path
                    Case "/Team/Emp/ID"
                       objEmp.EmployeeID = CInt(myReader.Value)    ' データ(ID) の取得
                    Case "/Team/Emp/FullName"
                        objEmp.FullName = myReader.Value            ' データ(FullName)の取得
                End Select
        End Select
    End While
    myReader.Close()

    ' 復元したオブジェクトのデータ表示
    Dim  message As String  
    For Each  emp As  Employee In myTeam.Employees
        message += String.Format("{0} / {1}", emp.EmployeeID, emp.FullName) + vbCrLf
    Next
    MessageBox.Show(message)
End Sub

ここでは、 XmlTextReader を使用し、ReadWriter.xml から XML ドキュメントを復元しています。
XmlTextReader では、順方向への読み込みが可能です。
今回は Read メソッドを使用し、ノード単位(要素/属性/テキストなど)での読み込みを行い、NodeType および Value プロパティより要素やテキストを特定し、復元を実施しています。

Button3 / Click イベント ハンドラへ XmlDocument を使用した永続化処理を実装します。

Private Sub Button3_Click(…) Handles Button3.Click
    Dim  myTeam As New  Team              ' 永続化するオブジェクト

    For i As Integer = 1 To 3           ' 永続化するオブジェクトへデータ設定
        myTeam.Employees.Add(New  Employee(i, "社員" + CStr(i), New  DateTime(1970, 1, 1)))
    Next

    ' ==== XmlDocument の作成(Team オブジェクトのデータを設定) ====
    Dim  xmlDoc As New  XmlDocument       ' Xml ドキュメント オブジェクト
    xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)) ' XML 宣言の追加
    Dim  teamElement As XmlElement       ' Team 要素
    Dim  empElement As XmlElement        ' Emp 要素
   Dim  element As XmlElement           ' 要素格納用(ID / FullName 作成時使用)
    teamElement = xmlDoc.CreateElement("Team")      ' Team 要素作成
    xmlDoc.AppendChild(teamElement)                 ' Team 要素の追加
    For Each  emp As Employee In myTeam.Employees
        empElement = xmlDoc.CreateElement("Emp")    ' Emp 要素作成
        teamElement.AppendChild(empElement)         ' Team 要素へ Emp 要素の追加
        element = xmlDoc.CreateElement("ID")        ' ID 要素作成
        element.InnerText = CStr(emp.EmployeeID)    ' ID 要素内のテキスト設定
        empElement.AppendChild(element)             ' Emp 要素へ ID 要素の追加
        element = xmlDoc.CreateElement("FullName")  ' FullName 要素作成
        element.InnerText = emp.FullName            ' FullName 要素内のテキスト設定
        empElement.AppendChild(element)             ' Emp 要素へ FullName 要素の追加
    Next

    ' ==== XmlDocument の永続化 ====
    xmlDoc.Save("XmlDocument.xml")
End Sub

ここでは、 XmlDocument 関連の処理として、大きく分けて XmlDocument の作成と XmlDocument の永続化の 2つの処理を行っています。

【XmlDocument の作成】

始めにルート要素である Team 要素を作成後、その後 子 / 孫要素を作成および追加し、 XmlDocument を作成しています。

【XmlDocument の永続化】

Save メソッドを使用し、 作成済みの XmlDocumentを XmlDocument.xml ファイルへ永続化しています。

Button4 / Click イベント ハンドラへ XmlDocument を使用した復元処理を実装します。

Private Sub Button4_Click(…) Handles Button4.Click
    Dim  myTeam As New  Team              ' 復元するオブジェクト

    Dim  xmlDoc As New  XmlDocument       ' Xml ドキュメント オブジェクト

    ' ==== XmlDocument の復元 ====
    xmlDoc.Load("XmlDocument.xml")

    ' ==== XmlDocument の参照(Team オブジェクトの作成) ====
    Dim  node As XmlNode                 ' ノード格納用(ID / FullName 参照時使用)
    Dim  objEmp As Employee              ' Employee オブジェクト
    For Each  empNode As XmlNode In xmlDoc.SelectNodes("/Team/Emp")  ' /Team/Emp ノード検索
        objEmp = New  Employee
        node = empNode.SelectSingleNode("ID")        ' /Team/Emp/ID ノード検索
        objEmp.EmployeeID = CInt(node.InnerText)     ' /Team/Emp/ID 内のテキスト(ID)取得
        node = empNode.SelectSingleNode("FullName")  ' /Team/Emp/FullName ノード検索
        objEmp.FullName = node.InnerText             ' /Team/Emp/ID 内のテキスト(FullName)取得
        myTeam.Employees.Add(objEmp)
    Next

    ' 復元したオブジェクトのデータ表示
    Dim  message As String 
    For Each  emp As Employee In myTeam.Employees
        message += String.Format("{0} / {1}", emp.EmployeeID, emp.FullName) + vbCrLf
    Next
    MessageBox.Show(message)
End Sub

ここでは、 XmlDocument 関連の処理として、大きく分けて XmlDocument の復元と XmlDocument の参照の 2つの処理を行っています。

【XmlDocument の復元】

Load メソッドを使用し XmlDocument.xml ファイルより XmlDocument を復元しています。

【XmlDocument の参照】

ノード(要素)を指定して XmlDocument を検索し、各テキストなどのデータを取得しています。

以上で、実装は完了です。では実際にビルドしてアプリケーションを動かしてみましょう。

アプリケーションにて各ボタンをクリックし、 Team オブジェクトをXML ドキュメントとして永続化および復元できることを確認します。
ま た、アプリケーションと同一フォルダ内に作成された XML ドキュメント ReadWriter.xml および XmlDocument.xml を Internet Explorer などで開き、 Team オブジェクトが XML ドキュメントとして永続化されていることを確認します。

まとめ

Xml 関連クラスを使用することにより、プログラミングによる永続化を行うことが可能です。
XmlSerializer クラスを使用したオブジェクトの永続化とは異なり、 XML の階層構造 / 要素 / テキスト(データ) などをプログラミングによる柔軟な制御を行うことが可能です。

今回ご紹介したプログラミング形式のそれぞれの特徴については下記の通りとなります。

形式
特徴
XmlReader / XmlWriter
  • 非キャッシュ、前方参照専用のストリーム アクセス
  • シーケンシャル アクセスのみ
  • ライトウェイト
XmlDocument
  • インメモリの XML ドキュメント
  • ランダム アクセス可能
  • XML ドキュメントのサイズに応じたメモリを使用
  • ノードの追加や削除などの柔軟なデータ編集可能

上記の特徴を考慮し、単純にプログラミングによる永続化を行いたい場合は、 XmlReader / XmlWriter を使用し、 XmlDocument の特徴であるインメモリでの XML ドキュメント操作(ランダム アクセス / 柔軟なデータ編集)を行いたい場合のみ、 XmlDocument を使用するなど、用途に応じた使い分けを行うことが可能です。

このように .NET Framework では、 プログラミング形式によるデータの永続化を行うことが可能です。

参考資料

  • .NET Framework 開発者ガイド / XML ドキュメント オブジェクト モデル (DOM)
  • .NET Framework 開発者ガイド / XML シリアル化を制御する属性
  • .NET Framework 開発者ガイド / 属性を使用した XML シリアル化の制御

ページのトップへ