C# xml文件反序列化記事

hrx521發表於2024-05-27

可以使用XmlSerializer直接序列化和反序列化xml

反序列化如以下程式碼
        private T? XmlDeseriallize<T>(string filePath)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));

            using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                var xmlReader = System.Xml.XmlReader.Create(fileStream);
                var deserializedObject = (T?)serializer.Deserialize(xmlReader);
                return deserializedObject;
            }
        }
呼叫方法
var udidEntity = XmlDeseriallize<udid>(filePath)
其中,xml檔案內容示例:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<udid version="1.0">
    <header frequency="daily" id="20240520235039" type="DELTA_INCREMENTAL">
        <downloadFilePart>1</downloadFilePart>
        <downloadFileTotalParts>1</downloadFileTotalParts>
        <numberRkeyecordXML>3480</numberRkeyecordXML>
        <numberRecordsDatabase>3480</numberRecordsDatabase>
        <creationDate>2024-05-20 23:50:39</creationDate>
    </header>
    <devices>
        <device>
            <zxxsdycpbs>06974652782710</zxxsdycpbs>
            <cpbsbmtxmc>GS1</cpbsbmtxmc>
            <cpbsfbrq>2024-05-20</cpbsfbrq>
            <zxxsdyzsydydsl>1</zxxsdyzsydydsl>
            <sydycpbs></sydycpbs>
            <bszt>一維碼</bszt>
            <sfyzcbayz>是</sfyzcbayz>
            <zcbacpbs></zcbacpbs>
            <sfybtzjbs>否</sfybtzjbs>
            <btcpbsyzxxsdycpbssfyz></btcpbsyzxxsdycpbssfyz>
            <btcpbs></btcpbs>
            <cpmctymc>一次性使用吸引活檢針及附件</cpmctymc>
            <spmc></spmc>
            <ggxh>CLA2505</ggxh>
            <sfwblztlcp>否</sfwblztlcp>
            <cpms>吸引活檢針25G×50mm</cpms>
            <cphhhbh>202710</cphhhbh>
            <yflbm></yflbm>
            <qxlb>器械</qxlb>
            <flbm>14-01-09</flbm>
            <tyshxydm>91430300MA4RGKD89R</tyshxydm>
            <zczbhhzbapzbh>湘械注準20222141907</zczbhhzbapzbh>
            <ylqxzcrbarmc>湖南省拓川醫療科技有限公司</ylqxzcrbarmc>
            <ylqxzcrbarywmc></ylqxzcrbarywmc>
            <ybbm>C01060200700003149010000032</ybbm>
            <cplb>耗材</cplb>
            <cgzmraqxgxx>說明書或標籤上面不包含MR安全性資訊</cgzmraqxgxx>
            <sfbjwycxsy>是</sfbjwycxsy>
            <zdcfsycs></zdcfsycs>
            <sfwwjbz>是</sfwwjbz>
            <syqsfxyjxmj>否</syqsfxyjxmj>
            <mjfs></mjfs>
            <qtxxdwzlj></qtxxdwzlj>
            <tsrq></tsrq>
            <scbssfbhph>是</scbssfbhph>
            <scbssfbhxlh>否</scbssfbhxlh>
            <scbssfbhscrq>是</scbssfbhscrq>
            <scbssfbhsxrq>是</scbssfbhsxrq>
            <tscchcztj>本產品應貯存在通風良好、無腐蝕性氣體、清潔的環境內。儲存溫度範圍為0℃至30℃,相對溼度不超過85%。本產品應使用無腐蝕性氣體、對產品無汙染的運輸工具運輸,嚴禁日曬雨淋,搬運時應注意防止包裝破損。</tscchcztj>
            <tsccsm></tsccsm>
            <deviceRecordKey>069746527827102024042904331816</deviceRecordKey>
            <versionNumber>1</versionNumber>
            <versionTime>2024-05-20</versionTime>
            <versionStauts>新增</versionStauts>
            <correctionNumber>0</correctionNumber>
            <correctionRemark></correctionRemark>
            <correctionTime></correctionTime>
        </device>
        <device>
            <zxxsdycpbs>06931450103406</zxxsdycpbs>
            <cpbsbmtxmc>GS1</cpbsbmtxmc>
            <cpbsfbrq>2024-05-20</cpbsfbrq>
            <zxxsdyzsydydsl>1</zxxsdyzsydydsl>
            <sydycpbs></sydycpbs>
            <bszt>一維碼,二維碼,RFID</bszt>
            <sfyzcbayz>是</sfyzcbayz>
            <zcbacpbs></zcbacpbs>
            <sfybtzjbs>否</sfybtzjbs>
            <btcpbsyzxxsdycpbssfyz></btcpbsyzxxsdycpbssfyz>
            <btcpbs></btcpbs>
            <cpmctymc>定製式活動義齒</cpmctymc>
            <spmc></spmc>
            <ggxh>鈷鉻鉬支架可摘全口義齒 1402040900</ggxh>
            <sfwblztlcp>否</sfwblztlcp>
            <cpms>由合成樹脂牙、卡環、樹脂基託及連線體組成</cpms>
            <cphhhbh></cphhhbh>
            <yflbm></yflbm>
            <qxlb>器械</qxlb>
            <flbm>17-06-04</flbm>
            <tyshxydm>91441900675189913A</tyshxydm>
            <zczbhhzbapzbh>粵械注準20152171212</zczbhhzbapzbh>
            <ylqxzcrbarmc>東莞市帕菲克義齒科技有限公司</ylqxzcrbarmc>
            <ylqxzcrbarywmc></ylqxzcrbarywmc>
            <ybbm></ybbm>
            <cplb>耗材</cplb>
            <cgzmraqxgxx>說明書或標籤上面不包含MR安全性資訊</cgzmraqxgxx>
            <sfbjwycxsy>否</sfbjwycxsy>
            <zdcfsycs></zdcfsycs>
            <sfwwjbz>否</sfwwjbz>
            <syqsfxyjxmj>否</syqsfxyjxmj>
            <mjfs></mjfs>
            <qtxxdwzlj></qtxxdwzlj>
            <tsrq></tsrq>
            <scbssfbhph>是</scbssfbhph>
            <scbssfbhxlh>是</scbssfbhxlh>
            <scbssfbhscrq>是</scbssfbhscrq>
            <scbssfbhsxrq>否</scbssfbhsxrq>
            <tscchcztj></tscchcztj>
            <tsccsm></tsccsm>
            <deviceRecordKey>0693145010340620240518045505448</deviceRecordKey>
            <versionNumber>1</versionNumber>
            <versionTime>2024-05-20</versionTime>
            <versionStauts>新增</versionStauts>
            <correctionNumber>0</correctionNumber>
            <correctionRemark></correctionRemark>
            <correctionTime></correctionTime>
            <contactList>
                <contact>
                    <qylxrcz></qylxrcz>
                    <qylxryx>2074662804@qq.com</qylxryx>
                    <qylxrdh>0769-85160532</qylxrdh>
                </contact>
            </contactList>
        </device>
    </devices>
