け日記

SIerから転職したWebアプリエンジニアが最近のIT技術キャッチアップに四苦八苦するブログ

C# XmlSerializerでXMLを扱う

XMLでリクエスト/レスポンスするAPIへアクセスする機会がありましたので、XmlSerializerの使い方を備忘録にしておきます。

XMLシリアライズ/デシリアライズする

まずはC#オブジェクト(ここではBook)とXML形式の文字列でシリアライズ/デシリアライズさせる方法です。

Bookクラス用のXmlSerializer(System.Xml.Serialization名前空間)を定義して、Serializeメソッドでシリアライズできます。

  • publicのフィールドまたはプロパティがXML要素になりますが、XmlRootAttribute、XmlElementAttributeで要素名を指定しています
    • これらの属性が無い場合は、フィールド名・プロパティ名がそのまま要素名になります
  • XMLの繰り返し構造を定義することもでき、その場合はXmlArrayAttributeで親要素名、XmlArrayItemAttributeで子要素名を指定できます
  • クラスは入れ子構造にできます(Book内にListを定義しています)

デシリアライズは、同様にBookクラス用のXmlSerializerを定義し、Deserializeメソッドでデシリアライズします。

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;

namespace ConsoleApplication
{
    [XmlRoot("book")]
    public class Book
    {
        [XmlElement("title")]
        public string Title { get; set; }

        [XmlElement("publised")]
        public DateTime Published { get; set; }

        [XmlArray("authors")]
        [XmlArrayItem("author")]
        public List<Author> Authors { get; set; }
    }

    public class Author
    {
        [XmlElement("authorName")]
        public string AuthorName { get; set; }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            var book = new Book
            {
                Title =
                    "The Art of Readable Code: Simple and Practical Techniques for Writing Better Code (Theory in Practice)",
                Published = new DateTime(2011, 11, 3),
                Authors = new List<Author>
                {
                    new Author {AuthorName = "Dustin Boswell"},
                    new Author {AuthorName = "Trevor Foucher"}
                }
            };

            // シリアライズ
            var writer = new StringWriter(); // 出力先のWriterを定義
            var serializer = new XmlSerializer(typeof(Book)); // Bookクラスのシリアライザを定義
            serializer.Serialize(writer, book);

            var xml = writer.ToString(); 
            Console.WriteLine(xml);

            // デシリアライズ
            var deserializedBook = (Book)serializer.Deserialize(new StringReader(xml));

            Console.WriteLine($"Title: {deserializedBook.Title}");
            Console.WriteLine($"Published: {deserializedBook.Published}");
            foreach (var author in deserializedBook.Authors)
            {
                Console.WriteLine($"AuthorName: {author.AuthorName}");
            }
        }
    }
}

実行すると、以下のように出力されます。

  • ルート要素にデフォルトで名前空間(xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://ww w.w3.org/2001/XMLSchema")が設定されます
<?xml version="1.0" encoding="utf-16"?>
<book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://ww
w.w3.org/2001/XMLSchema">
  <title>The Art of Readable Code: Simple and Practical Techniques for Writing B
etter Code (Theory in Practice)</title>
  <publised>2011-11-03T00:00:00</publised>
  <authors>
    <author>
      <authorName>Dustin Boswell</authorName>
    </author>
    <author>
      <authorName>Trevor Foucher</authorName>
    </author>
  </authors>
</book>
Title: The Art of Readable Code: Simple and Practical Techniques for Writing Bet
ter Code (Theory in Practice)
Published: 2011/11/03 0:00:00
AuthorName: Dustin Boswell
AuthorName: Trevor Foucher

大まかな使い方は以上で、以下はtipsです。

デフォルトの名前空間を削除する

Serializeメソッドでは、XmlSerializerNamespacesオブジェクトを引数にとることができ、任意のXML名前空間を定義できます。 先程のデフォルトの名前空間が不要の場合、空のXmlSerializerNamespacesを渡すことで削除できます。

var namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
serializer.Serialize(writer, book, namespaces);

book要素から名前空間が削除されていることが確認できます。

<?xml version="1.0" encoding="utf-16"?>
<book>
  <title>The Art of Readable Code: Simple and Practical Techniques for Writing B
etter Code (Theory in Practice)</title>
・・・

encoding=“utf-8"にする

出力のXML宣言を見ますと、encoding="utf-16"となっています。 StringWriterのEncodingプロパティの値がEncoding.UTF16になっているためですが、このプロパティはsetアクセサを持たないため、直接書き換えることができません。

そのため、StringWriterを継承したクラスを新たに作り、Encodingプロパティをオーバライドすることで、Encoding.UTF8に変えることができます。

private sealed class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding => Encoding.UTF8;
}

var writer = new Utf8StringWriter();
serializer.Serialize(writer, book, namespaces);

シリアライズされたXMLを見ると、encoding="utf-8"と出力されることが確認できます。

<?xml version="1.0" encoding="utf-8"?>
<book>
  <title>The Art of Readable Code: Simple and Practical Techniques for Writing B
etter Code (Theory in Practice)</title>
・・・