This guide details XML file operasions in C# using three distinct technologies: the traditional XmlDocument for in-memory document object model (DOM) manipulation, the forward-only XmlTextReader for stream-based reading, and the modern LINQ to XML for declarative querying and modification. Each method is demonstrtaed through common CRUD operations (Create, Read, Update, Delete) on a sample XML file representing a bookstore catalog.
XmlTextWriter for XML Creation and Serialization
The XmlTextWriter class provides a forward-only, write-only stream for generating XML data. It is efficient for creating new XML documents from scratch.
/// <summary>
/// Resets data and writes to an XML file using XmlTextWriter.
/// </summary>
private void ResetXmlData()
{
using (XmlTextWriter xmlWriter = new XmlTextWriter(XmlFilePath, Encoding.UTF8))
{
xmlWriter.Formatting = Formatting.Indented;
xmlWriter.WriteStartDocument(true);
xmlWriter.WriteStartElement("bookstore");
xmlWriter.WriteComment("Book catalog information");
// Write book elements
xmlWriter.WriteStartElement("book");
xmlWriter.WriteAttributeString("category", "Elective");
xmlWriter.WriteAttributeString("isbn", "978-0-321-94786-4");
xmlWriter.WriteElementString("title", "Operating System Concepts");
xmlWriter.WriteElementString("author", "Abraham Silberschatz");
xmlWriter.WriteElementString("price", "85.00");
xmlWriter.WriteEndElement(); // Closes book element
xmlWriter.WriteEndElement(); // Closes bookstore element
xmlWriter.WriteComment("Reset operation completed");
}
MessageBox.Show("Data reset successful.");
}
XmlDocument for DOM-Based Operations
The XmlDocument class loads the entire XML document into memory, enabling random access and modification of the node tree.
Loading and Displaying Data
private XmlDocument xmlDoc;
private DataTable dataTable;
/// <summary>
/// Loads XML data into a DataTable using XmlDocument.
/// </summary>
public void LoadWithXmlDocument()
{
InitializeDataTable();
xmlDoc = new XmlDocument();
XmlReaderSettings settings = new XmlReaderSettings { IgnoreComments = true };
using (XmlReader reader = XmlReader.Create(XmlFilePath, settings))
{
xmlDoc.Load(reader);
}
XmlNode root = xmlDoc.SelectSingleNode("/bookstore");
XmlNodeList bookNodes = root.ChildNodes;
foreach (XmlNode node in bookNodes)
{
XmlElement element = (XmlElement)node;
DataRow row = dataTable.NewRow();
row["Category"] = element.GetAttribute("category");
row["ISBN"] = element.GetAttribute("isbn");
row["Title"] = element["title"].InnerText;
row["Author"] = element["author"].InnerText;
row["Price"] = element["price"].InnerText;
dataTable.Rows.Add(row);
}
dataGridView.DataSource = dataTable;
}
Adding a New Record
/// <summary>
/// Adds a new book record to the XML document.
/// </summary>
public void AddBookWithXmlDocument()
{
DataRow newRow = GenerateNewDataRow();
XmlNode bookstore = xmlDoc.SelectSingleNode("/bookstore");
XmlElement newBook = xmlDoc.CreateElement("book");
newBook.SetAttribute("category", newRow["Category"].ToString());
newBook.SetAttribute("isbn", newRow["ISBN"].ToString());
XmlElement titleElem = xmlDoc.CreateElement("title");
titleElem.InnerText = newRow["Title"].ToString();
newBook.AppendChild(titleElem);
XmlElement authorElem = xmlDoc.CreateElement("author");
authorElem.InnerText = newRow["Author"].ToString();
newBook.AppendChild(authorElem);
XmlElement priceElem = xmlDoc.CreateElement("price");
priceElem.InnerText = newRow["Price"].ToString();
newBook.AppendChild(priceElem);
bookstore.AppendChild(newBook);
xmlDoc.Save(XmlFilePath);
LoadWithXmlDocument();
}
Updating an Existing Record
/// <summary>
/// Updates a book record identified by its ISBN.
/// </summary>
public void UpdateBookWithXmlDocument(string isbnToUpdate)
{
XmlNodeList books = xmlDoc.SelectNodes("/bookstore/book[@isbn='" + isbnToUpdate + "']");
if (books.Count == 0) return;
XmlElement book = (XmlElement)books[0];
DataRow updatedData = GenerateUpdatedDataRow(isbnToUpdate);
book.SetAttribute("category", updatedData["Category"].ToString());
book["title"].InnerText = updatedData["Title"].ToString();
book["author"].InnerText = updatedData["Author"].ToString();
book["price"].InnerText = updatedData["Price"].ToString();
xmlDoc.Save(XmlFilePath);
LoadWithXmlDocument();
}
Deleting a Record
/// <summary>
/// Deletes a book record by its ISBN.
/// </summary>
public void DeleteBookWithXmlDocument(string isbnToDelete)
{
XmlNode bookstore = xmlDoc.DocumentElement;
XmlNode bookToRemove = xmlDoc.SelectSingleNode("/bookstore/book[@isbn='" + isbnToDelete + "']");
if (bookToRemove != null)
{
bookstore.RemoveChild(bookToRemove);
xmlDoc.Save(XmlFilePath);
LoadWithXmlDocument();
}
}
XmlTextReader for Stream-Based Reading
The XmlTextReader provides a fast, forward-only, read-only cursor for processing XML data. It is memory-efficient for large files.
/// <summary>
/// Loads data using XmlTextReader for sequential parsing.
/// </summary>
public void LoadWithXmlTextReader()
{
InitializeDataTable();
DataRow currentRow = dataTable.NewRow();
using (XmlTextReader xmlReader = new XmlTextReader(XmlFilePath))
{
while (xmlReader.Read())
{
if (xmlReader.NodeType == XmlNodeType.Element)
{
if (xmlReader.Name == "book")
{
currentRow["Category"] = xmlReader.GetAttribute("category");
currentRow["ISBN"] = xmlReader.GetAttribute("isbn");
}
if (xmlReader.Name == "title")
{
currentRow["Title"] = xmlReader.ReadString();
}
if (xmlReader.Name == "author")
{
currentRow["Author"] = xmlReader.ReadString();
}
if (xmlReader.Name == "price")
{
currentRow["Price"] = xmlReader.ReadString();
}
}
if (xmlReader.NodeType == XmlNodeType.EndElement && xmlReader.Name == "book")
{
dataTable.Rows.Add(currentRow);
currentRow = dataTable.NewRow();
}
}
}
dataGridView.DataSource = dataTable;
}
LINQ to XML for Modern XML Processing
LINQ to XML provides an intuitive, in-memory XML programming API integrated with Language-Integrated Query (LINQ).
Loading Data with LINQ to XML
private XElement xElement;
/// <summary>
/// Loads and displays XML data using LINQ to XML.
/// </summary>
public void LoadWithLinq()
{
InitializeDataTable();
xElement = XElement.Load(XmlFilePath);
var bookQuery = from book in xElement.Elements("book")
select new
{
Category = book.Attribute("category").Value,
ISBN = book.Attribute("isbn").Value,
Title = book.Element("title").Value,
Author = book.Element("author").Value,
Price = book.Element("price").Value
};
foreach (var book in bookQuery)
{
DataRow row = dataTable.NewRow();
row["Category"] = book.Category;
row["ISBN"] = book.ISBN;
row["Title"] = book.Title;
row["Author"] = book.Author;
row["Price"] = book.Price;
dataTable.Rows.Add(row);
}
dataGridView.DataSource = dataTable;
}
Adding a Record with LINQ to XML
/// <summary>
/// Adds a new book element using LINQ to XML.
/// </summary>
public void AddBookWithLinq()
{
DataRow newBookData = GenerateNewDataRow();
XElement newBook = new XElement("book",
new XAttribute("category", newBookData["Category"]),
new XAttribute("isbn", newBookData["ISBN"]),
new XElement("title", newBookData["Title"]),
new XElement("author", newBookData["Author"]),
new XElement("price", newBookData["Price"])
);
xElement.Add(newBook);
xElement.Save(XmlFilePath);
LoadWithLinq();
}
Updating a Record with LINQ to XML
/// <summary>
/// Updates a book element identified by its ISBN.
/// </summary>
public void UpdateBookWithLinq(string targetIsbn)
{
XElement bookToUpdate = xElement.Elements("book")
.FirstOrDefault(b => b.Attribute("isbn").Value == targetIsbn);
if (bookToUpdate == null) return;
DataRow updatedData = GenerateUpdatedDataRow(targetIsbn);
bookToUpdate.SetAttributeValue("category", updatedData["Category"]);
bookToUpdate.SetElementValue("title", updatedData["Title"]);
bookToUpdate.SetElementValue("author", updatedData["Author"]);
bookToUpdate.SetElementValue("price", updatedData["Price"]);
xElement.Save(XmlFilePath);
LoadWithLinq();
}
Deleting a Record with LINQ to XML
/// <summary>
/// Removes a book element by its ISBN.
/// </summary>
public void DeleteBookWithLinq(string targetIsbn)
{
XElement bookToRemove = xElement.Elements("book")
.FirstOrDefault(b => b.Attribute("isbn").Value == targetIsbn);
if (bookToRemove != null)
{
bookToRemove.Remove();
xElement.Save(XmlFilePath);
LoadWithLinq();
}
}