</udid>
C# 型別示例:
    //為從XML反序列化來而做準備
    public class udid
    {
        public header header { get; set; } = new();
        [XmlArrayItem("device")]//序列化反序列化時,當DeviceInfoDto對應的xml中元素的名字不是DeviceInfoDto而是device時,用該特性指定型別DeviceInfoDto對應的在xml中的元素的名字device。如果不這麼做,則需要變能,改以下程式碼中List<DeviceInfoDto>為List<device>其中device為一個繼承自DeviceInfoDto型別的子類
        public List<DeviceInfoDto> devices { get; set; } = new();
    }
    public class header
    {
        [XmlAttribute("frequency")]
        public string Frequency { get; set; } = string.Empty;
        [XmlAttribute("id")]
        public string Id { get; set; } = string.Empty;
        [XmlAttribute("type")]
        public string Type { get; set; } = string.Empty;
        public int downloadFilePart { get; set; }
        public int downloadFileTotalParts { get; set; }
        public int numberRkeyecordXML { get; set; }
        public int numberRecordsDatabase { get; set; }

        #region 當直接使用一個型別為Datetime屬性名為creationDate來在反序列化xml檔案中的日期時間型別的接收者時,反序列化會報錯:【字串“2020-07-31 09:29:16”不是有效的AllXsd值】。於是採入引入一箇中間屬性stringCreationDate(型別為string)和儲存其值的欄位_creationDate(型別為DateTime)的方式,執行過程1.當反序列化時從xml檔案讀取元素名為creationDate的元素值並透過stringCreationDate的set訪問器將其值在轉值為DateTime型別後存放於欄位_creationDate中 2.當C#程式碼中其他地方要訪問這個值時,就從creationDate屬性的get訪問器傳遞出_creationDate欄位的值。缺點:需引入不必要的屬性和欄位,而且屬性名還必須是public的,這會讓外部訪問者對這個中間屬性感到疑惑。
        private DateTime _creationDate;
        [XmlElement(ElementName = "creationDate")]
        public string stringCreationDate { get => _creationDate.ToString("yyyy-MM-dd HH:mm:ss"); set => _creationDate = Convert.ToDateTime(value); }
        [XmlIgnore]
        public DateTime creationDate { get => _creationDate; }
        #endregion
    }


    public class DeviceInfoDto
    {

        [XmlElement("cpmctymc")]//用來在做xml反序列化時,指定本屬性對應到xml檔案中的標籤的名字。(注意還有一個是XmlAttribute它是指對應到xml標籤的屬性名字)
        public string CPMCTYMC { get; set; }

        [XmlElement("spmc")]
        public string SPMC { get; set; }

        [XmlElement("ggxh")]
        public string GGXH { get; set; }

        [XmlElement("cpms")]
        public string CPMS { get; set; }

        [XmlElement("tyshxydm")]
        public string TYSHXYDM { get; set; }

        [XmlElement("flbm")]
        public string CategoryCode { get; set; }

        [XmlElement("deviceRecordKey")]
        public string deviceRecordKey { get; set; }

        [XmlElement("versionTime")]
        public DateTime versionTime { get; set; }

        [XmlElement("zxxsdycpbs")]
        public string DI { get; set; }

        [XmlElement("cpbsbmtxmc")]
        public string DeviceCodeType { get; set; }

        [XmlElement("ylqxzcrbarmc")]
        public string Manufacturer { get; set; }

        [XmlElement("ylqxzcrbarywmc")]
        public string EnManufacturer { get; set; }

        [XmlElement("zczbhhzbapzbh")]
        public string RegistrationCertificateNo { get; set; }

        [XmlElement("versionStauts")]
        public string versionStauts { get; set; }
    }

