C# csharp XML操作の決定版!読み込み(Load), 書き出し(Write), LINQ, オブジェクト変換

C# でスマートに XML を操る!読み込みから書き出しまで完全ガイド

システム開発において、設定ファイルやデータ連携の形式として XML (Extensible Markup Language) を扱う場面は少なくありません。C# では、.NET Framework に標準搭載されている機能を利用することで、XML ファイルの読み込みや書き出しを簡単に行うことができます。

このブログでは、C#XML ファイルを効率的に扱うための基本的な方法から、具体的なコード例、そして注意点までを分かりやすく解説します。これを読めば、あなたも C#XML を自由自在に操れるようになるでしょう!

XML 読み込みの基本:XmlDocument クラス

C#XML ファイルを読み込む最も基本的な方法は、System.Xml 名前空間にある XmlDocument クラスを使用することです。

手順:

  1. System.Xml 名前空間を using ディレクティブで追加します。
  2. XmlDocument クラスのインスタンスを作成します。
  3. XmlDocument オブジェクトの Load() メソッドに XML ファイルのパスを指定して XML ファイルを読み込みます。

基本的なコード例:


using System.Xml;

public class XmlReaderExample
{
    public static void ReadXmlFile(string filePath)
    {
        XmlDocument xmlDoc = new XmlDocument();

        try
        {
            xmlDoc.Load(filePath);
            Console.WriteLine("XML ファイルの読み込みに成功しました。");

            // ここで XML ドキュメントを操作する処理を記述します
        }
        catch (XmlException ex)
        {
            Console.WriteLine($"XML ファイルの読み込み中にエラーが発生しました: {ex.Message}");
        }
        catch (System.IO.FileNotFoundException)
        {
            Console.WriteLine($"指定されたファイルが見つかりませんでした: {filePath}");
        }
    }

    public static void Main(string[] args)
    {
        string xmlFilePath = "sample.xml"; // 読み込む XML ファイルのパス
        ReadXmlFile(xmlFilePath);
    }
}

XML ドキュメントの操作:

XmlDocument オブジェクトが XML ファイルの内容をメモリ上に読み込んだら、様々なプロパティやメソッドを使って XML ドキュメントを操作できます。

  • ルート要素の取得: xmlDoc.DocumentElement プロパティ
  • ノードのリストを取得: xmlDoc.GetElementsByTagName("タグ名") メソッド
  • ノードの属性を取得: XmlNode.Attributes["属性名"].Value

具体的なノードへのアクセス例:


// ルート要素を取得
XmlElement rootElement = xmlDoc.DocumentElement;
Console.WriteLine($"ルート要素名: {rootElement.Name}");

// 特定のタグ名の要素をすべて取得
XmlNodeList bookList = xmlDoc.GetElementsByTagName("book");
Console.WriteLine($"見つかった book 要素の数: {bookList.Count}");

// 各 book 要素を処理
foreach (XmlNode bookNode in bookList)
{
    // title 要素の値を取得
    XmlNode titleNode = bookNode.SelectSingleNode("title");
    if (titleNode != null)
    {
        Console.WriteLine($"書籍タイトル: {titleNode.InnerText}");
    }

    // price 属性の値を取得
    if (bookNode.Attributes["price"] != null)
    {
        Console.WriteLine($"価格: {bookNode.Attributes["price"].Value}");
    }
}

XML 出力の基本:XmlWriter クラス

C#XML ファイルを出力するには、XmlWriter クラスを使用するのが一般的です。XmlWriter は、XML ドキュメントをストリームに出力するための機能を提供します。

手順:

  1. XmlWriterSettings クラスを使用して、出力形式などの設定を行います(インデント、エンコーディングなど)。
  2. XmlWriter.Create() メソッドにファイルパスと設定オブジェクトを指定して XmlWriterインスタンスを作成します。
  3. XmlWriter オブジェクトのメソッド (WriteStartDocument(), WriteStartElement(), WriteAttributeString(), WriteString(), WriteEndElement(), WriteEndDocument()) を使用して XML ドキュメントを記述します。
  4. 最後に、XmlWriter オブジェクトの Close() メソッドを呼び出してストリームを閉じ、ファイルを保存します。

基本的なコード例:


using System.Xml;

public class XmlWriterExample
{
    public static void WriteXmlFile(string filePath)
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true; // インデントを設定して見やすくする
        settings.Encoding = System.Text.Encoding.UTF8; // エンコーディングを設定

