C#操作XML通用方法汇总

Elena
Elena
发布时间:2026-10-13 | 6人浏览过
原创

本文整理并优化了C#中基于System.Xml命名空间的XML操作常用方法。涵盖了从基础的文件创建、节点属性增删改查到高级的对象序列化等功能,提供了一套可直接复用的静态方法库。

准备条件

所有示例均基于C# 6.0及以上版本语法,依赖.NET Framework中的System.Xml命名空间(对应类如XmlDocument、XmlSerializer等)。在进行任何涉及删除或覆盖的写入操作前,建议对原XML文件进行备份,以防数据丢失。

基础XML文档构建与解析

第1步:创建XML文档根节点

目的:初始化一个带有指定根节点名称及属性的XML文档对象。

/// <summary>
/// 创建XML文档
/// </summary>
/// <param name="name">根节点名称</param>
/// <param name="type">根节点的一个属性值</param>
/// <returns>XmlDocument对象</returns> 
public static XmlDocument CreateXmlDocument(string name, string type)
{
    XmlDocument doc = null;
    try
    {
        doc = new XmlDocument();
        // 注意:LoadXml需要完整的XML标签结构
        doc.LoadXml("<" + name + "/>");
        var rootEle = doc.DocumentElement;
        if (rootEle != null) 
            rootEle.SetAttribute("type", type);
    }
    catch (Exception er)
    {
        throw new Exception(er.ToString());
    }
    return doc;
}

第2步:读取XML文件中指定节点数据

目的:根据路径加载XML,获取特定节点的文本内容或其指定属性值。

/// <summary>
/// 读取数据
/// </summary>
/// <param name="path">文件路径</param>
/// <param name="node">XPath节点选择器</param>
/// <param name="attribute">属性名,非空时返回该属性值,否则返回InnerText</param>
/// <returns>string</returns>
public static string Read(string path, string node, string attribute)
{
    var value = "";
    try
    {
        var doc = new XmlDocument();
        doc.Load(path);
        var xn = doc.SelectSingleNode(node);
        if (xn != null && xn.Attributes != null)
        {
            // 如果指定了属性名,则获取属性值;否则获取节点内部文本
            value = string.IsNullOrEmpty(attribute) ? xn.InnerText : xn.Attributes[attribute].Value;
        }
    }
    catch (Exception er)
    {
        throw new Exception(er.ToString());
    }
    return value;
}

XML数据的增删改查操作

第3步:向XML文档插入元素或属性

目的:在选定节点下添加新的子元素,或在现有元素上设置/添加属性。

/// <summary>
/// 插入数据
/// </summary>
/// <param name="path">文件路径</param>
/// <param name="node">目标父节点XPath</param>
/// <param name="element">新元素名,为空表示操作属性</param>
/// <param name="attribute">属性名,为空表示设置元素文本</param>
/// <param name="value">属性值或元素文本</param>
public static void Insert(string path, string node, string element, string attribute, string value)
{
    try
    {
        var doc = new XmlDocument();
        doc.Load(path);
        var xn = doc.SelectSingleNode(node);
        
        // 判断是添加新元素还是修改/添加属性
        if (string.IsNullOrEmpty(element))
        {
            if (!string.IsNullOrEmpty(attribute) && xn is XmlElement xe)
            {
                xe.SetAttribute(attribute, value);
            }
        }
        else
        {
            // 创建新元素
            var xe = doc.CreateElement(element);
            if (string.IsNullOrEmpty(attribute))
                xe.InnerText = value;
            else
                xe.SetAttribute(attribute, value);
            
            if (xn != null)
                xn.AppendChild(xe);
        }
        doc.Save(path); // 保存更改
    }
    catch (Exception er)
    {
        throw new Exception(er.ToString());
    }
}

第4步:更新XML文档中的数据

目的:修改指定节点的内部文本内容或属性值。

/// <summary>
/// 修改数据
/// </summary>
/// <param name="path">文件路径</param>
/// <param name="node">节点XPath</param>
/// <param name="attribute">属性名,非空时修改属性,否则修改文本</param>
/// <param name="value">新值</param>
public static void Update(string path, string node, string attribute, string value)
{
    try
    {
        var doc = new XmlDocument();
        doc.Load(path);
        var xn = doc.SelectSingleNode(node);
        var xe = (XmlElement)xn;
        
        if (xe == null) return;

        if (string.IsNullOrEmpty(attribute))
        {
            // 修改节点文本内容
            xe.InnerText = value;
        }
        else
        {
            // 修改节点属性
            xe.SetAttribute(attribute, value);
        }
        doc.Save(path);
    }
    catch (Exception er)
    {
        throw new Exception(er.ToString());
    }
}

第5步:删除XML数据(节点或属性)

目的:从XML文档中移除指定的节点或节点的属性。

/// <summary>
/// 删除数据
/// </summary>
/// <param name="path">文件路径</param>
/// <param name="node">目标节点XPath</param>
/// <param name="attribute">属性名,非空时删除属性,否则删除节点</param>
public static void Delete(string path, string node, string attribute)
{
    try
    {
        var doc = new XmlDocument();
        doc.Load(path);
        var xn = doc.SelectSingleNode(node);
        var xe = (XmlElement)xn;
        
        if (string.IsNullOrEmpty(attribute))
        {
            // 删除整个节点:需从父节点移除
            if (xn?.ParentNode != null)
                xn.ParentNode.RemoveChild(xn);
        }
        else
        {
            // 删除指定属性
            if (xe != null)
                xe.RemoveAttribute(attribute);
        }
        doc.Save(path);
    }
    catch (Exception er)
    {
        throw new Exception(er.ToString());
    }
}

第6步:按节点名递归查找数据

目的:在全局范围内查找第一个匹配名称的子节点并返回其内容。

/// <summary>
/// 获得xml文件中指定节点的节点数据
/// </summary>
public static string GetNodeInfoByNodeName(string path, string nodeName)
{
    var xmlString = string.Empty;
    try
    {
        var xml = new XmlDocument();
        xml.Load(path);
        var root = xml.DocumentElement;
        if (root == null) return xmlString;
        
        // SelectSingleNode支持//开头的XPath用于全局搜索
        var node = root.SelectSingleNode("//" + nodeName);
        if (node != null)
        {
            xmlString = node.InnerText;
        }
    }
    catch (Exception er)
    {
        throw new Exception(er.ToString());
    }
    return xmlString;
}

节点属性的高级管理

第7步:获取指定节点的指定属性值

目的:精确读取某节点下特定名称的属性,而非遍历所有属性。

/// <summary>
/// 功能:读取指定节点的指定属性值 
/// </summary>
public string GetXmlNodeAttributeValue(string path, string strNode, string strAttribute)
{
    var strReturn = "";
    try
    {
        var xml = new XmlDocument();
        xml.Load(path);
        var xmlNode = xml.SelectSingleNode(strNode);
        if (xmlNode != null)
        {
            var xmlAttr = xmlNode.Attributes;
            if (xmlAttr == null) return strReturn;
            
            // 遍历Attributes集合寻找指定名称
            for (var i = 0; i < xmlAttr.Count; i++)
            {
                if (xmlAttr[i].Name == strAttribute)
                {
                    strReturn = xmlAttr[i].Value;
                    break;
                }
            }
        }
    }
    catch (XmlException xmle)
    {
        throw new Exception(xmle.Message);
    }
    return strReturn;
}

第8步:批量设置XML节点属性

目的:通过XPath选中多个节点,统一修改它们的某一属性值。

/// <summary>
/// 功能:设置节点的属性值
/// </summary>
public void SetXmlNodeAttributeValue(string path, string xmlNodePath, string xmlNodeAttribute, string xmlNodeAttributeValue)
{
    try
    {
        var xml = new XmlDocument();
        xml.Load(path);
        
        // SelectNodes可以返回一组节点,实现批量处理
        var xmlNodeList = xml.SelectNodes(xmlNodePath);
        if (xmlNodeList == null) return;

        foreach (XmlNode xn in xmlNodeList)
        {
            if (xn.Attributes == null) continue;
            
            for (var i = 0; i < xn.Attributes.Count; i++)
            {
                if (xn.Attributes[i].Name == xmlNodeAttribute)
                {
                    xn.Attributes[i].Value = xmlNodeAttributeValue;
                    break; // 找到后跳出当前节点循环
                }
            }
        }
        // 注意:若需生效,通常后续应调用xml.Save(path),此处省略
    }
    catch (XmlException xmle)
    {
        throw new Exception(xmle.Message);
    }
}

混合模式与对象序列化

第9步:灵活读取资源(文件或字符串)

目的:支持从本地文件或内存字符串中加载XML并提取节点值。

// 定义枚举以区分源类型
public enum XmlType { File, String } 

/// <summary>
/// 读取XML资源中的指定节点内容
/// </summary>
/// <param name="source">文件路径或XML字符串</param>
/// <param name="xmlType">资源类型:File/String</param>
/// <param name="nodeName">节点名称</param>
/// <returns>节点内容的字符串形式</returns>
public static object GetNodeValue(string source, XmlType xmlType, string nodeName)
{
    var xd = new XmlDocument();
    if (xmlType == XmlType.File)
        xd.Load(source);
    else
        xd.LoadXml(source);

    var xe = xd.DocumentElement;
    XmlNode xn = null;
    if (xe != null)
    {
        xn = xe.SelectSingleNode("//" + nodeName);
    }
    
    // 安全返回值
    return xn?.InnerText ?? string.Empty;
}

第10步:更新指定节点内容并返回结果

目的:类似第4步,但增加了操作成功状态反馈。

/// <summary>
/// 更新XML文件中的指定节点内容
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="nodeName">节点名称(XPath)</param>
/// <param name="nodeValue">更新内容</param>
/// <returns>更新是否成功</returns>
public static bool UpdateNode(string filePath, string nodeName, string nodeValue)
{   
    try
    {
        bool flag = false;
        var xd = new XmlDocument();
        xd.Load(filePath);
        var xe = xd.DocumentElement;
        
        if (xe != null)
        {
            var xn = xe.SelectSingleNode("//" + nodeName);
            if (xn != null)
            {
                xn.InnerText = nodeValue;
                xd.Save(filePath); // 务必保存
                flag = true;
            }
        }
        return flag;
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }
}

第11步:将对象序列化为XML文件

目的:利用XmlSerializer将C#实例直接转换为XML格式文件写入磁盘,适用于复杂数据结构持久化。

/// <summary>
/// 将对象转化为xml,并写入指定路径的xml文件中
/// </summary>
public static string WriteXml<T>(T item, string path, string jjdbh, string ends)
{
    if (string.IsNullOrEmpty(ends)) ends = "send";
    
    var serializer = new XmlSerializer(item.GetType());
    // 组合完整文件路径
    var xmlPath = Path.Combine(path, $"{jjdbh}_{ends}.xml");

    // 防止文件被占用的重试机制
    int retries = 0;
    while (retries < 5)
    {
        try
        {
            using (var fs = System.IO.File.Create(xmlPath)) { fs.Close(); }
            // TextWriter方式写入UTF-8编码
            using (TextWriter writer = new StreamWriter(xmlPath, false, Encoding.UTF8))
            {
                var xml = new XmlSerializerNamespaces();
                xml.Add(string.Empty, string.Empty); // 去除默认xmlns
                serializer.Serialize(writer, item, xml);
                break; // 成功则跳出
            }
        }
        catch
        {
            retries++;
            Thread.Sleep(100); // 避免频繁尝试
        }
    }
    
    return SerializeToXmlStr<T>(item, true);
}

第12步:向父节点动态添加子节点

目的:在不破坏原有结构的情况下,追加新的子元素。

/// <summary>
/// 向一个已经存在的父节点中插入一个子节点 
/// </summary>
public void AddChildNode(string path, string parentNodePath, string childnodename)
{
    try
    {
        var xml = new XmlDocument();
        xml.Load(path);
        var parentXmlNode = xml.SelectSingleNode(parentNodePath);
        var childXmlNode = xml.CreateElement(childnodename);
        
        if (parentXmlNode != null)
        {
            // 如果父节点存在,直接追加
            parentXmlNode.AppendChild(childXmlNode);
        }
        else
        {
            // 异常处理:若找不到父节点,则添加到根目录(视业务需求而定)
            // GetXmlRoot(path)假设有一个辅助方法获取根节点
            // 这里简单演示:xml.DocumentElement?.AppendChild(childXmlNode);
            throw new ArgumentException("Parent Node Not Found."); 
        }
        xml.Save(path);
    }
    catch (XmlException xmle)
    {
        throw new Exception(xmle.Message);
    }
}

简要总结

上述方法覆盖了C#开发中操作XML最常见的场景。对于简单的配置读取和修改,使用XmlDocument配合XPath最为直观;而对于包含复杂类的数据交换,建议使用XmlSerializer进行对象与XML之间的自动映射。需要注意的是,频繁的文件I/O操作(如多次Save)会影响性能,建议在业务允许的情况下适当合并读写操作。以上就是C#操作XML通用方法汇总的详细内容,更多关于C# XML处理技巧的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表