C#でXMLを読み書きする方法|初心者向けにXmlDocument・LINQ to XML・シリアライズを徹底解説

はじめに

C#でXMLを扱う方法は、大きく分けて「XmlDocument」「LINQ to XML」「XmlSerializer」の3つがあります。

XMLファイルから設定値を読み込んだり、ユーザー情報を保存したり、外部APIから取得したXMLデータを解析したりする場面では、C#のXML操作を理解しておくと非常に便利です。

この記事では、C#でXMLを読み書きする基本から、XmlDocument、LINQ to XML、XmlSerializerを使った実践的なコード例まで、初心者にもわかりやすく解説します。

1. C#でXMLを読み書きする基本

1-1. XMLとは?C#で扱う場面

XMLとは「Extensible Markup Language」の略で、データをタグで囲んで表現する形式です。

たとえば、以下のようにユーザー名や年齢などの情報を階層構造で表せます。

XML
<user>
<name>Tanaka</name>
<age>30</age>
</user>

C#でXMLを扱う主な場面には、次のようなものがあります。

・アプリケーションの設定ファイルを読み込む
・ユーザー情報や商品情報をXMLファイルに保存する
・外部APIから取得したXMLデータを解析する
・古いシステムとのデータ連携に使う
・オブジェクトとXMLを相互変換する

現在はJSONが使われる場面も多いですが、XMLは設定ファイル、業務システム、外部連携、古いAPIなどで今でもよく利用されています。

1-2. C#でXMLを扱う主な方法

C#でXMLを読み書きする代表的な方法は、次の3つです。

・XmlDocument
・LINQ to XML
・XmlSerializer

XmlDocumentは、XML全体をDOMとして読み込み、ノード単位で細かく操作する方法です。

LINQ to XMLは、XDocumentやXElementを使って、よりシンプルで直感的にXMLを扱う方法です。

XmlSerializerは、C#のクラスとXMLを相互に変換する方法です。XMLをオブジェクトとして扱いたい場合に便利です。

1-3. XmlDocument・LINQ to XML・XmlSerializerの違い

XmlDocumentは、古くから使われているXML操作用のクラスです。XPathを使って特定のノードを取得できるため、既存のXMLを細かく編集したい場合に向いています。

LINQ to XMLは、C#らしい書き方でXMLを操作できる方法です。コードが短くなりやすく、初心者にも比較的わかりやすいのが特徴です。

XmlSerializerは、XMLのタグとC#のクラスのプロパティを対応させて、XMLとオブジェクトを変換します。XMLをデータモデルとして扱いたい場合に便利です。

簡単にいうと、次のように使い分けるとよいでしょう。

XmlDocument    :既存XMLを細かく読み書きしたい場合
LINQ to XML :シンプルにXMLを読み書きしたい場合
XmlSerializer :クラスとXMLを変換したい場合

1-4. この記事で使うサンプルXML

この記事では、以下のXMLファイルを例にして解説します。

ファイル名は books.xml とします。

XML
<?xml version="1.0" encoding="utf-8"?>
<books>
<book id="1" category="programming">
<title>C#入門</title>
<author>山田太郎</author>
<price>2800</price>
</book>
<book id="2" category="database">
<title>SQL基礎</title>
<author>佐藤花子</author>
<price>3200</price>
</book>
<book id="3" category="programming">
<title>XML実践ガイド</title>
<author>鈴木一郎</author>
<price>2500</price>
</book>
</books>

このXMLでは、books がルート要素で、その中に複数の book 要素があります。

book 要素には、idcategory という属性があり、子要素として titleauthorprice を持っています。

2. C#でXMLファイルを読み込む準備

2-1. 必要な名前空間

C#でXMLを扱うには、使用する方法に応じて名前空間を追加します。

XmlDocumentを使う場合は、次の名前空間を使います。

C#
using System.Xml;

LINQ to XMLを使う場合は、次の名前空間を使います。

C#
using System.Xml.Linq;
using System.Linq;

XmlSerializerを使う場合は、次の名前空間を使います。

C#
using System.Xml.Serialization;
using System.IO;

また、Listを使う場合は以下も追加します。

C#
using System.Collections.Generic;

基本的には、使いたいXML操作の種類に合わせて必要な名前空間を追加すれば問題ありません。

2-2. XMLファイルの配置場所とパス指定

XMLファイルを読み込むときに初心者がつまずきやすいのが、ファイルパスの指定です。

たとえば、実行ファイルと同じフォルダに books.xml を置いた場合は、次のように相対パスで指定できます。

C#
string path = "books.xml";

プロジェクト内の Data フォルダに配置する場合は、次のように指定します。

C#
string path = Path.Combine("Data", "books.xml");

絶対パスを指定することもできます。

C#
string path = @"C:\Temp\books.xml";

文字列の前に @ を付けると、バックスラッシュをエスケープせずに書けます。

C#
string path = @"C:\Temp\books.xml";

通常の文字列として書く場合は、次のように \\ と書く必要があります。

C#
string path = "C:\\Temp\\books.xml";

Visual StudioでXMLファイルをプロジェクトに追加した場合は、ファイルのプロパティで「出力ディレクトリにコピー」を「新しい場合はコピーする」または「常にコピーする」に設定しておくと、実行時にファイルが見つからない問題を防ぎやすくなります。

2-3. 文字コードとエンコーディングの注意点