        using (XmlWriter writer = XmlWriter.Create(filePath, settings))
        {
            writer.WriteStartDocument(); // XML ドキュメントの開始

            writer.WriteStartElement("bookstore"); // ルート要素の開始

            writer.WriteStartElement("book"); // book 要素の開始
            writer.WriteAttributeString("price", "2980"); // price 属性の追加

            writer.WriteStartElement("title"); // title 要素の開始
            writer.WriteString("C# XML プログラミング"); // title 要素の値
            writer.WriteEndElement(); // title 要素の終了

            writer.WriteStartElement("author"); // author 要素の開始
            writer.WriteString("山田 太郎"); // author 要素の値
            writer.WriteEndElement(); // author 要素の終了

            writer.WriteEndElement(); // book 要素の終了

            writer.WriteStartElement("book"); // 別の book 要素
            writer.WriteAttributeString("price", "3500");

            writer.WriteStartElement("title");
            writer.WriteString("はじめての XML");
            writer.WriteEndElement();

            writer.WriteStartElement("author");
            writer.WriteString("鈴木 一郎");
            writer.WriteEndElement();

            writer.WriteEndElement(); // book 要素の終了

            writer.WriteEndElement(); // bookstore 要素の終了

            writer.WriteEndDocument(); // XML ドキュメントの終了
        }

        Console.WriteLine($"XML ファイルが {filePath} に書き出されました。");
    }

    public static void Main(string[] args)
    {
        string xmlFilePath = "output.xml"; // 出力する XML ファイルのパス
        WriteXmlFile(xmlFilePath);
    }
}

より簡潔な XML 操作:LINQ to XML

.NET Framework 3.5 以降では、LINQ to XML を使用することで、XML の読み込み、書き出し、操作をより簡潔な構文で行うことができます。

XML 読み込み (LINQ to XML):


using System.Xml.Linq;
using System.Linq;

public class LinqToXmlReaderExample
{
    public static void ReadXmlFileLinq(string filePath)
    {
        try
        {
            XDocument xmlDoc = XDocument.Load(filePath);
            Console.WriteLine("XML ファイルの読み込みに成功しました (LINQ to XML)。");

            // ルート要素名を取得
            XElement rootElement = xmlDoc.Root;
            Console.WriteLine($"ルート要素名: {rootElement.Name}");

            // book 要素をすべて取得し、タイトルと価格を表示
            var books = from book in xmlDoc.Descendants("book")
                        select new
                        {
                            Title = book.Element("title")?.Value,
                            Price = (string)book.Attribute("price")
                        };

            foreach (var book in books)
            {
                Console.WriteLine($"書籍タイトル: {book.Title}, 価格: {book.Price}");
            }
        }
        catch (System.IO.FileNotFoundException)
        {
            Console.WriteLine($"指定されたファイルが見つかりませんでした: {filePath}");
        }
        catch (XmlException ex)
        {
            Console.WriteLine($"XML ファイルの読み込み中にエラーが発生しました (LINQ to XML): {ex.Message}");
        }
    }

    public static void Main(string[] args)
    {
        string xmlFilePath = "sample.xml";
        ReadXmlFileLinq(xmlFilePath);
    }
}

XML 出力 (LINQ to XML):


using System.Xml.Linq;

public class LinqToXmlWriterExample
{
    public static void WriteXmlFileLinq(string filePath)
    {
        XDocument xmlDoc = new XDocument(
            new XDeclaration("1.0", "utf-8", "yes"), // XML 宣言
            new XElement("bookstore", // ルート要素
                new XElement("book", new XAttribute("price", "3200"),
                    new XElement("title", "LINQ to XML 入門"),
                    new XElement("author", "田中 一郎")
                ),
                new XElement("book", new XAttribute("price", "2800"),
                    new XElement("title", "XML の基礎"),
                    new XElement("author", "高橋 さゆり")
                )
            )
        );

        try
        {
            xmlDoc.Save(filePath);
            Console.WriteLine($"XML ファイルが {filePath} に書き出されました (LINQ to XML)。");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"XML ファイルの書き出し中にエラーが発生しました (LINQ to XML): {ex.Message}");
        }
    }

    public static void Main(string[] args)
    {
        string xmlFilePath = "output_linq.xml";
        WriteXmlFileLinq(xmlFilePath);
    }
}

LINQ to XML を使用すると、XML ドキュメントの構造をオブジェクトとして扱い、より直感的で簡潔なコードで XML の操作を行うことができます。

POCO クラスを使った XML の読み書き

XML のデータを直接 XML ドキュメントとして操作するだけでなく、C# のクラス(POCO クラス)と XML を相互に変換することで、よりオブジェクト指向的なプログラミングが可能になります。これには、System.Xml.Serialization 名前空間にある XmlSerializer クラスを使用します。

1. POCO クラスの定義

まず、XML の構造に対応した C# のクラスを定義します。XML の要素や属性は、クラスのプロパティとして定義します。XmlRootAttribute でルート要素名を指定したり、XmlElementAttributeXmlAttributeAttribute で要素や属性へのマッピングを制御したりできます。

例:書籍 (Book) クラスと書籍リスト (Bookstore) クラス


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

