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 所有的特性都必須在值的周圍加上雙引號。 
   具體瞭解,查看百科:   http://baike.baidu.com/view/159832.htm?fromId=63#1 
   
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");  //保存咯

            //下面都是清除數據,釋放資源
            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 }

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

發佈了5 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章