XMLファイルでは、先頭に文字コードを指定することがあります。

XML
<?xml version="1.0" encoding="utf-8"?>

日本語を含むXMLでは、基本的にUTF-8で保存するのがおすすめです。

C#でXMLを書き込む場合も、保存時のエンコーディングに注意しましょう。

LINQ to XMLやXmlDocumentの Save メソッドを使う場合、多くのケースでは問題なく保存できますが、別のエディタでShift_JISなどとして保存したXMLを読み込む場合、文字化けや読み込みエラーが起きることがあります。

XML宣言のエンコーディングと、実際のファイルの文字コードが一致していることが重要です。

2-4. 読み込み時によくあるエラー

C#でXMLを読み込むときによくあるエラーには、次のようなものがあります。

・ファイルパスが間違っている
・XMLファイルが存在しない
・XMLの形式が不正
・ルート要素が存在しない
・タグの閉じ忘れがある
・文字コードが一致していない
・取得しようとした要素が存在せずnullになる

たとえば、次のXMLは title タグが閉じられていないため不正です。

XML
<book>
<title>C#入門
</book>

正しくは、次のように閉じタグが必要です。

XML
<book>
<title>C#入門</title>
</book>

XMLは開始タグと終了タグの対応が厳密なので、読み込み前に形式が正しいか確認しておきましょう。

3. XmlDocumentでXMLを読み込む方法

3-1. XmlDocumentとは

XmlDocumentは、XML文書全体をメモリに読み込み、ノードとして操作するためのクラスです。

XMLの各要素、属性、テキストをノードとして扱えるため、細かいXML操作に向いています。

XmlDocumentでは、XPathを使って要素を検索できます。

XPathとは、XML内の特定の要素や属性を指定するための書き方です。

たとえば、次のように指定できます。

/books/book/title

これは、books の中にある book の中の title 要素を表します。

3-2. LoadでXMLファイルを読み込む

XmlDocumentでXMLファイルを読み込むには、Load メソッドを使います。

C#
using System;
using System.Xml;

class Program
{
static void Main()
{
string path = "books.xml";

XmlDocument doc = new XmlDocument();
doc.Load(path);

Console.WriteLine("XMLを読み込みました。");
}
}

doc.Load(path) によって、指定したXMLファイルが読み込まれます。

読み込んだXMLは、doc オブジェクトを通して操作できます。

3-3. SelectSingleNodeで特定の要素を取得する

特定の要素を1つだけ取得したい場合は、SelectSingleNode を使います。

たとえば、最初の本のタイトルを取得するコードは次のとおりです。

C#
using System;
using System.Xml;

class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");

XmlNode? titleNode = doc.SelectSingleNode("/books/book[1]/title");

if (titleNode != null)
{
Console.WriteLine(titleNode.InnerText);
}
}
}

実行結果は次のようになります。

C#入門

InnerText を使うと、要素の中のテキストを取得できます。

SelectSingleNode は、指定したXPathに一致する最初のノードを返します。該当するノードがない場合は null が返るため、必ずnullチェックを行うのが安全です。

3-4. SelectNodesで複数の要素を取得する

複数の要素を取得したい場合は、SelectNodes を使います。

すべての本のタイトルを取得する例です。

C#
using System;
using System.Xml;

class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");

XmlNodeList? titleNodes = doc.SelectNodes("/books/book/title");

if (titleNodes != null)
{
foreach (XmlNode node in titleNodes)
{
Console.WriteLine(node.InnerText);
}
}
}
}

実行結果は次のようになります。

C#入門
SQL基礎
XML実践ガイド

SelectNodes は、条件に一致する複数のノードを取得したいときに便利です。

3-5. 属性値を取得する方法

XMLの属性値を取得するには、Attributes を使います。

たとえば、各 book 要素の id 属性と category 属性を取得するコードは次のとおりです。

C#
using System;
using System.Xml;

class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");

XmlNodeList? bookNodes = doc.SelectNodes("/books/book");

if (bookNodes != null)
{
foreach (XmlNode book in bookNodes)
{
string id = book.Attributes?["id"]?.Value ?? "";
string category = book.Attributes?["category"]?.Value ?? "";

Console.WriteLine($"id={id}, category={category}");
}
}
}
}

実行結果は次のようになります。

id=1, category=programming
id=2, category=database
id=3, category=programming

Attributes?["id"]?.Value のように書くことで、属性が存在しない場合でも例外を避けられます。

3-6. XmlDocumentを使うメリット・デメリット

XmlDocumentのメリットは、XMLの構造を細かく操作しやすいことです。

XPathを使って要素を指定できるため、複雑なXMLから特定のノードを取得したい場合に便利です。また、古くから使われている方法なので、既存のC#コードや業務システムでもよく見かけます。

一方で、コードがやや長くなりやすく、LINQ to XMLに比べると直感的に書きづらい場合があります。

XmlDocumentは、次のような場合に向いています。

・既存のXMLを細かく編集したい
・XPathを使ってノードを取得したい
・古いC#プロジェクトを保守している
・XMLの構造をノード単位で操作したい

4. XmlDocumentでXMLを書き込む方法

4-1. 新しいXMLを作成する

XmlDocumentで新しいXMLを作成するには、CreateElement を使って要素を作成します。

C#
using System.Xml;

class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();

XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(declaration);

XmlElement root = doc.CreateElement("books");
doc.AppendChild(root);

