DotNET 读写 XML 文件入门必读

作为入门必读,本文将介绍 XML 的读取方式选择,然后总结初学者可能会遇到的坑。

方式比选

在 C# 中,有多种方式可以读取 XML 数据,以下是一些常见的方法:

  1. 使用 XmlDocument:这是 .NET Framework 中最早的 XML 处理类,它提供了丰富的方法和属性来读取和操作 XML 文档。

    1
    2
    3
    XmlDocument doc = new XmlDocument();
    doc.Load("file.xml");
    XmlNode node = doc.DocumentElement.SelectSingleNode("/book/title");
  2. 使用 XDocumentXElement:这些类是 .NET Framework 的 LINQ to XML 技术的一部分,它们提供了更现代和强大的方式来处理 XML。

    1
    2
    XDocument doc = XDocument.Load("file.xml");
    XElement node = doc.Root.Element("title");
  3. 使用 XmlReader:这是一个基于流的读取器,它提供了一种高效的方式来读取大型 XML 文件,因为它一次只读取文档的一小部分。

    1
    2
    3
    4
    5
    6
    7
    using (XmlReader reader = XmlReader.Create("file.xml"))
    {
    while (reader.Read())
    {
    // 处理每个节点...
    }
    }
  4. 使用 XmlSerializer:这个类可以将 XML 数据反序列化为 .NET 对象,或将 .NET 对象序列化为 XML。这是处理复杂数据结构的理想选择。

    1
    2
    XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
    MyClass obj = (MyClass)serializer.Deserialize(new StreamReader("file.xml"));

以上每种方法都有其优点和适用场景,在日常开发中若无特殊要求,建议选择更加现代化的 LINQ to XML 方式来读取 XML。

注意事项

注意 xmlns(命名空间)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<KeyinTree xmlns="http://www.bentley.com/schemas/1.0/MicroStation/AddIn/KeyinTree.xsd">
<RootKeyinTable>
<Keyword CommandWord="app" SubtableRef="app" />
</RootKeyinTable>
<SubKeyinTables>
<SubKeyinTable ID="default" />
<SubKeyinTable ID="app">
<Keyword CommandWord="test" SubtableRef="test" />
</SubKeyinTable>
<SubKeyinTable ID="test">
<Keyword CommandWord="keyin" />
</SubKeyinTable>
</SubKeyinTables>
<KeyinHandlers>
<KeyinHandler Keyin="app test keyin" Function="Namespace.App.Functions.Func" />
</KeyinHandlers>
</KeyinTree>

在 XML 中,节点的名称由两部分组成:{命名空间}+逻辑名称

上面的 XML 中,根节点 KeyinTree 是逻辑名称,它的 Name 是 {http://www.bentley.com/schemas/1.0/MicroStation/AddIn/KeyinTree.xsd}KeyinTree。因此:

  1. 不同命名空间的节点不能相互包含

  2. 在查询时,要注意区分是全称还是逻辑名称

  3. 使用 LINQ to XML 时,若只希望按标签来筛选,则应该去匹配它的逻辑名称

    1
    2
    var document = XDocument.Load(path);
    var keyinTree = document.Elements().FirstOrDefault(x=>x.Name.LocalName=="KeyinTree")

其它

可以添加以下扩展方法来读取 XML,简化对命名空间的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static class XDocumentExtension
{
/// <summary>
/// 使用带有命名空间的名称查询后代
/// </summary>
/// <param name="element"></param>
/// <param name="localName"></param>
/// <returns></returns>
public static IEnumerable<XElement> DescendantsWithNSP(this XElement element, string localName)
{
var fullName = "{" + element.Name.NamespaceName + "}" + localName;
return element.Descendants(fullName);
}

/// <summary>
/// 转换成带有命名空间的 XName
/// </summary>
/// <param name="localName"></param>
/// <param name="template"></param>
/// <returns></returns>
public static XName ToXNameWithNSP(this string localName, XElement template)
{
return template.Name.Namespace + localName;
}
}

参考

本文参考以下文章,在此致以诚挚谢意!

LINQ to XML 概述 - .NET | Microsoft Learn