LoginSignup
2
4

More than 5 years have passed since last update.

DataContractSerializerでXMLをデシリアライズする

Last updated at Posted at 2018-05-11

.NET(C#)で、設定情報をXMLで管理するための実装方法を試してみた。

1.設定情報のxmlファイルを作成

【CompanyInfo.xml】

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns="http://schemas.datacontract.org/2004/07/XMLDataContract">
    <company>ほんにゃら産業</company>
    <departments>
        <department>
            <name>営業部</name>
            <employees>
                <employee>
                    <name>かりあげくん</name>
                    <gender></gender>
                </employee>
                <employee>
                    <name>木村課長</name>
                    <gender></gender>
                </employee>
                <employee>
                    <name>鈴木</name>
                    <gender></gender>
                </employee>
                <employee>
                    <name>ヒサエさん</name>
                    <gender></gender>
                </employee>
            </employees>
        </department>
        <department>
            <name>総務部</name>
            <employees>
                <employee>
                    <name>佐藤クン</name>
                    <gender></gender>
                </employee>
                <employee>
                    <name>山田さん</name>
                    <gender></gender>
                </employee>
                <employee>
                    <name>太子さん</name>
                    <gender></gender>
                </employee>
            </employees>
        </department>
    </departments>
</root>
  • プロパティの「出力ディレクトリにコピー」は「コピーをしない」がデフォルトだが、そのままだとファイルがない旨のエラーが発生するので、それ以外に設定する。
  • xmlns属性を追加しないとエラーになる。プロジェクトからxmlファイルを追加する場合は、自動的に挿入されないので手入力する必要がある。
<root xmlns="http://schemas.datacontract.org/2004/07/XMLDataContract" >
<!-- xmlns="http://schemas.datacontract.org/2004/07/名前空間名 -->

2.デシリアライズのためのクラスを作成

  • 参照設定に「System.Runtime.Serialization」を追加する。
  • デシリアライズさせるためのクラスを定義する。まずは会社名(company)だけをやってみる。

【CompanyInfo.cs】

using System.Runtime.Serialization;

namespace XMLDataContract {
    [DataContract(Name = "root")]
    public class CompanyInfo {

        [DataMember(Name = "company")]
        public string Company {
            get;private set;
        }
    }
}

3.デシリアライズのメソッドを作成

  • 汎用的に利用するメソッドを作成

【XMLDataContract.cs】

using System.IO;
using System.Xml;
using System.Runtime.Serialization;

namespace XMLDataContract {
    public class XMLDataContract {
        public static T Load<T>(Stream stream) where T : new() {
            T result = default(T);

            var serialiser = new DataContractSerializer(typeof(T));

            using(var reader = XmlReader.Create(stream)) {
                result = (T)serialiser.ReadObject(reader);
            }

            return result;
        }
    }
}

単体テストのコード

using Microsoft.VisualStudio.TestTools.UnitTesting;
using XMLDataContract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace XMLDataContract.Tests {
    [TestClass()]
    public class XMLDataContractTests {
        [TestMethod()]
        public void LoadTest() {

            //Arrange
            string filename = "CompanyInfo.xml";

            using(Stream filestream = File.Open(filename, FileMode.Open)) {
                //Act
                var deserialize = XMLDataContract.Load<CompanyInfo>(filestream);

                //Assert
                Assert.AreEqual(deserialize.Company, "ほんにゃら産業");
            }

        }
    }
}

実際にテストを実行すると問題なければ、その他の属性もデシリアライズさせてみる。

4.その他の属性をデシリアライズ

  • CompanyInfo.xmlは部門(department)が配列(departments)になっていて、更に従業員(employee)が配列(employees)になっている。これらをデシリアライズさせるには「CollectionDataContractAttribute」を使用する。先程作成した「CompanyInfo.cs」に追記する。
using System.Runtime.Serialization;
using System.Collections.Generic;

namespace XMLDataContract {
    [DataContract(Name = "root")]
    public class CompanyInfo {

        [DataMember(Name = "company")]
        public string Company {
            get;private set;
        }

        [DataMember(Name = "departments")]
        public Departments Departments {
            get;private set;
        }
    }

    [CollectionDataContract(Name = "departments",ItemName = "department")]
    public class Departments : List<Department> {

    }

    [DataContract(Name = "department")]
    public class Department {

        [DataMember(Name = "name")]
        public string DeparmentName {
            get;private set;
        }
    }
}

単体テスト

        [TestMethod()]
        public void LoadTest2() {

            //Arrange
            string filename = "CompanyInfo.xml";

            using(Stream filestream = File.Open(filename, FileMode.Open)) {
                //Act
                var deserialize = XMLDataContract.Load<CompanyInfo>(filestream);

                //Assert
                Assert.AreEqual(deserialize.Departments[1].DeparmentName, "総務部");
            }

        }


5.最終型の実装

using System.Runtime.Serialization;
using System.Collections.Generic;

namespace XMLDataContract {
    [DataContract(Name = "root")]
    public class CompanyInfo {

        [DataMember(Name = "company")]
        public string Company {
            get;private set;
        }

        [DataMember(Name = "departments")]
        public Departments Departments {
            get;private set;
        }
    }

    [CollectionDataContract(Name = "departments",ItemName = "department")]
    public class Departments : List<Department> {

    }

    [DataContract(Name = "department")]
    public class Department {

        [DataMember(Name = "name",Order = 1)]
        public string DeparmentName {
            get;private set;
        }

        [DataMember(Name = "employees",Order = 2)]
        public Employees Employees {
            get; private set;
        }
    }

    [CollectionDataContract(Name = "employees", ItemName = "employee")]
    public class Employees : List<Emplyee> {

    }

    [DataContract(Name = "employee")]
    public class Emplyee {
        [DataMember(Name = "name",Order = 1)]
        public string EmployeeName {
            get;private set;
        }

        [DataMember(Name = "gender",Order = 2)]
        public string Gender {
            get;private set;
        }
    }
}

ここでの注意点として、CollectionDataContractAttributeのItemNameに設定しているクラス内のDataMamberAttributeに「Order=」を設定していないとデシリアライズされない。ここで結構悩みました。

単体テスト

        [TestMethod()]
        public void LoadTest3() {

            //Arrange
            string filename = "CompanyInfo.xml";

            using(Stream filestream = File.Open(filename, FileMode.Open)) {

                //Act
                var deserialize = XMLDataContract.Load<CompanyInfo>(filestream);

                //Assert
                Assert.AreEqual(deserialize.Departments[0].Employees[1].EmployeeName, "木村課長");
                Assert.AreEqual(deserialize.Departments[0].Employees[1].Gender, "男");

            }
        }

以上です。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4