doc.Save("new_books.xml");
}
}

このコードを実行すると、次のようなXMLが作成されます。

XML
<?xml version="1.0" encoding="utf-8"?>
<books />

CreateXmlDeclaration でXML宣言を作成し、CreateElement でルート要素を作成しています。

4-2. 要素を追加する

次に、book 要素とその子要素を追加してみましょう。

C#
using System.Xml;

class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();

XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(declaration);

XmlElement root = doc.CreateElement("books");
doc.AppendChild(root);

XmlElement book = doc.CreateElement("book");

XmlElement title = doc.CreateElement("title");
title.InnerText = "C#入門";

XmlElement author = doc.CreateElement("author");
author.InnerText = "山田太郎";

XmlElement price = doc.CreateElement("price");
price.InnerText = "2800";

book.AppendChild(title);
book.AppendChild(author);
book.AppendChild(price);

root.AppendChild(book);

doc.Save("new_books.xml");
}
}

作成されるXMLは次のようになります。

XML
<?xml version="1.0" encoding="utf-8"?>
<books>
<book>
<title>C#入門</title>
<author>山田太郎</author>
<price>2800</price>
</book>
</books>

XmlDocumentでは、要素を作成してから親要素に追加する流れでXMLを組み立てます。

4-3. 属性を追加する

属性を追加するには、SetAttribute を使います。

C#
using System.Xml;

class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();

XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(declaration);

XmlElement root = doc.CreateElement("books");
doc.AppendChild(root);

XmlElement book = doc.CreateElement("book");
book.SetAttribute("id", "1");
book.SetAttribute("category", "programming");

XmlElement title = doc.CreateElement("title");
title.InnerText = "C#入門";

book.AppendChild(title);
root.AppendChild(book);

doc.Save("new_books.xml");
}
}

出力されるXMLは次のようになります。

XML
<?xml version="1.0" encoding="utf-8"?>
<books>
<book id="1" category="programming">
<title>C#入門</title>
</book>
</books>

属性は、要素に付随する補足情報を表すときに使います。

4-4. 既存のXMLを更新する

既存のXMLを読み込んで、特定の要素を更新することもできます。

たとえば、idが 1 の本の価格を変更するコードは次のとおりです。

C#
using System;
using System.Xml;

class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");

XmlNode? priceNode = doc.SelectSingleNode("/books/book[@id='1']/price");

if (priceNode != null)
{
priceNode.InnerText = "3000";
}

doc.Save("books.xml");

Console.WriteLine("価格を更新しました。");
}
}

XPathの [@id='1'] は、id 属性が 1book 要素を指定しています。

4-5. SaveでXMLファイルに保存する

XmlDocumentで編集したXMLは、Save メソッドでファイルに保存します。

C#
doc.Save("books.xml");

別名で保存することもできます。

C#
doc.Save("books_updated.xml");

既存ファイルと同じパスを指定すると上書き保存されます。大切なXMLファイルを扱う場合は、いきなり上書きせず、別名で保存して内容を確認するのがおすすめです。

5. LINQ to XMLでXMLを読み込む方法

5-1. LINQ to XMLとは

LINQ to XMLは、XDocumentXElement を使ってXMLを操作する方法です。

XmlDocumentよりもコードがシンプルになりやすく、LINQの WhereSelect と組み合わせてXMLを検索できます。

C#でXMLを初めて扱う場合は、LINQ to XMLから学ぶと理解しやすいでしょう。

5-2. XDocumentでXMLファイルを読み込む

LINQ to XMLでXMLファイルを読み込むには、XDocument.Load を使います。

C#
using System;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");

Console.WriteLine("XMLを読み込みました。");
}
}

読み込んだXMLは、doc.RootElementElements を使って取得できます。

5-3. Elementで単一要素を取得する

単一の要素を取得するには、Element を使います。

たとえば、最初の book 要素の title を取得するコードは次のとおりです。

C#
using System;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");

XElement? firstBook = doc.Root?.Element("book");
XElement? title = firstBook?.Element("title");

Console.WriteLine(title?.Value);
}
}

実行結果は次のようになります。

C#入門

Value を使うと、要素の中のテキストを取得できます。

5-4. Elementsで複数要素を取得する

複数の要素を取得するには、Elements を使います。

C#
using System;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");

foreach (XElement book in doc.Root?.Elements("book") ?? Enumerable.Empty<XElement>())
{
string title = book.Element("title")?.Value ?? "";
Console.WriteLine(title);
}
}
}

このコードでは、books の直下にあるすべての book 要素を取得し、それぞれの title を表示しています。

Enumerable.Empty<XElement>() を使うことで、doc.Root がnullだった場合でも安全に処理できます。

5-5. Whereで条件を指定して検索する

LINQ to XMLの便利な点は、LINQの Where を使って条件検索できることです。

たとえば、category 属性が programming の本だけを取得するコードは次のとおりです。

C#
using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");

var programmingBooks = doc.Root?
.Elements("book")
.Where(book => (string?)book.Attribute("category") == "programming");

if (programmingBooks != null)
{
foreach (XElement book in programmingBooks)
{
string title = book.Element("title")?.Value ?? "";
Console.WriteLine(title);
}
}
}
}

実行結果は次のようになります。

C#入門
XML実践ガイド

LINQを使うことで、条件をC#のコードとして読みやすく書けます。

5-6. 属性値を取得する方法

LINQ to XMLで属性値を取得するには、Attribute を使います。

C#
using System;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");

foreach (XElement book in doc.Root?.Elements("book") ?? Enumerable.Empty<XElement>())
{
string id = book.Attribute("id")?.Value ?? "";
string category = book.Attribute("category")?.Value ?? "";

Console.WriteLine($"id={id}, category={category}");
}
}
}

属性値を文字列として取得したい場合は、Value を使います。

また、次のようにキャストして取得することもできます。

C#
int id = (int?)book.Attribute("id") ?? 0;

数値として扱いたい場合は、このような書き方が便利です。

6. LINQ to XMLでXMLを書き込む方法

6-1. XDocumentでXMLを新規作成する

LINQ to XMLでは、XMLの構造をC#コード内でそのまま表現するように書けます。

C#
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("books")
);

doc.Save("new_books.xml");
}
}

出力されるXMLは次のようになります。

XML
<?xml version="1.0" encoding="utf-8"?>
<books />

XmlDocumentよりも短いコードで新しいXMLを作成できます。

6-2. XElementで要素を追加する

XElement を使うと、要素を入れ子にして直感的にXMLを作れます。

C#
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("books",
new XElement("book",
new XElement("title", "C#入門"),
new XElement("author", "山田太郎"),
new XElement("price", 2800)
)
)
);

doc.Save("new_books.xml");
}
}

出力されるXMLは次のようになります。

XML
<?xml version="1.0" encoding="utf-8"?>
<books>
<book>
<title>C#入門</title>
<author>山田太郎</author>
<price>2800</price>
</book>
</books>

XMLの構造とコードの構造が近いため、読みやすいのがLINQ to XMLの大きなメリットです。

6-3. XAttributeで属性を追加する

属性を追加するには、XAttribute を使います。

C#
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("books",
new XElement("book",
new XAttribute("id", "1"),
new XAttribute("category", "programming"),
new XElement("title", "C#入門"),
new XElement("author", "山田太郎"),
new XElement("price", 2800)
)
)
);

doc.Save("new_books.xml");
}
}

出力されるXMLは次のようになります。

XML
<?xml version="1.0" encoding="utf-8"?>
<books>
<book id="1" category="programming">
<title>C#入門</title>
<author>山田太郎</author>
<price>2800</price>
</book>
</books>

6-4. 既存のXMLを編集・削除する

既存のXMLを編集する場合は、XDocument.Load で読み込んでから、対象の要素を変更します。

idが 1 の本の価格を変更する例です。

C#
using System.Linq;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");

XElement? book = doc.Root?
.Elements("book")
.FirstOrDefault(x => (string?)x.Attribute("id") == "1");

if (book != null)
{
book.Element("price")?.SetValue(3000);
}

doc.Save("books.xml");
}
}

要素を削除する場合は、Remove を使います。

C#
using System.Linq;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");

XElement? book = doc.Root?
.Elements("book")
.FirstOrDefault(x => (string?)x.Attribute("id") == "2");

book?.Remove();

doc.Save("books.xml");
}
}

このコードでは、idが 2book 要素を削除しています。

6-5. SaveでXMLファイルに保存する

LINQ to XMLでも、編集したXMLは Save メソッドで保存します。

C#
doc.Save("books.xml");

別名で保存する場合は、次のようにします。

C#
doc.Save("books_updated.xml");

既存のXMLを直接上書きする場合は、保存前にバックアップを取っておくと安心です。

7. C#でXMLをシリアライズ・デシリアライズする方法

7-1. XMLシリアライズとは

XMLシリアライズとは、C#のオブジェクトをXML形式に変換することです。

反対に、XMLをC#のオブジェクトに変換することをデシリアライズといいます。

たとえば、次のようなC#のクラスがあるとします。

C#
public class Book
{
public string? Title { get; set; }
public string? Author { get; set; }
public int Price { get; set; }
}

この Book オブジェクトをXMLとして保存したり、XMLファイルから Book オブジェクトとして読み込んだりできます。

XMLの構造とC#のクラス構造が対応している場合は、XmlSerializerを使うと非常に便利です。

7-2. XmlSerializerの基本

XmlSerializerを使うには、シリアライズ対象のクラスを用意します。

C#
public class Book
{
public string? Title { get; set; }
public string? Author { get; set; }
public int Price { get; set; }
}

XmlSerializerでは、基本的にpublicなプロパティがXMLの要素として出力されます。

また、シリアライズ対象のクラスには、引数なしのpublicコンストラクターが必要です。通常、明示的にコンストラクターを書かなければ自動的に用意されます。

7-3. オブジェクトをXMLにシリアライズする

C#のオブジェクトをXMLに保存する例です。

C#
using System.IO;
using System.Xml.Serialization;

public class Book
{
public string? Title { get; set; }
public string? Author { get; set; }
public int Price { get; set; }
}

class Program
{
static void Main()
{
Book book = new Book
{
Title = "C#入門",
Author = "山田太郎",
Price = 2800
};

XmlSerializer serializer = new XmlSerializer(typeof(Book));

using FileStream fs = new FileStream("book.xml", FileMode.Create);
serializer.Serialize(fs, book);
}
}

出力されるXMLは、次のような形式になります。

XML
<?xml version="1.0"?>
<Book>
<Title>C#入門</Title>
<Author>山田太郎</Author>
<Price>2800</Price>
</Book>

XmlSerializerを使うと、手作業でタグを作成しなくても、オブジェクトをそのままXMLとして保存できます。

7-4. XMLをオブジェクトにデシリアライズする

XMLファイルをC#のオブジェクトに変換するには、Deserialize を使います。

C#
using System;
using System.IO;
using System.Xml.Serialization;

public class Book
{
public string? Title { get; set; }
public string? Author { get; set; }
public int Price { get; set; }
}

class Program
{
static void Main()
{
XmlSerializer serializer = new XmlSerializer(typeof(Book));

using FileStream fs = new FileStream("book.xml", FileMode.Open);
Book? book = serializer.Deserialize(fs) as Book;

if (book != null)
{
Console.WriteLine(book.Title);
Console.WriteLine(book.Author);
Console.WriteLine(book.Price);
}
}
}

XMLの構造とクラスの構造が一致していれば、自動的にプロパティへ値が入ります。

7-5. XmlRoot・XmlElement・XmlAttributeの使い方

XMLの要素名や属性を細かく指定したい場合は、属性クラスを使います。

C#
using System.Xml.Serialization;

[XmlRoot("book")]
public class Book
{
[XmlAttribute("id")]
public int Id { get; set; }

[XmlAttribute("category")]
public string? Category { get; set; }

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

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

[XmlElement("price")]
public int Price { get; set; }
}

このクラスをシリアライズすると、次のようなXMLになります。

XML
<book id="1" category="programming">
<title>C#入門</title>
<author>山田太郎</author>
<price>2800</price>
</book>

主な属性の役割は次のとおりです。

XmlRoot      :ルート要素名を指定する
XmlElement :プロパティをXML要素として出力する
XmlAttribute :プロパティをXML属性として出力する

XMLの形式が決まっている場合は、これらを使ってC#クラスとXMLの対応関係を調整します。

7-6. Listや配列をXMLで扱う方法

複数の本をXMLで扱う場合は、Listを使います。

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

[XmlRoot("books")]
public class BookList
{
[XmlElement("book")]
public List<Book> Books { get; set; } = new();
}

public class Book
{
[XmlAttribute("id")]
public int Id { get; set; }

[XmlAttribute("category")]
public string? Category { get; set; }

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

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

[XmlElement("price")]
public int Price { get; set; }
}

このクラスを使って、複数のBookオブジェクトをXMLに保存できます。

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

class Program
{
static void Main()
{
BookList bookList = new BookList
{
Books = new List<Book>
{
new Book
{
Id = 1,
Category = "programming",
Title = "C#入門",
Author = "山田太郎",
Price = 2800
},
new Book
{
Id = 2,
Category = "database",
Title = "SQL基礎",
Author = "佐藤花子",
Price = 3200
}
}
};

XmlSerializer serializer = new XmlSerializer(typeof(BookList));

using FileStream fs = new FileStream("books_serialized.xml", FileMode.Create);
serializer.Serialize(fs, bookList);
}
}

この方法を使うと、XMLをデータ保存形式として扱いやすくなります。

8. XmlDocument・LINQ to XML・シリアライズの使い分け

8-1. 初心者におすすめの選び方

初心者がC#でXMLを扱う場合、まずはLINQ to XMLから始めるのがおすすめです。

理由は、コードが短く、XMLの構造を直感的に理解しやすいからです。

ただし、既存のXMLをXPathで細かく指定して操作したい場合はXmlDocument、クラスとXMLを変換したい場合はXmlSerializerが適しています。

8-2. 既存XMLを細かく操作するならXmlDocument

XmlDocumentは、既存XMLの一部を変更したり、XPathで特定の要素を取得したりする場合に向いています。

たとえば、次のような処理に適しています。

・特定の属性を持つ要素だけを更新する
・XPathで深い階層の要素を取得する
・既存システムのXML処理を保守する
・XMLノードを細かく追加・削除する

古い業務システムではXmlDocumentが使われていることも多いため、保守開発では知っておくと役立ちます。

8-3. シンプルに読み書きするならLINQ to XML

新しくC#でXML処理を書くなら、LINQ to XMLが扱いやすいです。

特に、XMLを読み込んで条件に合う要素を取得したり、簡単なXMLファイルを作成したりする場合に向いています。

・コードをシンプルに書きたい
・LINQのWhereやSelectを使いたい
・新規開発でXMLを扱う
・小〜中規模のXMLファイルを読み書きする

読みやすいコードを書きたい場合は、LINQ to XMLを第一候補にするとよいでしょう。

8-4. クラスとXMLを変換するならXmlSerializer

XMLをC#のクラスとして扱いたい場合は、XmlSerializerが向いています。

たとえば、ユーザー情報、商品情報、設定情報などをクラスで管理し、そのままXMLに保存したい場合に便利です。

・XMLをC#オブジェクトに変換したい
・C#オブジェクトをXMLとして保存したい
・XMLの構造がクラスと対応している
・Listや配列をXMLで保存したい

XMLを「データファイル」として扱う場合は、XmlSerializerを使うとコードが整理しやすくなります。

8-5. 用途別の比較表

方法特徴向いている用途初心者向け
XmlDocumentXMLをノード単位で操作できる既存XMLの細かい編集、XPath検索普通
LINQ to XMLC#らしくシンプルに書けるXMLの読み込み、検索、作成、更新おすすめ
XmlSerializerクラスとXMLを相互変換できるオブジェクトの保存・復元用途が合えば簡単

