C#でXMLを読み書き・解析する方法|XmlDocumentとLINQ to XMLの使い方を初心者向けに解説
はじめに
C#でXMLを扱う方法を理解しておくと、設定ファイルの読み込み、外部システムとのデータ連携、アプリケーション内の構造化データ管理など、さまざまな場面で役立ちます。
XMLは古くから使われているデータ形式ですが、現在でも業務システム、設定ファイル、API連携、帳票データなどで利用されることがあります。C#にはXMLを読み込み・解析・作成・更新するための機能が標準で用意されており、代表的な方法として「XmlDocument」と「LINQ to XML」があります。
この記事では、C#でXMLを読み書きする基本から、XmlDocumentとLINQ to XMLの違い、要素や属性の取得、XMLファイルの作成・更新・削除、実践的な使い方まで初心者向けに解説します。
1. C#でXMLを扱う前に知っておきたい基礎
1-1. XMLとは何か|C#でXMLを使う場面
XMLとは「Extensible Markup Language」の略で、データをタグで囲んで表現するマークアップ言語です。HTMLに似た見た目をしていますが、HTMLがWebページの表示を目的としているのに対し、XMLはデータの構造を表すことを目的としています。
C#でXMLを使う場面には、次のようなものがあります。
C#// 例:アプリケーション設定をXMLから読み込む
// 例:外部サービスから受け取ったXMLレスポンスを解析する
// 例:商品一覧やユーザー情報をXMLファイルとして保存する
// 例:古い業務システムとのデータ連携にXMLを使う
現在はJSONが使われることも多いですが、XMLは階層構造や属性を持つデータを表現しやすく、既存システムでは今でもよく使われています。
1-2. XMLファイルの基本構造|要素・属性・テキスト・階層
XMLは、要素、属性、テキスト、階層構造で構成されます。たとえば、次のようなXMLを考えてみましょう。
XML<?xml version="1.0" encoding="utf-8"?>
<books>
<book id="1">
<title>C#入門</title>
<price>3000</price>
</book>
<book id="2">
<title>XML基礎</title>
<price>2500</price>
</book>
</books>
このXMLでは、books がルート要素、book が子要素です。id="1" は属性、C#入門 や 3000 はテキストです。
C#でXMLを解析するときは、「どの要素を取得するのか」「属性を読むのか」「テキストを読むのか」を意識することが大切です。
1-3. C#でXMLを読み書きする主な方法
C#でXMLを扱う主な方法には、次のようなものがあります。
C#// XmlDocument
// DOM形式でXML全体を読み込み、ノードを操作する方法
// LINQ to XML
// XDocumentやXElementを使い、LINQで直感的にXMLを操作する方法
// XmlReader
// XMLを前から順番に読み込む高速な方法
// XmlWriter
// XMLを前から順番に書き込む方法
// XmlSerializer
// XMLとC#のオブジェクトを相互変換する方法
初心者がC# XML処理を学ぶ場合は、まず XmlDocument と LINQ to XML を理解するとよいでしょう。この2つを押さえれば、一般的なXMLの読み込み、解析、作成、更新は十分対応できます。
1-4. XmlDocumentとLINQ to XMLの違い
XmlDocument は、XMLをDOMツリーとして扱う従来からある方法です。XmlNode や XmlElement を使って、要素や属性を操作します。
一方、LINQ to XMLは、XDocument や XElement を使ってXMLを扱う比較的新しい書き方です。LINQの構文を使えるため、条件検索や一覧取得を簡潔に書けます。
たとえば、特定の book 要素を取得する場合、LINQ to XMLでは次のように書けます。
C#var books = doc.Descendants("book")
.Where(x => (int)x.Element("price") >= 3000);
XmlDocumentではXPathを使って検索することが多く、次のように書きます。
C#XmlNodeList nodes = doc.SelectNodes("//book[price >= 3000]");
どちらもXMLを扱えますが、書き方や得意な場面が異なります。
1-5. 初心者はどちらを使うべきか
これからC#でXML処理を学ぶ初心者には、基本的にはLINQ to XMLがおすすめです。理由は、コードが読みやすく、要素の取得や条件検索を直感的に書けるからです。
ただし、既存のプロジェクトで XmlDocument が使われている場合や、XPathを活用したい場合は、XmlDocumentを使う場面もあります。
新規開発ではLINQ to XML、既存コードの保守やXPath中心の処理ではXmlDocument、と考えると選びやすいです。
2. C#でXMLを読み込む方法
2-1. サンプルXMLファイルを用意する
まずは、次のような books.xml を用意します。
XML<?xml version="1.0" encoding="utf-8"?>
<books>
<book id="1" category="programming">
<title>C#入門</title>
<author>山田太郎</author>
<price>3000</price>
</book>
<book id="2" category="database">
<title>SQL基礎</title>
<author>佐藤花子</author>
<price>2500</price>
</book>
</books>
このXMLファイルをC#から読み込み、要素や属性の値を取得していきます。
2-2. XmlDocumentでXMLファイルを読み込む
XmlDocument を使ってXMLファイルを読み込むには、Load メソッドを使います。
C#using System;
using System.Xml;
class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");
XmlNode root = doc.DocumentElement;
Console.WriteLine(root.Name);
}
}
doc.Load("books.xml") でXMLファイル全体を読み込みます。DocumentElement はルート要素を表し、この例では books 要素が取得されます。
2-3. LINQ to XMLでXMLファイルを読み込む
LINQ to XMLでは、XDocument.Load を使います。
C#using System;
using System.Xml.Linq;
class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");
Console.WriteLine(doc.Root.Name);
}
}
doc.Root でルート要素を取得できます。LINQ to XMLはコードが短く、XMLの構造をC#のコードとして自然に扱いやすいのが特徴です。
2-4. 文字列のXMLを読み込む方法
ファイルではなく、文字列としてXMLを持っている場合もあります。その場合は、XmlDocumentでは LoadXml、LINQ to XMLでは Parse を使います。
C#using System;
using System.Xml;
class Program
{
static void Main()
{
string xml = "<user><name>田中</name><age>30</age></user>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
Console.WriteLine(doc.DocumentElement["name"].InnerText);
}
}
LINQ to XMLでは次のように書けます。
C#using System;
using System.Xml.Linq;
class Program
{
static void Main()
{
string xml = "<user><name>田中</name><age>30</age></user>";
XElement element = XElement.Parse(xml);
Console.WriteLine(element.Element("name").Value);
}
}
文字列のXMLを扱う場合でも、ファイル読み込みと基本的な考え方は同じです。
2-5. XML読み込み時によくあるエラーと原因
XML読み込み時によくあるエラーには、次のようなものがあります。
C#// ファイルが存在しない
// XMLのタグが閉じられていない
// ルート要素が複数ある
// 文字コードが合っていない
// アクセス権限がない
// パスの指定が間違っている
たとえば、次のXMLは正しくありません。
XML<books>
<book>
<title>C#入門</title>
</books>
book 要素の終了タグがないため、読み込み時に例外が発生します。XMLは開始タグと終了タグの対応が厳密なので、形式が正しいか確認することが重要です。
3. XmlDocumentを使ってXMLを解析する方法
3-1. XmlDocumentの基本的な使い方
XmlDocument では、XML全体をツリー構造として読み込み、ノードをたどりながら値を取得します。
C#XmlDocument doc = new XmlDocument();
doc.Load("books.xml");
XmlElement root = doc.DocumentElement;
Console.WriteLine(root.Name);
XmlDocument では、XMLの各部分を XmlNode や XmlElement として扱います。ルート要素、子要素、属性、テキストを順番に取得しながら処理していきます。
3-2. 特定の要素を取得する
特定の要素を取得するには、GetElementsByTagName を使えます。
C#XmlNodeList titles = doc.GetElementsByTagName("title");
foreach (XmlNode title in titles)
{
Console.WriteLine(title.InnerText);
}
このコードでは、XML内のすべての title 要素を取得し、そのテキストを表示しています。
最初の1件だけ取得したい場合は、次のように書けます。
C#XmlNode title = doc.GetElementsByTagName("title")[0];
Console.WriteLine(title.InnerText);
ただし、要素が存在しない場合はエラーになる可能性があるため、実際のコードではnullチェックや件数チェックを行うことが大切です。
3-3. 属性の値を取得する
属性の値を取得するには、Attributes を使います。
C#XmlNode book = doc.GetElementsByTagName("book")[0];
string id = book.Attributes["id"].Value;
string category = book.Attributes["category"].Value;
Console.WriteLine(id);
Console.WriteLine(category);
book 要素の id 属性と category 属性を取得しています。
属性が存在しない可能性がある場合は、次のように安全に取得します。
C#XmlAttribute attr = book.Attributes["id"];
if (attr != null)
{
Console.WriteLine(attr.Value);
}
XMLでは属性が省略されることもあるため、存在チェックを習慣にしておくと安全です。
3-4. 子要素・親要素をたどる
XmlDocument では、ChildNodes、ParentNode、FirstChild などを使ってノードの関係をたどれます。
C#XmlNode book = doc.GetElementsByTagName("book")[0];
foreach (XmlNode child in book.ChildNodes)
{
Console.WriteLine($"{child.Name}: {child.InnerText}");
}
親要素を取得する場合は、ParentNode を使います。
C#XmlNode title = doc.GetElementsByTagName("title")[0];
XmlNode parent = title.ParentNode;
Console.WriteLine(parent.Name);
この例では、title 要素の親である book 要素を取得できます。
3-5. XPathで目的のノードを検索する
XmlDocumentではXPathを使うと、目的のノードを柔軟に検索できます。
C#XmlNode node = doc.SelectSingleNode("//book[@id='1']/title");
if (node != null)
{
Console.WriteLine(node.InnerText);
}
このコードでは、id 属性が 1 の book 要素の中にある title 要素を取得しています。
複数の要素を取得する場合は、SelectNodes を使います。
C#XmlNodeList nodes = doc.SelectNodes("//book[@category='programming']");
foreach (XmlNode node in nodes)
{
Console.WriteLine(node["title"].InnerText);
}
XPathを使うと、階層が深いXMLでも目的のデータを効率よく取得できます。
3-6. XmlNodeとXmlElementの違い
XmlNode は、XML内のさまざまなノードを表す基本クラスです。要素、属性、テキスト、コメントなど、XMLを構成する多くのものをノードとして扱います。
一方、XmlElement は要素ノードを表します。つまり、<book> や <title> のようなタグ付きの要素を扱うときに使います。
C#XmlNode node = doc.SelectSingleNode("//book");
XmlElement element = node as XmlElement;
if (element != null)
{
Console.WriteLine(element.GetAttribute("id"));
}
要素として属性を操作したい場合は、XmlElement に変換すると扱いやすくなります。
3-7. XmlDocumentを使うメリット・デメリット
XmlDocumentのメリットは、古くから使われているため情報が多く、既存のC#プロジェクトでもよく見かけることです。また、XPathとの相性がよく、複雑な条件でノードを検索できます。
一方で、コードがやや冗長になりやすく、LINQ to XMLに比べると読み書きしにくいと感じる場面があります。また、XML全体をメモリに読み込むため、非常に大きなXMLファイルを扱う場合は注意が必要です。
4. LINQ to XMLを使ってXMLを解析する方法
4-1. LINQ to XMLとは
LINQ to XMLは、C#でXMLを簡潔に扱うための機能です。XDocument、XElement、XAttribute などのクラスを使い、LINQの構文でXMLを検索・抽出できます。
特に、要素の一覧を取得したり、条件に合うデータだけを抽出したりする処理が書きやすいです。
C#var books = doc.Descendants("book")
.Where(x => (string)x.Attribute("category") == "programming");
このように、C#のコレクションを扱う感覚でXMLを処理できます。
4-2. XDocumentでXMLを読み込む
XMLファイル全体を読み込むには、XDocument.Load を使います。
C#using System;
using System.Xml.Linq;
class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");
Console.WriteLine(doc.Root.Name);
}
}
XDocument はXML文書全体を表します。ルート要素だけを扱いたい場合は、doc.Root を使います。
4-3. XElementで要素を取得する
特定の要素を取得するには、Element や Elements、Descendants を使います。
C#XElement root = doc.Root;
foreach (XElement book in root.Elements("book"))
{
string title = book.Element("title").Value;
Console.WriteLine(title);
}
Elements("book") は、直下の book 要素を取得します。階層を問わずすべての book 要素を取得したい場合は、Descendants("book") を使います。
C#var books = doc.Descendants("book");
foreach (var book in books)
{
Console.WriteLine(book.Element("title").Value);
}
4-4. 属性の値を取得する
LINQ to XMLで属性を取得するには、Attribute メソッドを使います。
C#foreach (XElement book in doc.Descendants("book"))
{
string id = book.Attribute("id").Value;
string category = book.Attribute("category").Value;
Console.WriteLine($"{id}: {category}");
}
属性が存在しない可能性がある場合は、キャストを使うと安全です。
C#string id = (string)book.Attribute("id");
この書き方では、属性が存在しない場合に null が返ります。Value を直接使うとnull参照エラーになる可能性があるため、実務ではキャストを使う書き方が便利です。
4-5. LINQで条件に合う要素を検索する
LINQ to XMLの大きな特徴は、LINQで条件検索ができることです。
C#var expensiveBooks = doc.Descendants("book")
.Where(book => (int)book.Element("price") >= 3000);
foreach (var book in expensiveBooks)
{
Console.WriteLine(book.Element("title").Value);
}
このコードでは、price が3000以上の本だけを抽出しています。
属性を条件にする場合は、次のように書けます。
C#var programmingBooks = doc.Descendants("book")
.Where(book => (string)book.Attribute("category") == "programming");
foreach (var book in programmingBooks)
{
Console.WriteLine(book.Element("title").Value);
}
XMLから条件に合うデータを抽出したい場合、LINQ to XMLは非常に便利です。
4-6. 複数の要素をループ処理する
複数の要素をループ処理する場合も、LINQ to XMLはシンプルに書けます。
C#foreach (XElement book in doc.Descendants("book"))
{
string title = (string)book.Element("title");
string author = (string)book.Element("author");
int price = (int)book.Element("price");
Console.WriteLine($"{title} / {author} / {price}円");
}
キャストを使うことで、文字列や数値として値を取り出せます。ただし、数値変換に失敗する可能性がある場合は、int.TryParse を使うと安全です。
C#string priceText = (string)book.Element("price");
if (int.TryParse(priceText, out int price))
{
Console.WriteLine(price);
}
4-7. LINQ to XMLを使うメリット・デメリット
LINQ to XMLのメリットは、コードが短く読みやすいことです。C#のLINQに慣れている人であれば、XMLの条件検索や一覧取得を自然に書けます。
また、XMLの新規作成も直感的に書けるため、読み込みだけでなく書き込みにも向いています。
一方で、XPathを多用する既存コードとの相性はXmlDocumentほどよくありません。また、XmlDocumentと同じくXML全体をメモリに読み込むため、大容量XMLでは XmlReader の利用も検討する必要があります。
5. C#でXMLを書き込む・新規作成する方法
5-1. XmlDocumentでXMLを新規作成する
XmlDocumentでXMLを新規作成する場合は、CreateElement を使って要素を作成し、AppendChild で追加します。
C#XmlDocument doc = new XmlDocument();
XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(declaration);
XmlElement root = doc.CreateElement("books");
doc.AppendChild(root);
このコードでは、XML宣言とルート要素 books を作成しています。
5-2. XmlDocumentで要素と属性を追加する
要素や属性を追加するには、次のように書きます。
C#XmlElement book = doc.CreateElement("book");
book.SetAttribute("id", "1");
XmlElement title = doc.CreateElement("title");
title.InnerText = "C#入門";
XmlElement price = doc.CreateElement("price");
price.InnerText = "3000";
book.AppendChild(title);
book.AppendChild(price);
root.AppendChild(book);
最終的には、次のようなXMLになります。
XML<?xml version="1.0" encoding="utf-8"?>
<books>
<book id="1">
<title>C#入門</title>
<price>3000</price>
</book>
</books>
5-3. LINQ to XMLでXMLを新規作成する
LINQ to XMLでは、XMLの構造をそのままC#のコードで表現できます。
C#XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement("books",
new XElement("book",
new XAttribute("id", "1"),
new XElement("title", "C#入門"),
new XElement("price", 3000)
)
)
);
XmlDocumentよりも階層構造が見た目で分かりやすく、XMLを新規作成する場合に便利です。
5-4. XElementで要素と属性を追加する
既存の XElement に新しい要素を追加するには、Add メソッドを使います。
C#XElement root = new XElement("books");
root.Add(
new XElement("book",
new XAttribute("id", "1"),
new XElement("title", "C#入門"),
new XElement("price", 3000)
)
);
さらに別の本を追加する場合も、同じように Add を使います。
C#root.Add(
new XElement("book",
new XAttribute("id", "2"),
new XElement("title", "XML基礎"),
new XElement("price", 2500)
)
);
LINQ to XMLは、C#でXMLを組み立てる処理をかなり直感的に書けます。
5-5. 作成したXMLをファイルに保存する
XmlDocumentで作成したXMLは、Save メソッドで保存できます。
C#doc.Save("books.xml");
LINQ to XMLでも同じように Save メソッドを使います。
C#doc.Save("books.xml");
ファイルパスを相対パスで指定した場合、実行ファイルの場所を基準に保存されることがあります。保存先が分からない場合は、絶対パスを指定すると確認しやすいです。
C#doc.Save(@"C:\temp\books.xml");
5-6. インデント付きで見やすく保存する方法
LINQ to XMLの Save は、通常はインデント付きで保存されます。より細かく制御したい場合は、XmlWriterSettings を使います。
C#using System.Xml;
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true,
Encoding = System.Text.Encoding.UTF8
};
using (XmlWriter writer = XmlWriter.Create("books.xml", settings))
{
doc.Save(writer);
}
XmlDocumentでも同じように XmlWriter を使って保存できます。
C#XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true,
Encoding = System.Text.Encoding.UTF8
};
using (XmlWriter writer = XmlWriter.Create("books.xml", settings))
{
doc.Save(writer);
}
インデント付きで保存すると、人間が見ても読みやすいXMLになります。
6. C#でXMLを編集・更新・削除する方法
6-1. 既存の要素の値を変更する
XmlDocumentで要素の値を変更するには、対象ノードを取得して InnerText を変更します。
C#XmlNode title = doc.SelectSingleNode("//book[@id='1']/title");
if (title != null)
{
title.InnerText = "C# XML入門";
}
LINQ to XMLでは、Value を変更します。
C#XElement title = doc.Descendants("book")
.FirstOrDefault(x => (string)x.Attribute("id") == "1")
?.Element("title");
if (title != null)
{
title.Value = "C# XML入門";
}
6-2. 属性の値を変更する
XmlDocumentで属性を変更するには、SetAttribute を使います。
C#XmlElement book = doc.SelectSingleNode("//book[@id='1']") as XmlElement;
if (book != null)
{
book.SetAttribute("category", "csharp");
}
LINQ to XMLでは、SetAttributeValue を使います。
C#XElement book = doc.Descendants("book")
.FirstOrDefault(x => (string)x.Attribute("id") == "1");
if (book != null)
{
book.SetAttributeValue("category", "csharp");
}
SetAttributeValue は、属性が存在しない場合は追加し、存在する場合は更新します。
6-3. 新しい要素を追加する
XmlDocumentで新しい要素を追加するには、CreateElement と AppendChild を使います。
C#XmlElement stock = doc.CreateElement("stock");
stock.InnerText = "10";
XmlNode book = doc.SelectSingleNode("//book[@id='1']");
if (book != null)
{
book.AppendChild(stock);
}
LINQ to XMLでは、Add を使います。
C#XElement book = doc.Descendants("book")
.FirstOrDefault(x => (string)x.Attribute("id") == "1");
if (book != null)
{
book.Add(new XElement("stock", 10));
}
6-4. 不要な要素を削除する
XmlDocumentで要素を削除するには、親ノードから RemoveChild を呼び出します。
C#XmlNode book = doc.SelectSingleNode("//book[@id='2']");
if (book != null && book.ParentNode != null)
{
book.ParentNode.RemoveChild(book);
}
LINQ to XMLでは、対象の XElement に対して Remove を呼び出します。
C#XElement book = doc.Descendants("book")
.FirstOrDefault(x => (string)x.Attribute("id") == "2");
book?.Remove();
LINQ to XMLの方が削除処理はかなり簡潔に書けます。
6-5. XmlDocumentで更新するコード例
XmlDocumentでXMLを読み込み、値を更新して保存する一連のコードは次のとおりです。
C#using System;
using System.Xml;
class Program
{
static void Main()
{
XmlDocument doc = new XmlDocument();
doc.Load("books.xml");
XmlNode title = doc.SelectSingleNode("//book[@id='1']/title");
if (title != null)
{
title.InnerText = "C# XML完全入門";
}
XmlElement book = doc.SelectSingleNode("//book[@id='1']") as XmlElement;
if (book != null)
{
book.SetAttribute("category", "csharp");
}
doc.Save("books.xml");
Console.WriteLine("XMLを更新しました。");
}
}
SelectSingleNode で対象を検索し、値や属性を変更してから Save で保存します。
6-6. LINQ to XMLで更新するコード例
LINQ to XMLで同じような更新処理を書くと、次のようになります。
C#using System;
using System.Linq;
using System.Xml.Linq;
class Program
{
static void Main()
{
XDocument doc = XDocument.Load("books.xml");
XElement book = doc.Descendants("book")
.FirstOrDefault(x => (string)x.Attribute("id") == "1");
if (book != null)
{
book.Element("title")!.Value = "C# XML完全入門";
book.SetAttributeValue("category", "csharp");
}
doc.Save("books.xml");
Console.WriteLine("XMLを更新しました。");
}
}
LINQ to XMLでは、条件に合う要素を検索し、その要素に対して値や属性を更新します。C#のLINQに慣れている場合は、こちらの方が読みやすいでしょう。
7. XmlDocumentとLINQ to XMLの使い分け
7-1. XmlDocumentが向いているケース
XmlDocumentは、既存コードで使われている場合や、XPathを多用する場合に向いています。
C#XmlNode node = doc.SelectSingleNode("//book[@id='1']/title");
XPathで複雑な検索条件を表現したい場合、XmlDocumentは便利です。また、古い.NET FrameworkのプロジェクトではXmlDocumentが使われていることも多いため、保守開発では理解しておく必要があります。
7-2. LINQ to XMLが向いているケース
LINQ to XMLは、新しくC#でXML処理を書く場合に向いています。コードが短く、条件検索や集計処理も書きやすいです。
C#var books = doc.Descendants("book")
.Where(x => (int)x.Element("price") >= 3000)
.Select(x => new
{
Title = (string)x.Element("title"),
Price = (int)x.Element("price")
});
XMLから一覧データを取り出して処理する場合、LINQ to XMLは非常に扱いやすい方法です。
7-3. 既存コード・古い.NET環境での選び方
既存プロジェクトですでにXmlDocumentが使われている場合は、無理にLINQ to XMLへ置き換える必要はありません。既存コードとの統一感を優先した方が、保守しやすい場合があります。
一方、新規開発や学習目的であれば、LINQ to XMLから学ぶのがおすすめです。特に.NET 6、.NET 8などの比較的新しい環境では、LINQ to XMLを使うことで簡潔なコードを書きやすくなります。
7-4. 読みやすさ・書きやすさの比較
XmlDocumentは、ノードを1つずつ操作するため、処理の流れは分かりやすい反面、コードが長くなりがちです。
C#XmlNode node = doc.SelectSingleNode("//book/title");
if (node != null)
{
Console.WriteLine(node.InnerText);
}
LINQ to XMLでは、同じ処理をより簡潔に書けます。
C#var title = doc.Descendants("book")
.FirstOrDefault()
?.Element("title")?.Value;
読みやすさを重視するなら、LINQ to XMLの方が初心者にも扱いやすいでしょう。
7-5. パフォーマンス面での注意点
XmlDocumentもLINQ to XMLも、基本的にはXML全体をメモリに読み込んで処理します。そのため、数MB程度のXMLであれば問題になりにくいですが、数百MB以上の大きなXMLファイルではメモリ使用量に注意が必要です。
大きなXMLファイルを処理する場合は、XmlReader を使って必要な部分だけを順番に読み込む方法を検討します。
C#using XmlReader reader = XmlReader.Create("large.xml");
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "book")
{
Console.WriteLine("book要素を見つけました");
}
}
大容量データでは、XML全体を読み込まない設計が重要です。
7-6. 初心者におすすめの選び方
初心者がC# XML処理を学ぶなら、まずはLINQ to XMLをおすすめします。理由は、コードが短く、XMLの構造とC#のコードが対応しやすいからです。
ただし、業務ではXmlDocumentを使った既存コードに出会うこともあります。そのため、最初にLINQ to XMLで基本を学び、その後XmlDocumentとXPathも理解しておくと実践で困りにくくなります。
8. C#でXMLを扱うときの注意点
8-1. XMLファイルの文字コードに注意する
XMLファイルには、文字コードが指定されていることがあります。
XML<?xml version="1.0" encoding="utf-8"?>
C#でXMLを読み込むとき、ファイルの実際の文字コードとXML宣言の encoding が一致していないと、文字化けや読み込みエラーの原因になります。
日本語を含むXMLでは、基本的にUTF-8で保存しておくと扱いやすいです。
8-2. null参照エラーを防ぐ書き方
XML処理でよくあるエラーが、存在しない要素や属性にアクセスして発生するnull参照エラーです。
たとえば、次のコードは title 要素が存在しない場合にエラーになる可能性があります。
C#string title = book.Element("title").Value;
安全に書くなら、次のようにします。
C#string title = (string)book.Element("title") ?? "";
XmlDocumentの場合も同様です。
C#XmlNode node = doc.SelectSingleNode("//title");
if (node != null)
{
Console.WriteLine(node.InnerText);
}
XMLの構造が常に期待どおりとは限らないため、nullチェックを入れることが大切です。
8-3. 存在しない要素・属性への対処
存在しない要素や属性に対しては、初期値を設定する方法がよく使われます。
C#string category = (string)book.Attribute("category") ?? "未分類";
数値の場合は、変換エラーにも注意します。
C#int price = 0;
int.TryParse((string)book.Element("price"), out price);
外部から受け取るXMLでは、要素が不足していたり、値の形式が想定と違ったりすることがあります。安全に処理するためには、必ず存在チェックと変換チェックを行いましょう。
8-4. XMLの形式が正しくない場合の対処
XMLの形式が正しくない場合、読み込み時に例外が発生します。代表的なのは XmlException です。
C#try
{
XDocument doc = XDocument.Load("books.xml");
}
catch (System.Xml.XmlException ex)
{
Console.WriteLine("XMLの形式が正しくありません。");
Console.WriteLine(ex.Message);
}
XMLはタグの閉じ忘れ、ルート要素の重複、不正な文字などに厳密です。読み込みに失敗した場合は、XMLファイルの内容を確認しましょう。
8-5. 外部XMLを読み込むときのセキュリティ注意点
外部から受け取ったXMLを読み込む場合は、セキュリティに注意が必要です。特に、外部実体参照やDTDを悪用した攻撃を防ぐため、XmlReaderSettings を使って安全に読み込むことを検討します。
C#XmlReaderSettings settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit,
XmlResolver = null
};
using XmlReader reader = XmlReader.Create("external.xml", settings);
XDocument doc = XDocument.Load(reader);
信頼できないXMLをそのまま読み込むのは危険です。外部XMLを扱う場合は、DTDの処理を禁止する、不要な外部参照を無効にするなどの対策を行いましょう。
8-6. 例外処理の書き方
XMLファイルの読み込みや保存では、ファイルが存在しない、アクセス権限がない、XML形式が不正など、さまざまな例外が発生する可能性があります。
C#try
{
XDocument doc = XDocument.Load("books.xml");
// XML処理
}
catch (System.IO.FileNotFoundException)
{
Console.WriteLine("XMLファイルが見つかりません。");
}
catch (System.Xml.XmlException ex)
{
Console.WriteLine("XMLの形式が正しくありません。");
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("予期しないエラーが発生しました。");
Console.WriteLine(ex.Message);
}
実務では、エラー内容をログに出力し、ユーザーには分かりやすいメッセージを表示することが多いです。
9. よくあるC# XML処理の実践例
9-1. 設定ファイルとしてXMLを読み込む
XMLはアプリケーション設定ファイルとして使えます。
XML<settings>
<database>
<host>localhost</host>
<port>5432</port>
</database>
</settings>
LINQ to XMLで読み込む例です。
C#XDocument doc = XDocument.Load("settings.xml");
string host = (string)doc.Root.Element("database").Element("host");
int port = (int)doc.Root.Element("database").Element("port");
Console.WriteLine($"{host}:{port}");
設定値をXMLにまとめておくと、アプリケーションの動作をファイルで変更できるようになります。
9-2. XMLから一覧データを取得する
商品一覧や書籍一覧のようなデータをXMLから取得する場合、LINQ to XMLが便利です。
C#var books = XDocument.Load("books.xml")
.Descendants("book")
.Select(book => new
{
Id = (string)book.Attribute("id"),
Title = (string)book.Element("title"),
Price = (int)book.Element("price")
});
foreach (var book in books)
{
Console.WriteLine($"{book.Id}: {book.Title} - {book.Price}円");
}
XMLの各要素をC#の匿名オブジェクトに変換することで、その後の処理がしやすくなります。
9-3. XMLの値を条件付きで抽出する
条件に合うデータだけを抽出する例です。
C#XDocument doc = XDocument.Load("books.xml");
var result = doc.Descendants("book")
.Where(book => (int)book.Element("price") >= 3000)
.Select(book => (string)book.Element("title"));
foreach (var title in result)
{
Console.WriteLine(title);
}
このコードでは、価格が3000円以上の本のタイトルだけを取得しています。LINQを使うと、XMLの検索条件を分かりやすく書けます。
9-4. XMLにデータを追記して保存する
既存のXMLに新しいデータを追加して保存する例です。
C#XDocument doc = XDocument.Load("books.xml");
doc.Root.Add(
new XElement("book",
new XAttribute("id", "3"),
new XAttribute("category", "network"),
new XElement("title", "ネットワーク入門"),
new XElement("author", "鈴木一郎"),
new XElement("price", 2800)
)
);
doc.Save("books.xml");
doc.Root.Add を使うことで、ルート要素の下に新しい book 要素を追加できます。
9-5. XMLをオブジェクトに変換する考え方
XMLを扱うときは、読み込んだ値をC#のクラスに変換すると管理しやすくなります。
C#class Book
{
public string Id { get; set; } = "";
public string Title { get; set; } = "";
public int Price { get; set; }
}
XMLから Book オブジェクトの一覧に変換する例です。
C#List<Book> books = doc.Descendants("book")
.Select(book => new Book
{
Id = (string)book.Attribute("id") ?? "",
Title = (string)book.Element("title") ?? "",
Price = (int?)book.Element("price") ?? 0
})
.ToList();
XMLのまま処理するより、C#のオブジェクトに変換した方が、その後の検索、表示、保存処理を行いやすくなります。
9-6. JSONとの使い分け
現在のWeb APIではJSONがよく使われますが、XMLにも強みがあります。
JSONは軽量で、JavaScriptやWeb APIとの相性がよい形式です。一方、XMLは属性や名前空間、スキーマ定義などを使えるため、複雑な文書構造や厳密なデータ定義に向いています。
C#で新しくデータ連携を作るならJSONが選ばれることも多いですが、既存システム、業務システム、設定ファイル、SOAP連携などではXMLが必要になる場面があります。
10. C#のXML処理でよくある質問
10-1. XmlDocumentとXDocumentは何が違う?
XmlDocumentは従来からあるDOMベースのXML操作方法で、XmlNode や XmlElement を使います。XPathで検索しやすく、既存コードでもよく使われます。
XDocumentはLINQ to XMLで使うクラスで、XElement や XAttribute と組み合わせてXMLを扱います。LINQで条件検索しやすく、コードが簡潔になりやすいです。
初心者や新規開発では、XDocumentを使うLINQ to XMLがおすすめです。
10-2. XMLの属性と要素はどう使い分ける?
属性は、要素を補足する短い情報に向いています。
XML<book id="1" category="programming">
要素は、データ本体や階層を持つ情報に向いています。
XML<title>C#入門</title>
<price>3000</price>
IDや種別のような補足情報は属性、タイトルや価格のようなデータ本体は要素にする、と考えると分かりやすいです。
10-3. XMLファイルが読み込めない原因は?
XMLファイルが読み込めない主な原因は、ファイルパスの間違い、ファイルが存在しない、XMLの形式が不正、文字コードの不一致、アクセス権限の不足などです。
まずは、指定したパスにファイルが存在するか確認しましょう。次に、XMLのタグが正しく閉じられているか、ルート要素が1つだけか、文字コードが合っているかを確認します。
C#側では、try-catch を使って例外内容を確認すると原因を特定しやすくなります。
10-4. XPathとLINQはどちらを使うべき?
XPathは、XMLの階層をパスで指定して検索する方法です。複雑なXML構造から特定のノードを探す場合に便利です。
LINQは、C#のコードとして条件検索や変換処理を書ける方法です。データの一覧取得、条件抽出、オブジェクトへの変換などに向いています。
既存コードでXPathが使われているならXPath、新規開発で読みやすさを重視するならLINQ to XMLを選ぶとよいでしょう。
10-5. 大きなXMLファイルを扱う場合はどうする?
大きなXMLファイルを扱う場合、XmlDocumentやXDocumentで全体を読み込むとメモリ使用量が大きくなる可能性があります。
そのような場合は、XmlReader を使ってXMLを先頭から順番に読み込む方法が適しています。
C#using XmlReader reader = XmlReader.Create("large.xml");
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "item")
{
string id = reader.GetAttribute("id");
Console.WriteLine(id);
}
}
すべてのXMLをメモリに保持する必要がないため、大容量ファイルでも効率よく処理できます。
10-6. C#でXMLを簡単に読み書きするならどの方法がおすすめ?
C#でXMLを簡単に読み書きしたい場合は、LINQ to XMLがおすすめです。XDocument と XElement を使うことで、XMLの読み込み、検索、作成、更新を分かりやすく書けます。
特に初心者の場合、XmlDocumentよりもLINQ to XMLの方がコードの見通しがよく、C#らしい書き方ができます。
ただし、XPathを使いたい場合や既存コードがXmlDocumentで書かれている場合は、XmlDocumentを選ぶのも自然です。
まとめ
C#でXMLを扱う方法には、主にXmlDocumentとLINQ to XMLがあります。
XmlDocumentは、従来から使われているXML操作方法で、XPathを使った検索に向いています。既存のC#プロジェクトや古い.NET環境では、XmlDocumentを使う場面も多いです。
一方、LINQ to XMLは、XDocument や XElement を使ってXMLを直感的に操作できる方法です。LINQで条件検索や一覧取得ができるため、新規開発や初心者の学習には特におすすめです。
C# XML処理では、要素、属性、テキスト、階層構造を理解し、読み込み、解析、作成、更新、削除の基本を押さえることが重要です。また、実務ではnull参照エラー、文字コード、XML形式の不正、外部XMLのセキュリティにも注意する必要があります。
まずはLINQ to XMLで基本的な読み書きを学び、必要に応じてXmlDocumentやXPath、XmlReaderも使い分けることで、C#でXMLを安全かつ効率的に扱えるようになります。