[XmlRoot("bookstore")]
public class Bookstore
{
    [XmlElement("book")]
    public List Books { get; set; }
}

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

    [XmlElement("author")]
    public string Author { get; set; }

    [XmlAttribute("price")]
    public decimal Price { get; set; }
}

2. XML ファイルの読み込み (POCO クラスへのデシリアライズ)

XmlSerializer クラスの Deserialize() メソッドを使用すると、XML ファイルの内容を POCO クラスのインスタンスに変換(デシリアライズ)できます。

コード例:


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

public class XmlDeserializeExample
{
    public static Bookstore ReadXmlAsObject(string filePath)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(Bookstore));

        try
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Open))
            {
                Bookstore bookstore = (Bookstore)serializer.Deserialize(fs);
                Console.WriteLine("XML ファイルのデシリアライズに成功しました。");
                return bookstore;
            }
        }
        catch (System.IO.FileNotFoundException)
        {
            Console.WriteLine($"指定されたファイルが見つかりませんでした: {filePath}");
            return null;
        }
        catch (System.Xml.XmlException ex)
        {
            Console.WriteLine($"XML ファイルの形式が不正です: {ex.Message}");
            return null;
        }
    }

    public static void Main(string[] args)
    {
        string xmlFilePath = "books.xml"; // デシリアライズする XML ファイル
        Bookstore bookstore = ReadXmlAsObject(xmlFilePath);

        if (bookstore != null && bookstore.Books != null)
        {
            foreach (Book book in bookstore.Books)
            {
                Console.WriteLine($"タイトル: {book.Title}, 著者: {book.Author}, 価格: {book.Price}");
            }
        }
    }
}

books.xml の例:

<?xml version="1.0" encoding="utf-8"?>
<bookstore>
  <book price="2980">
    <title>C# XML プログラミング</title>
    <author>山田 太郎</author>
  </book>
  <book price="3500">
    <title>はじめての XML</title>
    <author>鈴木 一郎</author>
  </book>
</bookstore>

3. XML ファイルの書き出し (POCO クラスからのシリアライズ)

XmlSerializer クラスの Serialize() メソッドを使用すると、POCO クラスのインスタンスの内容を XML ファイルに書き出し(シリアライズ)できます。

コード例:


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

public class XmlSerializeExample
{
    public static void WriteObjectAsXml(string filePath, Bookstore bookstore)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(Bookstore));
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.Encoding = System.Text.Encoding.UTF8;

        try
        {
            using (XmlWriter writer = XmlWriter.Create(filePath, settings))
            {
                serializer.Serialize(writer, bookstore);
                Console.WriteLine($"Bookstore オブジェクトが {filePath} に XML としてシリアライズされました。");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"XML ファイルのシリアライズ中にエラーが発生しました: {ex.Message}");
        }
    }

    public static void Main(string[] args)
    {
        string xmlFilePath = "output_books.xml"; // シリアライズ先の XML ファイル
        Bookstore bookstore = new Bookstore
        {
            Books = new List
            {
                new Book { Title = "C# オブジェクト指向", Author = "佐藤 二郎", Price = 3800 },
                new Book { Title = "XML データ処理", Author = "田中 三郎", Price = 3200 }
            }
        };

        WriteObjectAsXml(xmlFilePath, bookstore);
    }
}

output_books.xml の内容例:

<?xml version="1.0" encoding="utf-8"?>
<bookstore xmlns:xsi="[http://www.w3.org/2001/XMLSchema-instance](http://www.w3.org/2001/XMLSchema-instance)" xmlns:xsd="[http://www.w3.org/2001/XMLSchema](http://www.w3.org/2001/XMLSchema)">
  <book price="3800">
    <title>C# オブジェクト指向</title>
    <author>佐藤 二郎</author>
  </book>
  <book price="3200">
    <title>XML データ処理</title>
    <author>田中 三郎</author>
  </book>
</bookstore>

注意点

  • 例外処理: XML ファイルの読み込みや書き出し時には、ファイルが見つからない、XML の形式が不正であるなどの例外が発生する可能性があります。必ず try-catch ブロックで例外処理を行うようにしましょう。
  • エンコーディング: XML ファイルのエンコーディングC# アプリケーションのエンコーディングが一致していることを確認してください。XmlWriterSettingsエンコーディングを指定できます。
  • 大きな XML ファイル: 非常に大きな XML ファイルを XmlDocument で読み込むと、メモリを大量に消費する可能性があります。そのような場合は、XmlReader クラスを使用してストリームとして順次読み込むことを検討してください。

まとめ

C#XML を扱う方法はいくつかありますが、POCO クラスと XmlSerializer を組み合わせることで、XML のデータをより自然な C# のオブジェクトとして扱うことができます。これにより、XML データの操作がより直感的になり、コードの保守性も向上します。

XML の構造が明確な場合は、ぜひこの POCO クラスを使った方法を検討してみてください。