迷った場合は、次の基準で選ぶとわかりやすいです。

XMLをそのまま読む・書く      → LINQ to XML
XPathで細かく操作する → XmlDocument
クラスに変換して扱う → XmlSerializer

9. C# XML操作でよくあるエラーと対処法

9-1. ファイルが見つからない

XMLファイルを読み込むときに、次のようなエラーが出ることがあります。

System.IO.FileNotFoundException

これは、指定したパスにXMLファイルが存在しない場合に発生します。

対処法として、まずファイルが存在するか確認しましょう。

C#
using System;
using System.IO;

string path = "books.xml";

if (!File.Exists(path))
{
Console.WriteLine("XMLファイルが見つかりません。");
return;
}

Visual Studioで実行している場合、プロジェクトフォルダではなく、実行ファイルの出力先が基準になる点に注意してください。

9-2. ルート要素がない・XML形式が不正

XMLの形式が不正な場合、読み込み時に例外が発生します。

たとえば、次のようなXMLは不正です。

XML
<book>
<title>C#入門</title>
</book>
<book>
<title>SQL基礎</title>
</book>

XMLにはルート要素が1つだけ必要です。

正しくは、次のように全体を1つのルート要素で囲みます。

XML
<books>
<book>
<title>C#入門</title>
</book>
<book>
<title>SQL基礎</title>
</book>
</books>

XMLでは、タグの閉じ忘れや入れ子構造の間違いにも注意しましょう。

9-3. NullReferenceExceptionが発生する

C#でXMLを読み込むときによくあるのが、取得した要素が存在しないのに ValueInnerText にアクセスしてしまうケースです。

たとえば、次のコードは title が存在しない場合にエラーになる可能性があります。

C#
string title = book.Element("title").Value;

安全に書くなら、次のようにnullチェックを入れます。

C#
string title = book.Element("title")?.Value ?? "";

XmlDocumentの場合も同様です。

C#
XmlNode? node = doc.SelectSingleNode("/books/book/title");
string title = node?.InnerText ?? "";

XMLの要素や属性は、存在しない可能性がある前提で書くことが大切です。

9-4. 日本語が文字化けする

日本語が文字化けする場合は、XML宣言のエンコーディングと実際のファイルの文字コードが一致しているか確認します。

おすすめはUTF-8です。

XML
<?xml version="1.0" encoding="utf-8"?>

また、XMLファイルを保存するエディタ側でもUTF-8として保存してください。

C#でテキストとして直接書き込む場合は、エンコーディングを明示する方法もあります。

C#
using System.Text;

File.WriteAllText("sample.xml", xmlText, Encoding.UTF8);

ただし、XmlDocumentやXDocumentの Save を使う場合は、XML宣言と保存形式に注意しながら扱うのが基本です。

9-5. デシリアライズに失敗する

XmlSerializerでデシリアライズに失敗する場合、主な原因はXMLの構造とC#クラスの構造が一致していないことです。

たとえば、XML側が小文字の title なのに、C#側が Title のままだと、想定どおりに値が入らないことがあります。

その場合は、XmlElement を使って対応する要素名を指定します。

C#
[XmlElement("title")]
public string? Title { get; set; }

属性として定義されている値を受け取りたい場合は、XmlAttribute を使います。

C#
[XmlAttribute("id")]
public int Id { get; set; }

また、XmlSerializerで扱うクラスはpublicである必要があります。プロパティもpublicにしておきましょう。

9-6. XML名前空間がある場合の取得方法

XMLに名前空間がある場合、通常の要素名だけでは取得できないことがあります。

たとえば、次のようなXMLです。

XML
<books xmlns="http://example.com/books">
<book>
<title>C#入門</title>
</book>
</books>

LINQ to XMLでは、XNamespace を使って取得します。

C#
using System;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");

XNamespace ns = "http://example.com/books";

foreach (XElement book in doc.Root?.Elements(ns + "book") ?? Enumerable.Empty<XElement>())
{
string title = book.Element(ns + "title")?.Value ?? "";
Console.WriteLine(title);
}
}
}

XmlDocumentで名前空間付きXMLを扱う場合は、XmlNamespaceManager を使います。

C#
using System;
using System.Xml;

class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");

XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("b", "http://example.com/books");

XmlNode? titleNode = doc.SelectSingleNode("/b:books/b:book/b:title", ns);

Console.WriteLine(titleNode?.InnerText);
}
}

XML名前空間がある場合は、名前空間を含めて要素を指定する必要があります。

10. C#でXMLを扱うときの注意点

10-1. XMLファイルの読み書き権限

XMLファイルを読み書きする場合、ファイルへのアクセス権限が必要です。

特に、次のような場所に保存しようとすると権限エラーになることがあります。

・Program Files配下
・Windowsシステムフォルダ
・他ユーザーのフォルダ
・読み取り専用のフォルダ

設定ファイルやユーザーデータを保存する場合は、アプリケーションが書き込み可能なフォルダを選びましょう。

たとえば、ユーザーごとのアプリケーションデータフォルダを使う方法があります。

C#
string folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string path = Path.Combine(folder, "MyApp", "settings.xml");

保存先フォルダが存在しない場合は、作成してから保存します。