注意其中幾個關鍵點

  1. 讀取xml檔案時,以獨佔方式,這樣可以避免檔案被別的程式開啟時無法獨取的問題。
    using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {}
  2. 在序列化反序列化時,當型別DeviceInfoDto對應的xml中元素的名字不是DeviceInfoDto而是device時,用該特性指定型別DeviceInfoDto對應的在xml中的元素的名字device。如果不這麼做,則需要變通,改以下程式碼中List<DeviceInfoDto>List<device>其中device為一個繼承自DeviceInfoDto型別的子類
        [XmlArrayItem("device")]
        public List<DeviceInfoDto> devices { get; set; } = new();
  1. 反序列化時對應C#型別DateTime時的報錯處理
    當直接使用一個型別為Datetime屬性名為creationDate來在反序列化xml檔案中的日期時間型別的接收者時,反序列化會報錯:【字串“2020-07-31 09:29:16”不是有效的AllXsd值】。於是採入引入一箇中間屬性stringCreationDate(型別為string)和儲存其值的欄位_creationDate(型別為DateTime)的方式,執行過程1.當反序列化時從xml檔案讀取元素名為creationDate的元素值並透過stringCreationDate的set訪問器將其值在轉值為DateTime型別後存放於欄位_creationDate中 2.當C#程式碼中其他地方要訪問這個值時,就從creationDate屬性的get訪問器傳遞出_creationDate欄位的值。缺點:需引入不必要的屬性和欄位,而且屬性名還必須是public的,這會讓外部訪問者對這個中間屬性感到疑惑。
        private DateTime _creationDate;
        [XmlElement(ElementName = "creationDate")]
        public string stringCreationDate { get => _creationDate.ToString("yyyy-MM-dd HH:mm:ss"); set => _creationDate = Convert.ToDateTime(value); }
        [XmlIgnore]
        public DateTime creationDate { get => _creationDate; }
  1. 序列化反序列化時,XmlSerializer可識別的常用的C#特性標籤 Attribute
    a. [XmlRoot("udid")]
    用於C#類名上,用於指明根型別對應的xml中的元素名
    b. [XmlElement("creationDate")]
    用於C#屬性或欄位上,用於指明屬性對應的xml元素名或者叫標籤名為 creationDate
    c. [XmlAttribute("frequency")]
    用於C#屬性或欄位上,用於指明屬性或欄位對應的XML元素的屬性名為 frequency
    d. [XmlIgnore]
    用於C#屬性或欄位上,用來標記該欄位在序列化反序列化XML文件時是要忽略的C#屬性或欄位
    e. [XmlArrayItem("device")]
    用於C# List<T>集合型別的屬性或欄位上,用來標記集合中的元素型別T在XML文件中對應的元素名稱

更多參考:

https://www.cnblogs.com/guogangj/p/7489218.html

相關文章