1、什么是XML?
2、XDocument和XmlDocument的區別?
3、XDocument
4、XmlDocument
5、LINQ to XML
6、XML序列化與反序列化
因為這幾天用到了不熟悉的xml統計數據,啃了網上的資料解決了問題,故總結下xml知識。
// 創建一個xml文檔 XDocument所屬命名空間:using System.Xml.Linq; XDocument xDoc = new XDocument(); // 添加根節點 XElement xRoot = new XElement("Root"); // 添加節點使用Add xDoc.Add(xRoot); // 創建一個學生加到root中 // 1、創建學生節點 XElement xStudent = new XElement("Student"); // 2、創建學生姓名、年齡、性別 XElement xName = new XElement("Name"); XElement xAge = new XElement("Age"); XElement xGender = new XElement("Gender"); //給每個元素賦值 xName.Value = "張三"; xAge.Value = "19"; xGender.Value = "男"; // 3、添加節點(沒有順序之分) xStudent.Add(xName, xAge, xGender); //把學生姓名,年齡,性別元素添加到學生節點下 xRoot.Add(xStudent); //把學生節點添加到根節點下 // 為Student添加屬性 XAttribute xId = new XAttribute("id", ".Net01"); xStudent.Add(xId); // 保存該文檔 xDoc.Save("myxml.xml");
運行后的結果:
<?xml version="1.0" encoding="utf-8"?> <Root> <Student id=".Net01"> <Name>張三</Name> <Age>19</Age> <Gender>男</Gender> </Student> </Root>
但XDocument提供了更舒服的創建xml方式:
static void saveXml2() { //如果你喜歡這樣寫的話,那就一級一級階梯狀排列好。很有層次感,看起來特明了 XDocument xDoc = new XDocument( new XElement("Root", new XElement("FlyInfo", new XElement("Sum", new XElement("AirLine", "航空"), new XElement("Seat", "經濟艙"), new XElement("Rating", "A"), new XElement("Gai", "可以改"), new XElement("Tui", "可以退"), new XElement("Qian", "可以簽"), new XElement("com", new XElement("comm", "暫無") ) ) ), new XElement("FlyInfo", new XElement("Sum", new XElement("AirLine", "航空"), new XElement("Seat", "頭等艙"), new XElement("Rating", "R"), new XElement("Gai", "不可以改"), new XElement("Tui", "不可以退"), new XElement("Qian", "不可以簽") ) ) ) ); xDoc.Save("Test.xml"); }
運行成功后就生成了一個Test.xml文檔
也許你也見過這樣的寫法,效果是相同的(與上面樹結構不同)
static void saveXMLs() { XDocument xDoc = new XDocument(); //實例化一個xml(內容)文檔 XElement xRoot = new XElement("Root"); //創建一個xml根節點 xDoc.Add(xRoot); //把根節點添加到xml文檔 記住:一個xml文檔只能有一個根節點,可以多個父節點。多個子節點,可以把任何一個元素作為父節點或子節點 //以下均是xml元素 FlyInfo元素(父節點)下又有子元素(子節點) 如果把一個學校(根節點) 很多個教室(父節點) 每個班級的學生(子節點)就是所屬班級(父節點)的子節點 XElement xFlyInfo = new XElement("FlyInfo"); // XElement xAirLine = new XElement("AirLine"); XElement xSeat = new XElement("Seat"); XElement xRating = new XElement("Rating"); XElement xGai = new XElement("Gai"); XElement xTui = new XElement("Tui"); XElement xQian = new XElement("Qian"); xAirLine.Value = "航空"; xSeat.Value = "經濟艙"; xRating.Value = "A"; xGai.Value = "可以改"; xTui.Value = "可以退"; xQian.Value = "可以簽"; xRoot.Add(xAirLine, xSeat, xRating, xGai, xTui, xQian); //把元素添加到根節點中 xDoc.Save("test.xml"); //保存xml文檔 }
運行結果:
當然你也可以用DataSet,先保存在內存緩存中,然后在保存到磁盤
static void saveDtable() { DataSet ds = new DataSet("Root"); //實例化一個DataSet 並初始化值為Root,映射到xml時則是根節點,當沒初始化值時。默認是NewDataSet DataTable table = new DataTable("FlyInfo"); //實例化一個table。同時取名為FlyInfo。當映射到xml文檔時則是xml文檔中的一個父節點,table必須指定表名,因為它可沒有默認值。 //table.TableName = "FlyInfo"; //如果初始化沒設置表名,可以通過屬性設置。也OK //給Table添加列,映射到xml文檔時是當前父節點的子節點 table.Columns.Add("AirLine"); table.Columns.Add("Seat"); table.Columns.Add("Rating"); table.Columns.Add("Gai"); table.Columns.Add("Tui"); table.Columns.Add("Qian"); //創建與該表具有相同架構的新行 DataRow dr = table.NewRow(); //添加數據 dr["AirLine"] = "航空"; dr["Seat"] = "經濟艙"; dr["Rating"] = "A"; dr["Gai"] = "可以改"; dr["Tui"] = "可以退"; dr["Qian"] = "可以簽"; table.Rows.Add(dr); //把每一行添加到table //以下兩句效果相同 ds.Tables.Add(table); //把table添加到DataSet(數據集)中 //ds.Tables.Add(table.Copy()); //這樣也行,復制當前表格的數據和結構,然后添加到DataSet中 ds.WriteXml("tableDemo.xml"); //保存咯 //下面都是清除數據,釋放資源
//dt.Rows[0].Delete(); 刪除某一行
//dt.AcceptChanges(); 返回刪除后的數據 ds.Clear(); ds.Tables.Clear(); }
嗯。以上幾個示列都是創建新的xml文檔,現在我們來看看如何給已有的xml文檔添加新的數據。還是拿上面xml文檔例子來進行。
已有的xml數據:
<?xml version="1.0" standalone="yes"?> <Root> <FlyInfo> <AirLine>航空</AirLine> <Seat>經濟艙</Seat> <Rating>A</Rating> <Gai>可以改</Gai> <Tui>可以退</Tui> <Qian>可以簽</Qian> </FlyInfo> </Root>
接下來我們一步一步來看,當完成一個就同時看運行后的代碼。比較明了
來看怎么給節點末尾添加新的節點:
//XDocument提供了Load()靜態方法 XDocument xDoc = XDocument.Load("tableDemo.xml"); //加載xml文檔。這里是相對路徑 //當你生了個兒子。想上戶口簿時,就給其父親加個兒子節點 XElement xfa = xDoc.Root.Element("FlyInfo"); //找到父親(FlyInfo是父節點,所屬他下面的都是子節點) XNode xson = xfa.LastNode; //找到最后一個兒子節點 //這里給父親添加個兒子(在末尾添加的) xson.AddAfterSelf( new XElement("son","還沒生子") //這里son沒有兒子。也就是son節點沒有子節點 ); xDoc.Save("tableDemo.xml"); //保存數據 其實總的來說是把全部數據讀到內存中然后在內存中追加數據后再全部保存tableDemo.xml
看運行后的結果
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <Root> <FlyInfo> <AirLine>航空</AirLine> <Seat>經濟艙</Seat> <Rating>A</Rating> <Gai>可以改</Gai> <Tui>可以退</Tui> <Qian>可以簽</Qian> <son>還沒生子</son> </FlyInfo> </Root>
你運行一次就會增加一個"兒子"挺划算的······
當然,也許你會想,那如果我要在指定的兒子節點后面添加一個節點(這樣是指兄弟節點)呢?
1、根據元素名(節點名);
2、根據元素屬性來定位某個節點;
先看第一種情況:根據元素名定位節點
如果你是順序看下來的。那你看到這句代碼就知道 XElement xfa = xDoc.Root.Element("FlyInfo");
這就是根據元素名來找到“FlyInfo”節點,這是在文檔開始順序查找的。也就是說不管有多個“FlyInfo”節點。程序也只會找到第一個。並停止,
當然如果沒找到“FlyInfo”節點,顯然這句:“XNode xson = xfa.LastNode; //找到最后一個兒子節點”就會報異常:未將對象引用設置到對象的實例-點擊看此博文能學到更多。因為xfa變量是空怎么會有子節點呢?
好。我們在節點“<Seat>經濟艙</Seat>”后添加一個兄弟節點“<Info>詳細信息</Info>”
只要改變查找方式: XElement i = xDoc.Root.Element("FlyInfo").Element("Seat"); //父節點(FlyInfo)下的子節點(Seat)。
其他代碼不變:
XElement i = xDoc.Root.Element("FlyInfo").Element("Seat"); //父節點(FlyInfo)下的子節點(Seat) //這里給父親添加個兒子(在末尾添加的) 在之前添加用:AddBeforeSelf i.AddAfterSelf( new XElement("Info","詳細信息") //這里Info沒有兒子。也就是Info節點沒有子節點 ); xDoc.Save("tableDemo.xml");
運行后看結果:
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <Root> <FlyInfo> <AirLine>航空</AirLine> <Seat>經濟艙</Seat> <Info>詳細信息</Info> <Rating>A</Rating> <Gai>可以改</Gai> <Tui>可以退</Tui> <Qian>可以簽</Qian> </FlyInfo> </Root>
然后第二種情況:根據元素屬性定位節點
既然是元素屬性,那元素就必然會有相應的屬性名,其實,當你創建xml數據的時候就可以初始化給Element(元素)添加相應的屬性;
我這里初始化沒有添加,那現在我們來給“Rating”元素添加一個屬性並賦值:name="mark",添加屬性用XAttribute類
XElement i = xDoc.Root.Element("FlyInfo").Element("Rating"); //父節點(FlyInfo)下的子節點(Rating) i.Add(new XAttribute("name", "mark")); xDoc.Save("tableDemo.xml");
同樣運行看結果:“Rating ”元素添加了個name屬性
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <Root> <FlyInfo> <AirLine>航空</AirLine> <Seat>經濟艙</Seat> <Rating name="mark">A</Rating> <Gai>可以改</Gai> <Tui>可以退</Tui> <Qian>可以簽</Qian> </FlyInfo> </Root>
屬性有了。那么就可以找到有name屬性的元素
IEnumerable<XNode> atr = xDoc.Root.Element("FlyInfo").Nodes(); //找到FlyInfo節點下所有子節點 foreach (XElement item in atr) //遍歷節點 { if (item.Attribute("name") != null) //不為null說明找到了有name屬性的節點,拆開寫的話: XAttribute at = item.Attribute("name"); 然后if(at!=null){...} { item.AddAfterSelf( new XElement("attr","根據屬性查找節點並添加") ); } } xDoc.Save("tableDemo.xml");
運行后看結果:
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <Root> <FlyInfo> <AirLine>航空</AirLine> <Seat>經濟艙</Seat> <Rating name="mark">A</Rating> <attr>根據屬性查找節點並添加</attr> <Gai>可以改</Gai> <Tui>可以退</Tui> <Qian>可以簽</Qian> </FlyInfo> </Root>
//創建一個xml文檔 XmlDocument xmlDoc = new XmlDocument(); //定義xml聲明,XmlDoxument跟XDocument不同,默認沒有聲明, XmlDeclaration xmlDec = xmlDoc.CreateXmlDeclaration("1.0", "GB2312", "yes"); xmlDoc.AppendChild(xmlDec); //創建一個根節點 XmlElement xmlRoot = xmlDoc.CreateElement("Root"); //把根節點添加到xml文檔 xmlDoc.AppendChild(xmlRoot); //創建學生節點 XmlElement xmlStudent = xmlDoc.CreateElement("Student"); //創建學生姓名,年齡,性別 XmlElement xmlName = xmlDoc.CreateElement("Name"); XmlElement xmlAge = xmlDoc.CreateElement("Age"); XmlElement xmlGender = xmlDoc.CreateElement("Gender"); //賦值 xmlName.InnerText = "張三"; xmlAge.InnerText = "20"; xmlGender.InnerText = "男"; //當然。你喜歡的話,可以添加屬性 XmlAttribute xId = xmlDoc.CreateAttribute("id"); xId.Value = ".Net01"; xmlStudent.SetAttributeNode(xId); //添加節點 xmlStudent.AppendChild(xmlName); xmlStudent.AppendChild(xmlAge); xmlStudent.AppendChild(xmlGender); xmlRoot.AppendChild(xmlStudent); //保存xml文檔 xmlDoc.Save("xmlDocument.xml");
同樣,運行后是我們期待的結果:
<?xml version="1.0" encoding="GB2312" standalone="yes"?> <Root> <Student id=".Net01"> <Name>張三</Name> <Age>20</Age> <Gender>男</Gender> </Student> </Root>
那同樣我們用XmlDocument來給已有的xml文檔添加數據,還是用“FlyInfo”這個例子
首先來看已有的xml數據
<?xml version="1.0" encoding="utf-8"?> <Root> <FlyInfo> <AirLine>航空</AirLine> <Seat>經濟艙</Seat> <Rating>A</Rating> <Gai>可以改</Gai> <Tui>可以退</Tui> <Qian>可以簽</Qian> </FlyInfo> </Root>
當你添加一個與“FlyInfo”有相同結構的節點時:
static void xmlDocu() { //實例化一個XmlDocument文檔 XmlDocument xmlDoc = new XmlDocument(); //加載xml文檔 xmlDoc.Load("xmlDoumer.xml"); //ChildNodes[0]這是找到第一個,樹結構一樣。找誰都行。當然要保證有咯 XmlNode node = xmlDoc.DocumentElement.ChildNodes[0].CloneNode(true); //因為是添加具有相同節點樹結構,所有找到一個樹結構,創建副本,即克隆 //以下是獲取父節點下的子節點 這里更改了每個子元素的內容。如果你不更改。默認值還是原來的值 node["AirLine"].InnerText = "北京航空"; node["Seat"].InnerText = "頭等艙"; node["Rating"].InnerText = "AB"; node["Gai"].InnerText = "不改"; node["Tui"].InnerText = "不退"; node["Qian"].InnerText = "不簽"; //在根節點下最后一個子元素末尾添加 xmlDoc.DocumentElement.AppendChild(node); xmlDoc.Save("xmlDoumer.xml"); //保存 }
運行結果:
<?xml version="1.0" encoding="utf-8"?> <Root> <FlyInfo> <AirLine>航空</AirLine> <Seat>經濟艙</Seat> <Rating>A</Rating> <Gai>可以改</Gai> <Tui>可以退</Tui> <Qian>可以簽</Qian> </FlyInfo> <FlyInfo> <AirLine>北京航空</AirLine> <Seat>頭等艙</Seat> <Rating>AB</Rating> <Gai>不改</Gai> <Tui>不退</Tui> <Qian>不簽</Qian> </FlyInfo> </Root>
也許你會說這是具有相同xml樹結構。如果我想添加自己的xml樹結構呢?那......
static void xmlDocu() { //實例化一個XmlDocument文檔 XmlDocument xmlDoc = new XmlDocument(); //加載xml文檔 xmlDoc.Load("xmlDoumer.xml"); //ChildNodes[0]這是找到第一個,樹結構一樣。找誰都行。當然要保證有咯 XmlNode node = xmlDoc.DocumentElement.ChildNodes[0].CloneNode(true); //因為是添加具有相同節點樹結構,所有找到一個樹結構,創建副本,即克隆 //以下是獲取父節點下的子節點 這里更改了每個子元素的內容。如果你不更改。默認值還是原來的值 node["AirLine"].InnerText = "北京航空"; node["Seat"].InnerText = "頭等艙"; node["Rating"].InnerText = "AB"; node["Gai"].InnerText = "不改"; node["Tui"].InnerText = "不退"; node["Qian"].InnerText = "不簽"; //修改屬性:很顯然要保證子節點有屬性。同樣 (當然這也是你百分百確定有這個屬性) //node["AirLine"].Attributes["id"].Value = "90"; //當然,如果你不想要這個元素 就干掉 //node.RemoveChild(node["Qian"]); //創建一個子節點的兩種方式 XmlElement addNode = xmlDoc.CreateElement("Phone"); XmlNode xno = xmlDoc.CreateNode(XmlNodeType.Element, "link", null); //給元素賦值 xno.InnerText = "新來的Node"; addNode.InnerText = "15858585588"; //把節點添加到末尾 node.AppendChild(xno); node.AppendChild(addNode); //在根節點下最后一個子元素末尾添加 xmlDoc.DocumentElement.AppendChild(node); xmlDoc.Save("xmlDoumer.xml"); //保存 }
同樣不厭其煩的看結果:
<?xml version="1.0" encoding="utf-8"?> <Root> <FlyInfo> <AirLine>航空</AirLine> <Seat>經濟艙</Seat> <Rating>A</Rating> <Gai>可以改</Gai> <Tui>可以退</Tui> <Qian>可以簽</Qian> </FlyInfo> <FlyInfo> <AirLine>北京航空</AirLine> <Seat>頭等艙</Seat> <Rating>AB</Rating> <Gai>不改</Gai> <Tui>不退</Tui> <Qian>不簽</Qian> <link>新來的Node</link> <Phone>15858585588</Phone> </FlyInfo> </Root>
/// <summary> /// linq to xml--創建xml文檔 /// </summary> public static void createXML() { var xDoc = new XDocument(new XElement("Root", new XElement("Student", new XAttribute("Id", 1), //添加屬性 new XElement("name", "Tom"), new XElement("age", 18) ), new XElement("Student", new XAttribute("Id", 2), //屬性 new XElement("name", "Jim"), new XElement("age", 20) ) ) ); xDoc.Save(Console.Out); //為了方便,我直接輸出到控制台觀看結果 xDoc.Save("Student.xml"); //保存 }
我們看運行結果。xml文檔就順理成章的生成了

/// <summary> /// linq to xml--讀取xml文檔 /// </summary> public static void ReadXML() { XDocument xDoc = XDocument.Load("Student.xml"); //加載xml文檔,(相對路勁) /*這里用Descendants(xName)的好處是可以跨層次,跨節點,而不像Element 比如要找到所有的Student節點。 Element: xDoc.Element("Root").Elements() 這里必須是從根節點到子節點一級一級找。 Descendants:xDoc.Descendants("Student") 跨了 根節點 Root 直接在根節點下找 */ var E1 = from item in xDoc.Descendants("Student") //找到所有Student元素 select item; E1.ToList().ForEach(it => Console.WriteLine(it)); Console.WriteLine("-----------分割線1-----------"); //找到學生屬性Id=1的學生。顯示學生姓名和年齡 var E2 = from item in xDoc.Descendants("Student") where item.Attribute("Id").Value == "1" select new { name = item.Element("name").Value, age = item.Element("age").Value }; E2.ToList().ForEach(it => Console.WriteLine(string.Format("姓名:{0},年齡:{1}", it.name, it.age))); Console.WriteLine("-----------分割線2-----------"); //如果學生Id=1有多個,而你只想顯示第一個。則用FirstOrDefault(),返回滿足條件的第一個元素 var E3 = (from item in xDoc.Descendants("Student") where item.Attribute("Id").Value == "1" select new { name = item.Element("name").Value, age = item.Element("age").Value }).FirstOrDefault(); //因為此時返回的結果已不是集合,可直接輸出 Console.WriteLine("姓名為:" + E3.name + "年齡為:" + E3.age); Console.WriteLine("-----------分割線3-----------"); //顯示所有學生的姓名和年齡 var E4 = from item in xDoc.Descendants("Student") select new { name = item.Element("name").Value, age = item.Element("age").Value }; E4.ToList().ForEach(it => Console.WriteLine(string.Format("姓名:{0},年齡為:{1}", it.name, it.age))); //以上僅僅是舉了些簡單的例子,實際中還得根據需要靈活運用。記住。xml是區分大小寫的。所以要注意屬性名和元素名的大小寫要一致 }
看結果圖:
/// <summary> /// linq to xml--編輯xml文檔 /// </summary> public static void EditXML() { XDocument xDoc = XDocument.Load("Student.xml"); //加載xml文檔 //現在你發現學生的姓名和年齡不能滿足需求,需要添加一個性別信息 ,那就得添加一個元素<sex>male</sex> var E5 = from item in xDoc.Descendants("Student") //找到所有(元素名為Student)學生節點 select item; E5.ToList().ForEach(it => it.SetElementValue("sex", "male")); //當然。這是給所有的學生都添加性別為male xDoc.Save(Console.Out); //這里為了方便查看修改后的內容。輸出到控制台看結果,此時是在內存中。並沒有保存到磁盤 下同 Console.WriteLine("-----------分割線1-----------"); //這是把第一個學生為mail 第二個學生為female foreach (var item in E5) { if (item.Attribute("Id").Value.Equals("1")) item.SetElementValue("sex", "male"); else item.SetElementValue("sex", "female"); } xDoc.Save(Console.Out); Console.WriteLine("-----------分割線2-----------"); //知道添加元素了。現在你添加一個學生也是如此簡單,班級來了個插班生。需添加第三個學生,多加一張課桌 var E6 = from item in xDoc.Descendants("Root") //找到根節點(班級)下所有的(學生)的元素 select item; //先拼好要添加的元素 var content = new XElement("Student", new XAttribute("Id", "3"), new XElement("name", "Jack"), new XElement("age", "22"), new XElement("sex", "gay") ); E6.ToList().ForEach(it => it.LastNode.AddAfterSelf(content)); //在最后一個(學生)節點后添加新(座位)元素 xDoc.Save(Console.Out); Console.WriteLine("-----------分割線3-----------"); //當發現學生Id=1的學生姓名不能是英文。需修改成中文 var E7 = from item in xDoc.Descendants("Student") where item.Attribute("Id").Value.Equals("1") select item; //找到name元素,修改value。同理。修改age一樣。。擴展:SetAttributeValue(name,value)添加屬性 E7.ToList().ForEach(it => it.Element("name").SetValue("湯姆")); xDoc.Save(Console.Out); Console.WriteLine("-----------分割線4-----------"); //當湯姆退學。需刪除元素(課桌) var E18 = from item in xDoc.Descendants("Student") where item.Element("name").Value.Equals("湯姆") //找到湯姆這個學生 select item; //刪除滿足條件的節點(同學),最后只剩下id=2和id=3的節點(學生) 以下三句效果相同 E18.Remove(); //E8.ToList().ForEach(it => it.Element("name").Parent.Remove()); //E8.ToList().ForEach(it => it.Element("age").Parent.Remove()); xDoc.Save(Console.Out); //記住:1、一個xml文檔(XDocument)只能有一個跟節點(Root),文檔中不能有相同的元素名(XElement),如果你添加相同的XElement。會覆蓋之前的value //xDoc.Save("Student.xml"); //保存修改后內容:這里是把xml加載到內存。在內存中修改后再保存到磁盤的。這里保存名不一定是 Student.xml 名字可以隨便取。跟之前的Student.xml已經沒有任何關系。 }
繼續看圖:因為圖片過大,所以圖片是分開截圖。

/// <summary> /// 序列化與反序列化幫助類--XMLHelper /// </summary> public class XmlHelper { /// <summary> /// serializer /// </summary> /// <typeparam name="T"></typeparam> /// <param name="obj">要序列化的實例</param> public static void serializeToXml<T>(T obj) { XmlSerializer serialize = new XmlSerializer(typeof(T)); using (XmlTextWriter xtw = new XmlTextWriter("Info.xml", Encoding.Default)) serialize.Serialize(xtw, obj); } /// <summary> /// Deserialize /// </summary> /// <typeparam name="T">泛型-反序列化后的類型</typeparam> /// <param name="data">反序列化的xml文檔</param> /// <returns></returns> public static T DeserializerXml<T>(string data) { XmlSerializer Deserializer = new XmlSerializer(typeof(T)); using (XmlTextReader xtr = new XmlTextReader(data)) return (T)Deserializer.Deserialize(xtr); } }
編寫測試類 即我所說的實體類和集合類
/// <summary> /// 實體類序列化 /// </summary> [Serializable] [XmlRoot("Root")] //這表明序列化xml文檔時。自定義節點名 public class Person { //[XmlIgnore] //此字段不序列化 public string name { get; set; } public int age { get; set; } } /// <summary> /// 集合類序列化 /// </summary> public class Persons { public List<Person> data { get; set; } }
Main函數測試
static void Main(string[] args) { Person ps = new Person() { name = "李四", age = 20 }; #region 實體類的序列化和反序列化 XmlHelper.serializeToXml(ps); Person p = XmlHelper.DeserializerXml<Person>("Info.xml"); Console.WriteLine("實體類反序列化結果:"); Console.WriteLine("姓名:" + p.name + "年齡:" + p.age); #endregion Console.WriteLine("---------分割線-------"); #region 集合類的序列化和反序列化 Persons pos = new Persons() { data = new List<Person> { ps } }; //pos.data = new List<Person>() { ps }; XmlHelper.serializeToXml(pos); Persons po = XmlHelper.DeserializerXml<Persons>("Info.xml"); Console.WriteLine("集合類反序列化結果:"); po.data.ForEach(item => Console.WriteLine("姓名:" + item.name + "年齡:" + item.age)); #endregion }
最后序列化生成Info.xml文檔,這里是實體類的序列化的xml,可以看到我自定義的根節點名字 Root
<?xml version="1.0" encoding="gb2312" ?>
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <name>李四</name> <age>20</age> </Root>
反序列化數據:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Xml.Linq; 6 7 namespace Linq_to_XML 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 //createXML(); 14 //ReadXML(); 15 EditXML(); 16 } 17 18 /// <summary> 19 /// linq to xml--創建xml文檔 20 /// </summary> 21 public static void createXML() 22 { 23 var xDoc = new XDocument(new XElement("Root", 24 new XElement("Student", 25 new XAttribute("Id", 1), //添加屬性 26 new XElement("name", "Tom"), 27 new XElement("age", 18) 28 ), 29 new XElement("Student", 30 new XAttribute("Id", 2), //屬性 31 new XElement("name", "Jim"), 32 new XElement("age", 20) 33 ) 34 ) 35 ); 36 xDoc.Save(Console.Out); //為了方便,我直接輸出到控制台觀看結果 37 xDoc.Save("Student.xml"); //保存 38 } 39 40 /// <summary> 41 /// linq to xml--讀取xml文檔 42 /// </summary> 43 public static void ReadXML() 44 { 45 46 XDocument xDoc = XDocument.Load("Student.xml"); //加載xml文檔,(相對路勁) 47 48 /*這里用Descendants(xName)的好處是可以跨層次,跨節點,而不像Element 49 比如要找到所有的Student節點。 50 Element: xDoc.Element("Root").Elements() 這里必須是從根節點到子節點一級一級找。 51 Descendants:xDoc.Descendants("Student") 跨了 根節點 Root 直接在根節點下找 52 */ 53 var E1 = from item in xDoc.Descendants("Student") //找到所有Student元素 54 select item; 55 56 E1.ToList().ForEach(it => Console.WriteLine(it)); 57 58 Console.WriteLine(""); 59 Console.WriteLine("-----------分割線1-----------"); 60 61 //找到學生屬性Id=1的學生。顯示學生姓名和年齡 62 var E2 = from item in xDoc.Descendants("Student") 63 where item.Attribute("Id").Value == "1" 64 select new 65 { 66 name = item.Element("name").Value, 67 age = item.Element("age").Value 68 }; 69 E2.ToList().ForEach(it => Console.WriteLine(string.Format("姓名:{0},年齡:{1}", it.name, it.age))); 70 71 Console.WriteLine(""); 72 Console.WriteLine("-----------分割線2-----------"); 73 74 //如果學生Id=1有多個,而你只想顯示第一個。則用FirstOrDefault(),返回滿足條件的第一個元素 75 var E3 = (from item in xDoc.Descendants("Student") 76 where item.Attribute("Id").Value == "1" 77 select new 78 { 79 name = item.Element("name").Value, 80 age = item.Element("age").Value 81 }).FirstOrDefault(); 82 83 //因為此時返回的結果已不是集合,可直接輸出 84 Console.WriteLine("姓名為:" + E3.name + "年齡為:" + E3.age); 85 86 Console.WriteLine(""); 87 Console.WriteLine("-----------分割線3-----------"); 88 89 //顯示所有學生的姓名和年齡 90 var E4 = from item in xDoc.Descendants("Student") 91 select new 92 { 93 name = item.Element("name").Value, 94 age = item.Element("age").Value 95 }; 96 E4.ToList().ForEach(it => Console.WriteLine(string.Format("姓名:{0},年齡為:{1}", it.name, it.age))); 97 98 //以上僅僅是舉了些簡單的例子,實際中還得根據需要靈活運用。記住。xml是區分大小寫的。所以要注意屬性名和元素名的大小寫要一致 99 100 } 101 102 /// <summary> 103 /// linq to xml--編輯xml文檔 104 /// </summary> 105 public static void EditXML() 106 { 107 XDocument xDoc = XDocument.Load("Student.xml"); //加載xml文檔 108 109 //現在你發現學生的姓名和年齡不能滿足需求,需要添加一個性別信息 ,那就得添加一個元素<sex>male</sex> 110 var E5 = from item in xDoc.Descendants("Student") //找到所有(元素名為Student)學生節點 111 select item; 112 113 E5.ToList().ForEach(it => it.SetElementValue("sex", "male")); //當然。這是給所有的學生都添加性別為male 114 xDoc.Save(Console.Out); //這里為了方便查看修改后的內容。輸出到控制台看結果,此時是在內存中。並沒有保存到磁盤 下同 115 116 Console.WriteLine("-----------分割線1-----------"); 117 118 //這是把第一個學生為mail 第二個學生為female 119 foreach (var item in E5) 120 { 121 if (item.Attribute("Id").Value.Equals("1")) 122 item.SetElementValue("sex", "male"); 123 else 124 item.SetElementValue("sex", "female"); 125 } 126 xDoc.Save(Console.Out); 127 128 Console.WriteLine("-----------分割線2-----------"); 129 130 //知道添加元素了。現在你添加一個學生也是如此簡單,班級來了個插班生。需添加第三個學生,多加一張課桌 131 var E6 = from item in xDoc.Descendants("Root") //找到根節點(班級)下所有的(學生)的元素 132 select item; 133 134 //先拼好要添加的元素 135 var content = new XElement("Student", 136 new XAttribute("Id", "3"), 137 new XElement("name", "Jack"), 138 new XElement("age", "22"), 139 new XElement("sex", "gay") 140 ); 141 142 E6.ToList().ForEach(it => it.LastNode.AddAfterSelf(content)); //在最后一個(學生)節點后添加新(座位)元素 143 xDoc.Save(Console.Out); 144 145 Console.WriteLine("-----------分割線3-----------"); 146 147 //當發現學生Id=1的學生姓名不能是英文。需修改成中文 148 var E7 = from item in xDoc.Descendants("Student") 149 where item.Attribute("Id").Value.Equals("1") 150 select item; 151 152 //找到name元素,修改value。同理。修改age一樣。。擴展:SetAttributeValue(name,value)添加屬性 153 E7.ToList().ForEach(it => it.Element("name").SetValue("湯姆")); 154 xDoc.Save(Console.Out); 155 Console.WriteLine("-----------分割線4-----------"); 156 157 //當湯姆退學。需刪除元素(課桌) 158 var E18 = from item in xDoc.Descendants("Student") 159 where item.Element("name").Value.Equals("湯姆") //找到湯姆這個學生 160 select item; 161 162 //刪除滿足條件的節點(同學),最后只剩下id=2和id=3的節點(學生) 以下三句效果相同 163 E18.Remove(); 164 //E8.ToList().ForEach(it => it.Element("name").Parent.Remove()); 165 //E8.ToList().ForEach(it => it.Element("age").Parent.Remove()); 166 xDoc.Save(Console.Out); 167 168 //記住:1、一個xml文檔(XDocument)只能有一個跟節點(Root),文檔中不能有相同的元素名(XElement),如果你添加相同的XElement。會覆蓋之前的value 169 170 //xDoc.Save("Student.xml"); //保存修改后內容:這里是把xml加載到內存。在內存中修改后再保存到磁盤的。這里保存名不一定是 Student.xml 名字可以隨便取。跟之前的Student.xml已經沒有任何關系。 171 } 172 } 173 }
序列化和反序列化完整代碼:

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Xml.Serialization; 6 using System.IO; 7 using System.Xml; 8 9 namespace XMLSerialize 10 { 11 class Program 12 { 13 static void Main(string[] args) 14 { 15 Person ps = new Person() { name = "李四", age = 20 }; 16 17 #region 實體類的序列化和反序列化 18 XmlHelper.serializeToXml(ps); 19 Person p = XmlHelper.DeserializerXml<Person>("Info.xml"); 20 Console.WriteLine("實體類反序列化結果:"); 21 Console.WriteLine("姓名:" + p.name + "年齡:" + p.age); 22 #endregion 23 Console.WriteLine("---------分割線-------"); 24 #region 集合類的序列化和反序列化 25 Persons pos = new Persons() { data = new List<Person> { ps } }; 26 //pos.data = new List<Person>() { ps }; 27 XmlHelper.serializeToXml(pos); 28 Persons po = XmlHelper.DeserializerXml<Persons>("Info.xml"); 29 Console.WriteLine("集合類反序列化結果:"); 30 po.data.ForEach(item => Console.WriteLine("姓名:" + item.name + "年齡:" + item.age)); 31 #endregion 32 } 33 } 34 /// <summary> 35 /// 實體類序列化 36 /// </summary> 37 [Serializable] 38 [XmlRoot("Root")] //這表明序列化xml文檔時。自定義節點名 39 public class Person 40 { 41 //[XmlIgnore] //此字段不序列化 42 public string name { get; set; } 43 public int age { get; set; } 44 } 45 /// <summary> 46 /// 集合類序列化 47 /// </summary> 48 public class Persons 49 { 50 public List<Person> data { get; set; } 51 } 52 /// <summary> 53 /// 序列化與反序列化幫助類--XMLHelper 54 /// </summary> 55 public class XmlHelper 56 { 57 /// <summary> 58 /// serializer 59 /// </summary> 60 /// <typeparam name="T"></typeparam> 61 /// <param name="obj">要序列化的實例</param> 62 public static void serializeToXml<T>(T obj) 63 { 64 XmlSerializer serialize = new XmlSerializer(typeof(T)); 65 using (XmlTextWriter xtw = new XmlTextWriter("Info.xml", Encoding.Default)) 66 serialize.Serialize(xtw, obj); 67 } 68 /// <summary> 69 /// Deserialize 70 /// </summary> 71 /// <typeparam name="T">泛型-反序列化后的類型</typeparam> 72 /// <param name="data">反序列化的xml文檔</param> 73 /// <returns></returns> 74 public static T DeserializerXml<T>(string data) 75 { 76 XmlSerializer Deserializer = new XmlSerializer(typeof(T)); 77 using (XmlTextReader xtr = new XmlTextReader(data)) 78 return (T)Deserializer.Deserialize(xtr); 79 } 80 } 81 }
到這里就結束了。初出茅廬。還請多多指教,謝謝!!