C#
Directory.CreateDirectory(Path.GetDirectoryName(path)!);

10-2. 大きなXMLファイルを扱う場合

XmlDocumentやXDocumentは、XML全体をメモリに読み込みます。

そのため、数MB程度のXMLであれば扱いやすいですが、非常に大きなXMLファイルを処理する場合はメモリ使用量に注意が必要です。

大容量XMLを逐次的に読みたい場合は、XmlReader の利用を検討します。

C#
using System;
using System.Xml;

class Program
{
static void Main()
{
using XmlReader reader = XmlReader.Create("large.xml");

while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "title")
{
string title = reader.ReadElementContentAsString();
Console.WriteLine(title);
}
}
}
}

XmlReader は前から順に読み進めるため、メモリ使用量を抑えられます。

10-3. 外部XMLを読み込むときのセキュリティ

インターネット上のXMLや、ユーザーがアップロードしたXMLなど、信頼できないXMLを読み込む場合は注意が必要です。

外部エンティティやDTDを悪用した攻撃を避けるため、不要なDTD処理は無効にするのが安全です。

C#
using System.Xml;

XmlReaderSettings settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit
};

using XmlReader reader = XmlReader.Create("sample.xml", settings);

XmlDocument doc = new XmlDocument();
doc.Load(reader);

外部から受け取ったXMLをそのまま読み込む場合は、ファイルサイズ、形式、エンコーディング、DTDの扱いなどを確認しましょう。

10-4. 例外処理を入れるべき理由

XMLファイルの読み込みや保存では、さまざまな例外が発生する可能性があります。

・ファイルが存在しない
・XML形式が不正
・アクセス権限がない
・ファイルが別プロセスで使用中
・文字コードが不正

そのため、実際のアプリケーションでは try-catch を使って例外処理を入れるべきです。

C#
using System;
using System.Xml.Linq;

class Program
{
static void Main()
{
try
{
XDocument doc = XDocument.Load("books.xml");
Console.WriteLine("XMLを読み込みました。");
}
catch (Exception ex)
{
Console.WriteLine("XMLの読み込みに失敗しました。");
Console.WriteLine(ex.Message);
}
}
}

エラー内容をログに残しておくと、トラブルの原因を調査しやすくなります。

10-5. JSONとの使い分け

現在のWeb APIではJSONが使われることが多いですが、XMLにも適した場面があります。

JSONは軽量で、JavaScriptやWeb APIとの相性がよい形式です。

一方、XMLは属性、名前空間、スキーマ、文書構造の表現に強く、業務システムや既存システムとの連携で使われることがあります。

使い分けの目安は次のとおりです。

Web APIや軽量なデータ交換       → JSON
既存システム連携や文書構造の表現 → XML
設定ファイル → XMLまたはJSON
クラスとの相互変換 → XMLならXmlSerializer、JSONならSystem.Text.Json

どちらが優れているというより、連携先やデータ形式に合わせて選ぶことが大切です。

11. C# XML操作の実践サンプル

11-1. 設定ファイルをXMLで読み込む

アプリケーションの設定をXMLで管理する例です。

settings.xml を次のように用意します。

XML
<?xml version="1.0" encoding="utf-8"?>
<settings>
<appName>SampleApp</appName>
<version>1.0.0</version>
<debug>true</debug>
</settings>

C#で読み込むコードは次のとおりです。

C#
using System;
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = XDocument.Load("settings.xml");

string appName = doc.Root?.Element("appName")?.Value ?? "";
string version = doc.Root?.Element("version")?.Value ?? "";
bool debug = bool.TryParse(doc.Root?.Element("debug")?.Value, out bool result) && result;

Console.WriteLine($"アプリ名: {appName}");
Console.WriteLine($"バージョン: {version}");
Console.WriteLine($"デバッグ: {debug}");
}
}

設定ファイルのようなシンプルなXMLは、LINQ to XMLで読み込むと簡単です。

11-2. ユーザー情報をXMLに保存する

ユーザー情報をXMLファイルに保存する例です。

C#
using System.Xml.Linq;

class Program
{
static void Main()
{
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("users",
new XElement("user",
new XAttribute("id", "1"),
new XElement("name", "田中太郎"),
new XElement("email", "tanaka@example.com")
),
new XElement("user",
new XAttribute("id", "2"),
new XElement("name", "佐藤花子"),
new XElement("email", "sato@example.com")
)
)
);

doc.Save("users.xml");
}
}

出力されるXMLは次のようになります。

XML
<?xml version="1.0" encoding="utf-8"?>
<users>
<user id="1">
<name>田中太郎</name>
<email>tanaka@example.com</email>
</user>
<user id="2">
<name>佐藤花子</name>
<email>sato@example.com</email>
</user>
</users>

ユーザー一覧のように複数データを保存する場合は、ルート要素の下に同じ名前の要素を複数配置すると扱いやすくなります。

11-3. APIから取得したXMLを解析する

APIから取得したXML文字列を解析する場合は、XDocument.Parse を使います。

C#
using System;
using System.Linq;
using System.Xml.Linq;

class Program
{
static void Main()
{
string xml = @"
<items>
<item>
<name>商品A</name>
<price>1000</price>
</item>
<item>
<name>商品B</name>
<price>2000</price>
</item>
</items>";

XDocument doc = XDocument.Parse(xml);

var items = doc.Root?
.Elements("item")
.Select(item => new
{
Name = item.Element("name")?.Value ?? "",
Price = (int?)item.Element("price") ?? 0
});

if (items != null)
{
foreach (var item in items)
{
Console.WriteLine($"{item.Name}: {item.Price}円");
}
}
}
}

