XDocument簡單入門


1、什么是XML?
2、XDocument和XmlDocument的區別?
3、XDocument
4、XmlDocument
5、LINQ to XML
6、XML序列化與反序列化

因為這幾天用到了不熟悉的xml統計數據,啃了網上的資料解決了問題,故總結下xml知識。

什么是XML?
    XML(extensible markup language)可擴展標記語言,用於標記電子文件使其具有結構性的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。
  特性:
    XML要求所有的標記必須成對出現;HTML標記不區分大小寫,XML則大小敏感,即區分大小寫。
  語法:
  1 任何的起始標簽都必須有一個結束標簽。
  2 可以采用另一種簡化語法,可以在一個標簽中同時表示起始和結束標簽。這種語法是在大於符號之前緊跟一個斜線(/),例如<tag/ >。XML解析器會將其翻譯成<tag></tag>。
   3 標簽必須按合適的順序進行嵌套,所以結束標簽必須按鏡像順序匹配起始標簽,例如 this is a samplestring。這好比是將起始和結束標簽看作是數學中的左右括號:在沒有關閉所有的內部括號之前,是不能關閉外面的括號的。
   4 所有的特性都必須有值。可以是空值
   5 所有的特性都必須在值的周圍加上雙引號。
 
XDocument和XmlDocument的區別
  XDocument和XmlDocument都可以用來操作XML文檔,XDocument是.net 3.5為Linq to XML准備的輕量級Document對象,在功能上他和XmlDocument差不多,但是Linq to XML只能配合XDocument使用
 
XDocument
先看一段簡單的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方式:

  我們先看一段XDocument代碼(這里推薦幾種常見的方法)這是后面要介紹的linq to xml 方式
  以下三個列子都是創建一個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>

 

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>

 

 
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")); //當然。這是給所有的學生都添加性別為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已經沒有任何關系。
        }

 

繼續看圖:因為圖片過大,所以圖片是分開截圖。

 
 
 
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);
            #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>

 

反序列化數據:

 

 

 最后附上完整代碼
linq to xml 的完整代碼 :
View Code
  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 }

序列化和反序列化完整代碼:

View Code
 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 }

到這里就結束了。初出茅廬。還請多多指教,謝謝!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM