XML

请明月發表於2024-10-18

概念

C# 中讀取Xml檔案有兩種方式
注意這裡沒有展示包含屬性的讀取,如果包含屬性DataSet方法的讀取會相對複雜一些

讀取檔案

1.使用DataSet讀取對應檔案

    public DataSet GetXmlDataset(string path)
    {
        DataSet dataSet = new DataSet();
        dataSet.ReadXml(path);//ReadXml(String)使用指定的檔案將 XML架構和資料讀入 DataSet。
        return dataSet;
    }

2.使用XmlDocument讀取對應檔案需要引入using System.Xml模組

    public XmlNode GetXmlXmlDocument(string path)
    {
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.Load(path);
        XmlNode node = xmlDocument.DocumentElement;
        return node;
    }

如果是簡單的讀取可以直接使用DataSet讀取檔案,XmlDocument可以操作更復雜的檔案。

寫入檔案

使用XmlDocument中的CreateElement這個Api建立節點,操作完成後直接使用Save(Path)進行儲存。
下面這段程式碼實現了向xml檔案中寫入一個節點,然後儲存

    public void WriteDocument(XmlDocument xmlDocument, string path)
    {
        XmlElement xn = xmlDocument.CreateElement("student");
        XmlElement xesub1 = xmlDocument.CreateElement("name");
        xesub1.InnerText = "趙九";//設定文字節點
        xn.AppendChild(xesub1);//新增到<xn>節點中
        XmlElement xesub2 = xmlDocument.CreateElement("sex");
        xesub2.InnerText = "男";//設定文字節點
        xn.AppendChild(xesub2);//新增到<xn>節點中
        XmlElement xesub3 = xmlDocument.CreateElement("old");
        xesub3.InnerText = "50";//設定文字節點
        xn.AppendChild(xesub3);//新增到<xn>節點中

        xmlDocument.SelectSingleNode("studentList").AppendChild(xn);
        xmlDocument.Save(path);
    }

程式碼示例

這段程式碼示例,主要作用是將xml檔案中表示對應含義的節點轉換為對應的類,這裡使用了以上兩種方法讀取檔案,使用XmlDocument寫入檔案。

使用DataSet讀取並進行轉換

這裡的轉換我使用了泛型擴充套件這個方法,具體實現思路:
1.獲取所有列標籤並且儲存在列表中
2.讀取每一行資料並且使用反射生成物件
3.根據讀取出的資料使用提前儲存好的FieldInfo進行約束和賦值物件
4.將物件新增入列表中

/// <summary>
/// 讀取不帶標籤的XMl, 並且將資料使用反射建立對應的類,最後返回所有的物件
/// </summary>
/// <typeparam name="T">需要將該檔案中的節點轉換的類</typeparam>
/// <param name="list">儲存轉換的類</param>
/// <param name="path">檔案地址</param>
public void GetXmlData<T>(ref List<T> list, string path) where T : new()
{
    DataSet dataSet = GetXmlDataset(path);
    List<FieldInfo> fieldinfos = new List<FieldInfo>();
    List<string> columns = new List<string>();
    Type type = typeof(T);
    foreach (object item in dataSet.Tables[0].Columns)
    {
        FieldInfo fieldInfo = type.GetField(item.ToString());
        if (fieldInfo != null)
        {
            fieldinfos.Add(fieldInfo);
        }
        columns.Add(item.ToString());
    }
    for (int i = 0; i < dataSet.Tables[0].Rows.Count; i++)
    {
        T obj = (T)Activator.CreateInstance(type);

        for (int j = 0; j < columns.Count; j++)
        {
            FieldInfo info = type.GetField(columns[j].ToString());
            if (info != null)
            {
                info.SetValue(obj, Convert.ChangeType(dataSet.Tables[0].Rows[i][columns[j]], info.FieldType));
            }
        }
        list.Add(obj);

    }
}
使用XmlDocument讀取並進行轉換

使用XmlDocument稍微有一些區別但具體流程還是和上面一樣

    public void GetDocumentData<T>(ref List<T> list, string path) where T : new()
    {
        XmlNode node = GetXmlXmlDocument(path);
        List<FieldInfo> fieldinfos = new List<FieldInfo>();
        List<string> columns = new List<string>();
        Type type = typeof(T);
        foreach (XmlNode item in node.SelectNodes(type.ToString())[0].ChildNodes)
        {
            FieldInfo fieldInfo = type.GetField(item.Name);
            if (fieldInfo != null)
            {
                fieldinfos.Add(fieldInfo);
            }
            columns.Add(item.Name);
        }
        for (int i = 0; i < node.SelectNodes(type.ToString()).Count; i++)
        {
            T obj = (T)Activator.CreateInstance(type);

            for (int j = 0; j < columns.Count; j++)
            {
                FieldInfo info = type.GetField(columns[j].ToString());
                if (info != null)
                {
                    info.SetValue(obj, Convert.ChangeType(node.SelectNodes(type.ToString())[i].ChildNodes[j].InnerText, info.FieldType));
                }
                //Debug.Log(node.SelectNodes(type.ToString())[i].ChildNodes[j].Attributes["id"].InnerText);
            }
            list.Add(obj);

        }
    }

以下是該指令碼的全部程式碼,貼一下

using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Xml;
using UnityEngine;

public class XMLLoad : MonoBehaviour
{
    public void Start()
    {
        string path = Application.dataPath+ "/Resources/Xml/XMLFile1.xml";
        List<student> students = new List<student>();
        GetDocumentData<student>(ref students, path);
        DisPlayList(students);
        GetXmlData<student>(ref students, path);
        DisPlayList(students);

    }

    public void DisPlayList(List<student> students)
    {
        foreach (student student in students)
        {
            Debug.Log(student.ToString());
        }
    }
    /// <summary>
    /// 讀取不帶標籤的XMl, 並且將資料使用反射建立對應的類,最後返回所有的物件
    /// </summary>
    /// <typeparam name="T">需要將該檔案中的節點轉換的類</typeparam>
    /// <param name="list">儲存轉換的類</param>
    /// <param name="path">檔案地址</param>
    public void GetXmlData<T>(ref List<T> list, string path) where T : new()
    {
        DataSet dataSet = GetXmlDataset(path);
        List<FieldInfo> fieldinfos = new List<FieldInfo>();
        List<string> columns = new List<string>();
        Type type = typeof(T);
        foreach (object item in dataSet.Tables[0].Columns)
        {
            FieldInfo fieldInfo = type.GetField(item.ToString());
            if (fieldInfo != null)
            {
                fieldinfos.Add(fieldInfo);
            }
            columns.Add(item.ToString());
        }
        for (int i = 0; i < dataSet.Tables[0].Rows.Count; i++)
        {
            T obj = (T)Activator.CreateInstance(type);

            for (int j = 0; j < columns.Count; j++)
            {
                FieldInfo info = type.GetField(columns[j].ToString());
                if (info != null)
                {
                    info.SetValue(obj, Convert.ChangeType(dataSet.Tables[0].Rows[i][columns[j]], info.FieldType));
                }
            }
            list.Add(obj);

        }
    }

    public void GetDocumentData<T>(ref List<T> list, string path) where T : new()
    {
        XmlNode node = GetXmlXmlDocument(path);
        List<FieldInfo> fieldinfos = new List<FieldInfo>();
        List<string> columns = new List<string>();
        Type type = typeof(T);
        foreach (XmlNode item in node.SelectNodes(type.ToString())[0].ChildNodes)
        {
            FieldInfo fieldInfo = type.GetField(item.Name);
            if (fieldInfo != null)
            {
                fieldinfos.Add(fieldInfo);
            }
            columns.Add(item.Name);
        }
        for (int i = 0; i < node.SelectNodes(type.ToString()).Count; i++)
        {
            T obj = (T)Activator.CreateInstance(type);

            for (int j = 0; j < columns.Count; j++)
            {
                FieldInfo info = type.GetField(columns[j].ToString());
                if (info != null)
                {
                    info.SetValue(obj, Convert.ChangeType(node.SelectNodes(type.ToString())[i].ChildNodes[j].InnerText, info.FieldType));
                }
                //Debug.Log(node.SelectNodes(type.ToString())[i].ChildNodes[j].Attributes["id"].InnerText);
            }
            list.Add(obj);

        }
    }



    public DataSet GetXmlDataset(string path)
    {
        DataSet dataSet = new DataSet();
        dataSet.ReadXml(path);
        return dataSet;
    }

    public XmlNode GetXmlXmlDocument(string path)
    {
        XmlDocument xmlDocument = new XmlDocument();
        xmlDocument.Load(path);
        XmlNode node = xmlDocument.DocumentElement;
        //WriteDocument(xmlDocument, path);
        return node;
    }

    public void WriteDocument(XmlDocument xmlDocument, string path)
    {
        XmlElement xn = xmlDocument.CreateElement("student");
        XmlElement xesub1 = xmlDocument.CreateElement("name");
        xesub1.InnerText = "趙九";//設定文字節點
        xn.AppendChild(xesub1);//新增到<xn>節點中
        XmlElement xesub2 = xmlDocument.CreateElement("sex");
        xesub2.InnerText = "男";//設定文字節點
        xn.AppendChild(xesub2);//新增到<xn>節點中
        XmlElement xesub3 = xmlDocument.CreateElement("old");
        xesub3.InnerText = "50";//設定文字節點
        xn.AppendChild(xesub3);//新增到<xn>節點中

        xmlDocument.SelectSingleNode("studentList").AppendChild(xn);
        xmlDocument.Save(path);
    }
}

public class student
{
    public int id;
    public string name;
    public string sex;
    public int old;
    public override string ToString()
    {
        return $"id:{this.id},name:{this.name},sex:{this.sex},old:{this.old}";
    }
}

表現

XMLFile1.xml 檔案內容

<?xml version="1.0" encoding="utf-8"?>
<studentList>
  <student>
    <name>張三</name>
    <sex>男</sex>
    <old>20</old>
  </student>
  <student>
    <name>李四</name>
    <sex>女</sex>
    <old>21</old>
  </student>
  <student>
    <name>王五</name>
    <sex>男</sex>
    <old>40</old>
  </student>
  <student>
    <name>王五</name>
    <sex>女</sex>
    <old>18</old>
  </student>
  <student>
    <name>鄭七</name>
    <sex>女</sex>
    <old>31</old>
  </student>
  <student>
    <name>趙九</name>
    <sex>男</sex>
    <old>50</old>
  </student>
</studentList>

輸出獲取到的檔案內容: