C#操作XML通用方法汇总
本文整理并优化了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处理技巧的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