XMLファイルではなく文字列を読み込む場合は、Load ではなく Parse を使うのがポイントです。

11-4. XMLをクラスに変換して扱う

XMLをクラスに変換すると、C#のオブジェクトとして扱えるため、処理が書きやすくなります。

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

[XmlRoot("users")]
public class UserList
{
[XmlElement("user")]
public List<User> Users { get; set; } = new();
}

public class User
{
[XmlAttribute("id")]
public int Id { get; set; }

[XmlElement("name")]
public string? Name { get; set; }

[XmlElement("email")]
public string? Email { get; set; }
}

class Program
{
static void Main()
{
XmlSerializer serializer = new XmlSerializer(typeof(UserList));

using FileStream fs = new FileStream("users.xml", FileMode.Open);
UserList? userList = serializer.Deserialize(fs) as UserList;

if (userList != null)
{
foreach (User user in userList.Users)
{
Console.WriteLine($"{user.Id}: {user.Name} / {user.Email}");
}
}
}
}

XMLを一度クラスに変換してしまえば、通常のC#オブジェクトとして処理できます。

12. C# XMLに関するよくある質問

12-1. C#でXMLを読み込む一番簡単な方法は?

一番簡単にXMLを読み込むなら、LINQ to XMLの XDocument.Load がおすすめです。

C#
using System.Xml.Linq;

XDocument doc = XDocument.Load("books.xml");

要素の取得もシンプルです。

C#
string title = doc.Root?
.Element("book")?
.Element("title")?
.Value ?? "";

新しくC#でXML操作を学ぶ場合は、まずLINQ to XMLを使うとよいでしょう。

12-2. XmlDocumentとXDocumentはどちらを使うべき?

新規開発でシンプルにXMLを読み書きするなら、XDocumentを使うのがおすすめです。

XDocumentはLINQ to XMLで使うクラスで、C#らしく簡潔に書けます。

一方、XPathを使って既存XMLを細かく操作したい場合や、古いコードを保守する場合はXmlDocumentが向いています。

新しく書くなら        → XDocument
XPathを使いたいなら → XmlDocument
既存コードがあるなら → 既存の方法に合わせる

12-3. XMLの属性と要素はどう使い分ける?

XMLでは、データの本体は要素、補足情報や識別情報は属性として表すことが多いです。

たとえば、次の例では idcategory が属性、titleprice が要素です。

XML
<book id="1" category="programming">
<title>C#入門</title>
<price>2800</price>
</book>

使い分けの目安は次のとおりです。

属性:ID、分類、フラグなどの補足情報
要素:タイトル、本文、価格、説明文などのデータ本体

ただし、連携先のXML仕様が決まっている場合は、その仕様に合わせることが最優先です。

12-4. XMLをオブジェクトに変換できる?

はい、XmlSerializerを使うとXMLをC#のオブジェクトに変換できます。

C#
XmlSerializer serializer = new XmlSerializer(typeof(Book));

using FileStream fs = new FileStream("book.xml", FileMode.Open);
Book? book = serializer.Deserialize(fs) as Book;

反対に、C#のオブジェクトをXMLとして保存することもできます。

C#
using FileStream fs = new FileStream("book.xml", FileMode.Create);
serializer.Serialize(fs, book);

XMLをデータモデルとして扱いたい場合は、XmlSerializerが便利です。

12-5. .NET 6・.NET 8でも同じ方法で使える?

はい、XmlDocument、LINQ to XML、XmlSerializerは、.NET 6や.NET 8でも利用できます。

基本的な使い方は大きく変わりません。

ただし、プロジェクトの種類やNullable参照型の設定によって、string? やnullチェックの書き方が変わることがあります。

最近のC#では、XMLから取得した要素や属性が存在しない可能性を考えて、次のように安全に書くのがおすすめです。

C#
string title = book.Element("title")?.Value ?? "";

nullチェックを意識することで、NullReferenceException を防ぎやすくなります。

まとめ

C#でXMLを読み書きする方法には、XmlDocument、LINQ to XML、XmlSerializerがあります。

XmlDocumentは、XMLをノード単位で細かく操作したい場合に向いています。XPathを使って特定の要素を取得できるため、既存XMLの編集や保守で役立ちます。

LINQ to XMLは、XDocumentやXElementを使ってシンプルにXMLを扱える方法です。C#らしい書き方ができ、初心者がXML操作を学ぶ場合にもおすすめです。

XmlSerializerは、C#のクラスとXMLを相互変換したい場合に便利です。XMLをオブジェクトとして扱いたい場合や、Listや配列をXMLで保存したい場合に適しています。

使い分けの目安は、次のとおりです。

既存XMLを細かく操作する       → XmlDocument
シンプルにXMLを読み書きする → LINQ to XML
クラスとXMLを相互変換する → XmlSerializer

C#でXMLを扱うときは、ファイルパス、文字コード、nullチェック、例外処理、名前空間に注意することが大切です。

まずはLINQ to XMLで基本的な読み込みと書き込みを試し、その後、必要に応じてXmlDocumentやXmlSerializerを使い分けると、C#のXML操作を効率よく習得できます。