因為這幾天用到了不熟悉的xml統計數據,啃了網上的資料解決了問題,故總結下xml知識。
- 1.什么是XML?
- 2.XDocument和XmlDocument的區別
- 3.XDocument
- 示例1
- 示例2:
- 示例3:
- 4.XmlDocument
- 5.LINQ to XML
- 6.XML序列化(Serialize)與反序列化(Deserialize)
1.什么是XML?
XML(extensible markup language)可擴展標記語言,用于標記電子文件使其具有結構性的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。
特性:
XML要求所有的標記必須成對出現;HTML標記不區分大小寫,XML則大小敏感,即區分大小寫。
語法:
1 任何的起始標簽都必須有一個結束標簽。
2 可以采用另一種簡化語法,可以在一個標簽中同時表示起始和結束標簽。這種語法是在大于符號之前緊跟一個斜線(/),例如<tag/ >。XML解析器會將其翻譯成。
3 標簽必須按合適的順序進行嵌套,所以結束標簽必須按鏡像順序匹配起始標簽,例如 this is a samplestring。這好比是將起始和結束標簽看作是數學中的左右括號:在沒有關閉所有的內部括號之前,是不能關閉外面的括號的。
4 所有的特性都必須有值。可以是空值
5 所有的特性都必須在值的周圍加上雙引號。
具體了解,查看百科: 什么是可擴展標記語言
2.XDocument和XmlDocument的區別
XDocument和XmlDocument都可以用來操作XML文檔,XDocument是.net 3.5為Linq to XML準備的輕量級Document對象,在功能上他和XmlDocument差不多,但是Linq to XML只能配合XDocument使用。
3.XDocument
先看一段簡單的xml代碼,一步一步來揭開xml的面紗
// 創建一個xml文檔 XDocument所屬命名空間:using System.Xml.Linq;XDocument xDoc = new XDocument();// 添加根節點XElement xRoot = new XElement("Root");// 添加節點使用AddxDoc.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方式:
我們先看一段XDocument代碼(這里推薦幾種常見的方法)這是后面要介紹的linq to xml 方式
以下三個列子都是創建一個xml文檔。當然。你可以根據自己的需要選擇更好的方式
示例1
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文檔
示例2:
也許你也見過這樣的寫法,效果是相同的(與上面樹結構不同)
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文檔}
運行結果:
示例3:
當然你也可以用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"); //保存咯//下面都是清除數據,釋放資源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變量是空怎么會有子節點呢?
好。我們在節點“經濟艙”后添加一個兄弟節點“詳細信息”
只要改變查找方式: XElement i = xDoc.Root.Element(“FlyInfo”).Element(“Seat”); //父節點(FlyInfo)下的子節點(Seat)。
其他代碼不變:
XElement i = xDoc.Root.Element("FlyInfo").Element("Seat"); //父節點(FlyInfo)下的子節點(Seat)//這里給父親添加個兒子(在末尾添加的) 在之前添加用:AddBeforeSelfi.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>
4.XmlDocument
接下來我們我們看看XmlDocument,它出現在XDocument之前,你可以看看有哪些異同。
//創建一個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>
5.LINQ to XML
LINQ to XML是用來操作XDocument類,利用LINQ to XML來對xml進行CRUD 增加(Create)、查詢(Retrieve)(重新得到數據)、更新(Update)和刪除(Delete)代碼簡化了許多
在上面你已經看到用linq to xml創建xml文檔了。這里為了更明確。用linq to xml來進行完整的增刪改查,所以先創建一個xml文檔
/// <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文檔就順理成章的生成了
接下來看讀取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是區分大小寫的。所以要注意屬性名和元素名的大小寫要一致}
看結果圖:
最后看編輯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")); //當然。這是給所有的學生都添加性別為malexDoc.Save(Console.Out); //這里為了方便查看修改后的內容。輸出到控制臺看結果,此時是在內存中。并沒有保存到磁盤 下同Console.WriteLine("-----------分割線1-----------");//這是把第一個學生為mail 第二個學生為femaleforeach (var item in E5){if (item.Attribute("Id").Value.Equals("1"))item.SetElementValue("sex", "male");elseitem.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已經沒有任何關系。}
繼續看圖:因為圖片過大,所以圖片是分開截圖。
6.XML序列化(Serialize)與反序列化(Deserialize)
我這里分別對實體類(非集合類我這樣稱呼),和集合類進行序列化和反序列化
先提供一個泛型XMLHelper
/// <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);#endregionConsole.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>
反序列化數據:
最后附上完整代碼
linq to xml 的完整代碼
View Code1 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_XML8 {9 class Program10 {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)的好處是可以跨層次,跨節點,而不像Element49 比如要找到所有的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 new65 {66 name = item.Element("name").Value,67 age = item.Element("age").Value68 };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 new78 {79 name = item.Element("name").Value,80 age = item.Element("age").Value81 }).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 new92 {93 name = item.Element("name").Value,94 age = item.Element("age").Value95 };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 }
序列化和反序列化完整代碼:
View Code1 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 }
到這里就結束了。初出茅廬。還請多多指教,謝謝!!