使用C#讀寫xml檔案

xhubobo發表於2024-03-12

由於xml檔案的易讀特性,使得它非常適合作為程式配置檔案。和ini檔案相比,xml檔案可以實現列表等複雜引數配置,靈活性比較大。

使用C#讀取xml檔案,首先要載入xml檔案獲取XmlDocument物件,然後透過該物件獲取XmlNode型別的根節點,之後再對根節點獲取相應子節點的屬性或值。寫入xml檔案時,獲取對應的節點後設定其屬性或者值即可。

本文對C#操作xml檔案進行了封裝處理,方便程式碼複用。

1、xml檔案內容

<?xml version="1.0" encoding="utf-8"?>
<AppSettings>
  <!-- 除錯模式:0-否,1-是 -->
  <DebugMode>0</DebugMode>
  <!-- FTP伺服器引數 -->
  <FTP IP="127.0.0.1" Port="21" UserName="user" Password="user"/>
  <!-- 學生資訊:Grade-年級,Class-班級 -->
  <Students Grade="1" Class="7">
    <!-- 學生:Name-姓名,Age-年齡 -->
    <Student Name="Name1" Age="6"/>
    <Student Name="Name2" Age="7"/>
    <Student Name="Name3" Age="7"/>
    <Student Name="Name4" Age="6"/>
  </Students>
</AppSettings>

2、XmlHelper.cs

public static class XmlHelper
{
    public static bool GetNodeInnerInt(XmlNode node, string xpath, out int value)
    {
        var text = node?.SelectSingleNode(xpath)?.InnerText.Trim();
        return int.TryParse(text, out value);
    }

    public static bool GetNodeInnerStr(XmlNode node, string xpath, out string value)
    {
        value = node?.SelectSingleNode(xpath)?.InnerText.Trim();
        return !string.IsNullOrEmpty(value);
    }

    public static void SetNodeInnerValue(XmlNode node, string xpath, string text)
    {
        var item = node?.SelectSingleNode(xpath);
        if (item != null)
        {
            item.InnerText = text;
        }
    }

    public static bool GetNodeAttributeInt(XmlNode node, string xpath, out int value)
    {
        var text = node?.Attributes?.GetNamedItem(xpath)?.Value.Trim();
        return int.TryParse(text, out value);
    }

    public static bool GetNodeAttributeStr(XmlNode node, string xpath, out string value)
    {
        value = node?.Attributes?.GetNamedItem(xpath)?.Value.Trim();
        return !string.IsNullOrEmpty(value);
    }

    public static void SetNodeAttributeValue(XmlNode node, string xpath, string text)
    {
        var item = node?.Attributes?.GetNamedItem(xpath);
        if (item != null)
        {
            item.Value = text;
        }
    }
}

3、XmlConfigManager.cs

internal class StudentInfo
{
    public string Name { get; set; }
    public int Age { get; set; }

    public StudentInfo(string name, int age)
    {
        Name = name;
        Age = age;
    }
}

internal class ClassInfo
{
    public int Grade { get; set; }
    public int Class { get; set; }

    public List<StudentInfo> StudentInfoList { get; }

    public ClassInfo()
    {
        StudentInfoList = new List<StudentInfo>();
    }
}

internal sealed class XmlConfigManager
{
    public bool DebugMode { get; private set; } //除錯模式
    public ClassInfo ClassInfo { get; } //班級資訊

    #region 資料庫引數

    public string DbIp { get; private set; } //資料庫IP
    public int DbPort { get; private set; } = 1433; //資料庫埠
    public string DbCatalog { get; private set; } //資料庫名稱
    public string DbUser { get; private set; } //資料庫使用者名稱
    public string DbPassword { get; private set; } //資料庫密碼

    public string ConnectionString =>
        $@"data source={DbIp},{DbPort};initial catalog={DbCatalog};persist security info=True;user id={DbUser};password={DbPassword}";

    #endregion

    private string _configName;
    private static readonly ILog Logger = LogManager.GetLogger(nameof(XmlConfigManager));

    /// <summary>
    /// 初始化配置
    /// </summary>
    public void LoadConfig(string configName)
    {
        _configName = configName;

        //Get Config file
        var info = new DirectoryInfo(Assembly.GetExecutingAssembly().Location);
        var xmlFilePath = Path.Combine(info.Parent?.FullName ?? string.Empty, _configName);

        //從配置檔案讀取資料
        var xmlDoc = new XmlDocument();
        try
        {
            xmlDoc.Load(xmlFilePath);
        }
        catch (Exception e)
        {
            Logger.Error($@"載入配置檔案[{configName}]失敗:{e.Message}.");
            return;
        }

        var root = xmlDoc.SelectSingleNode("/AppSettings");
        LoadDebugModeConfig(root); //載入除錯模式
        LoadDatabaseConfig(root); //載入資料庫引數
        LoadClassInfoConfig(root); //載入班級資訊
    }

    #region 獲取引數

    private void LoadDebugModeConfig(XmlNode root)
    {
        try
        {
            var node = root?.SelectSingleNode("Common");
            if (XmlHelper.GetNodeInnerStr(node, "DebugMode", out var str))
            {
                DebugMode = str == "1";
            }
        }
        catch (Exception e)
        {
            Logger.Error($@"載入除錯模式異常:{e.Message}.");
        }
    }

    private void LoadDatabaseConfig(XmlNode root)
    {
        try
        {
            var node = root?.SelectSingleNode("Database");
            if (XmlHelper.GetNodeAttributeStr(node, "Ip", out var ip))
            {
                DbIp = ip;
            }

            if (XmlHelper.GetNodeAttributeInt(node, "Port", out var port))
            {
                DbPort = port;
            }

            if (XmlHelper.GetNodeAttributeStr(node, "Catalog", out var catalog))
            {
                DbCatalog = catalog;
            }

            if (XmlHelper.GetNodeAttributeStr(node, "User", out var user))
            {
                DbUser = user;
            }

            if (XmlHelper.GetNodeAttributeStr(node, "Password", out var password))
            {
                DbPassword = password;
            }
        }
        catch (Exception e)
        {
            Logger.Error($@"載入資料庫引數異常:{e.Message}.");
        }
    }

    private void LoadClassInfoConfig(XmlNode root)
    {
        try
        {
            var node = root?.SelectSingleNode("ClassInfo");
            if (XmlHelper.GetNodeAttributeInt(node, "Grade", out var val))
            {
                ClassInfo.Grade = val;
            }

            if (XmlHelper.GetNodeAttributeInt(node, "Class", out val))
            {
                ClassInfo.Class = val;
            }

            var nodeList = node?.SelectNodes("Student");
            if (nodeList == null || nodeList.Count == 0)
            {
                return;
            }

            foreach (XmlNode item in nodeList)
            {
                if (XmlHelper.GetNodeAttributeStr(item, "Name", out var str) &&
                    XmlHelper.GetNodeAttributeInt(item, "Age", out val))
                {
                    ClassInfo.StudentInfoList.Add(new StudentInfo(str, val));
                }
            }
        }
        catch (Exception e)
        {
            Logger.Error($@"載入班級資訊異常:{e.Message}.");
        }
    }

    #endregion

    #region 設定引數

    public void SetDatabaseConfig(string ip, string catalog, string user, string password)
    {
        DbIp = ip;
        DbCatalog = catalog;
        DbUser = user;
        DbPassword = password;

        //Get Config file
        var info = new DirectoryInfo(Assembly.GetExecutingAssembly().Location);
        var xmlFilePath = Path.Combine(info.Parent?.FullName ?? string.Empty, _configName);

        //從配置檔案讀取資料
        var xmlDoc = new XmlDocument();
        try
        {
            xmlDoc.Load(xmlFilePath);
            var node = xmlDoc.SelectSingleNode("/AppSettings/Database");
            XmlHelper.SetNodeAttributeValue(node, "Ip", ip);
            XmlHelper.SetNodeAttributeValue(node, "Catalog", catalog);
            XmlHelper.SetNodeAttributeValue(node, "User", user);
            XmlHelper.SetNodeAttributeValue(node, "Password", password);
            xmlDoc.Save(xmlFilePath);
        }
        catch (Exception e)
        {
            Logger.Error($@"設定資料庫引數失敗:{e.Message}.");
            throw;
        }
    }

    #endregion

    #region 單例模式

    private static XmlConfigManager _instance;

    private static readonly object LockInstanceHelper = new object();

    private XmlConfigManager()
    {
        ClassInfo = new ClassInfo();
    }

    public static XmlConfigManager Instance
    {
        get
        {
            if (_instance != null)
            {
                return _instance;
            }

            lock (LockInstanceHelper)
            {
                _instance = _instance ?? new XmlConfigManager();
            }

            return _instance;
        }
    }

    #endregion
}

相關文章