XML(可扩展标记语言)仍然是一种广泛使用的数据格式,用于在应用程序之间存储和交换结构化数据。无论您是使用遗留系统、集成不同的平台还是管理复杂的配置,XML 都是一项必不可少的技术。在 .NET 中,使用 XML 很常见,并且可以使用多个库来有效地处理 XML 文档。
尽管 XML 具有结构化性质,但使用 XML 可能会带来一些挑战,包括:
.NET 提供了各种 API 和技术来有效管理这些挑战。让我们探索不同的方法。
XmlDocument自 .NET 的早期就已经存在。它遵循基于 DOM 的方法,其中整个 XML 文档被加载到内存中,允许您逐个节点导航和操作它。
using System.Xml;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("employees.xml");
XmlNodeList employeeNodes = xmlDoc.GetElementsByTagName("Employee");
foreach (XmlNode employee in employeeNodes)
{
string id = employee.Attributes["id"].Value;
string name = employee["Name"].InnerText;
Console.WriteLine($"Employee ID: {id}, Name: {name}");
}
这是加载和查询 XML 文件的一种简单方法。但是,对于大型文件,将整个文档加载到内存中可能效率低下。
XmlDocument xmlDoc = new XmlDocument();
XmlElement root = xmlDoc.CreateElement("Company");
XmlElement employee = xmlDoc.CreateElement("Employee");
employee.SetAttribute("id", "101");
XmlElement name = xmlDoc.CreateElement("Name");
name.InnerText = "Alice";
employee.AppendChild(name);
root.AppendChild(employee);
xmlDoc.AppendChild(root);
xmlDoc.Save("company.xml");
虽然提供了对 XML 结构的精细控制,但它可能很冗长且效率低下,尤其是对于大型文件。XmlDocument
对于现代 .NET 应用程序,LINQ to XML () 是首选方法。它提供了一种更具声明性和直观的 XML 处理方式。使用 LINQ,您可以编写更简洁、可读性更强的代码。XDocument
using System.Xml.Linq;
XDocument xdoc = XDocument.Load("employees.xml");
var employees = from e in xdoc.Descendants("Employee")
select new
{
Id = e.Attribute("id").Value,
Name = e.Element("Name").Value
};
foreach (var employee in employees)
{
Console.WriteLine($"Employee ID: {employee.Id}, Name: {employee.Name}");
}
LINQ to XML 比 更简洁,并且使复杂的查询更易于表达。它允许您直接对 XML 数据使用 LINQ 强大的筛选和转换功能。XmlDocument
XDocument xdoc = new XDocument(
new XElement("Company",
new XElement("Employee",
new XAttribute("id", "102"),
new XElement("Name", "Bob")
)
)
);
xdoc.Save("company.xml");
语法更具声明性和直观性,因此更易于使用 XML 结构。使用 LINQ to XML,您可以毫不费力地创建、修改和查询 XML 文档。
在现代 .NET 开发中,还有其他功能和改进可以增强 XML 的处理能力,特别是对于大型文件和安全应用程序。
对于大型 XML 文件,使用 或 将整个文档加载到内存中效率低下。相反,您可以使用 ,它以流式处理方式读取 XML 文件,一次处理一个节点。XmlDocumentXDocumentXmlReader
using System.Xml;
using (XmlReader reader = XmlReader.Create("largefile.xml"))
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Employee")
{
string id = reader.GetAttribute("id");
reader.ReadToFollowing("Name");
string name = reader.ReadElementContentAsString();
Console.WriteLine($"Employee ID: {id}, Name: {name}");
}
}
}
XmlReader非常适合需要以增量方式处理大型文件的情况,从而避免一次加载整个文件的内存开销。
在现代 .NET 应用程序中,尤其是在 Web API 中,异步编程对于确保可扩展性和响应能力至关重要。您可以使用 或 异步读取和写入 XML。XDocumentXmlReader
using System.Xml.Linq;
async Task ProcessXmlAsync()
{
XDocument xdoc = await XDocument.LoadAsync("employees.xml", LoadOptions.None, CancellationToken.None);
var employees = from e in xdoc.Descendants("Employee")
select new
{
Id = e.Attribute("id").Value,
Name = e.Element("Name").Value
};
foreach (var employee in employees)
{
Console.WriteLine($"Employee ID: {employee.Id}, Name: {employee.Name}");
}
}
这可确保您的应用程序在读取大型 XML 文件时不会阻塞,从而提高其效率和可扩展性。
XML 文件可能容易受到 XXE (XML 外部实体) 攻击,尤其是当它们包含外部实体时。为了降低此风险,请在使用不受信任的 XML 源时始终禁用 DTD 处理。
XmlReaderSettings settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit
};
using (XmlReader reader = XmlReader.Create("input.xml", settings))
{
// Safely process the XML
}
通过禁用 DTD 处理,可以防止攻击者利用外部实体,从而确保 XML 处理的安全性。
XML 命名空间通常用于消除元素和属性的歧义,尤其是在大型复杂文档中。LINQ to XML 使处理命名空间变得容易。
XNamespace ns = "https://www.example.com/employees";
XDocument xdoc = XDocument.Load("employees_with_namespace.xml");
var employees = from e in xdoc.Descendants(ns + "Employee")
select new
{
Id = e.Attribute("id").Value,
Name = e.Element(ns + "Name").Value
};
foreach (var employee in employees)
{
Console.WriteLine($"Employee ID: {employee.Id}, Name: {employee.Name}");
}
使用该类可确保正确定位相应命名空间中的元素和属性。XNamespace
.NET 开发中最常见的任务之一是将对象序列化为 XML,然后将它们反序列化回对象。该类使此操作变得简单明了。XmlSerializer
using System.Xml.Serialization;
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
Employee emp = new Employee { Id = 103, Name = "Charlie" };
XmlSerializer serializer = new XmlSerializer(typeof(Employee));
using (StreamWriter writer = new StreamWriter("employee.xml"))
{
serializer.Serialize(writer, emp);
}
这会将对象序列化为 XML。您可以轻松地将其反序列化回对象:Employee
using (StreamReader reader = new StreamReader("employee.xml"))
{
Employee emp = (Employee)serializer.Deserialize(reader);
Console.WriteLine($"Employee ID: {emp.Id}, Name: {emp.Name}");
}
XML 序列化通常用于存储对象状态、在本地缓存数据或跨应用程序传输数据。
在 .NET 中使用 XML 是任何处理数据交换、配置或存储的开发人员的基本技能。.NET 提供了强大的工具来简化这些任务。关键是根据项目的大小、复杂性和性能需求选择正确的方法。