XDocument和XmlDocument的区别及用法

因为这几天用到了不熟悉的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 }

到这里就结束了。初出茅庐。还请多多指教,谢谢!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/75681.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从竞速到巡检:不同无人机如何匹配最佳PCB方案?

随着无人机技术的快速发展&#xff0c;高性能PCB&#xff08;印刷电路板&#xff09;成为无人机制造商的核心需求之一。无论是消费级无人机还是工业级应用&#xff0c;PCB的质量直接影响飞行控制、信号传输和整机稳定性。那么&#xff0c;无人机制造商在选型高端PCB时&#xff…

高支模自动化监测解决方案

1.行业现状 高大模板支撑系统在浇筑施工过程中&#xff0c;诸多重大安全风险点进行实时自动化安全监测的解决方案主要监测由于顶杆失稳、扣件失效、承压过大等引起的支撑轴力、模板沉降、相对位移、支撑体系倾斜等参数变化。系统采用无线自动组网、高频连续采样&#xff0c;实时…

python【标准库】multiprocessing

文章目录 介绍多进程Process 创建子进程共享内存数据多进程通信Pool创建子进程多进程案例多进程注意事项介绍 python3.10.17版本multiprocessing 是一个多进程标准模块,使用类似于threading模块的API创建子进程,充分利用多核CPU来并行处理任务。提供本地、远程的并发,高效避…

UniApp基于xe-upload实现文件上传组件

xe-upload地址&#xff1a;文件选择、文件上传组件&#xff08;图片&#xff0c;视频&#xff0c;文件等&#xff09; - DCloud 插件市场 致敬开发者&#xff01;&#xff01;&#xff01; 感觉好用的话&#xff0c;给xe-upload的作者一个好评 背景&#xff1a;开发中经常会有…

STM32 HAL库之GPIO示例代码

LED灯不断闪烁 GPIO初始化&#xff0c;main文件中的 MX_GPIO_Init(); 也就是在 gpio.c文件中 void MX_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStruct {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOE_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOA_C…

二维数点 系列 题解

1.AT_dp_w Intervals 我的博客 2.CF377D Developing Games 我的博客 这两道题是比较经典的线段树区间 trick&#xff0c;希望自己可以在以后的比赛中手切。 3.洛谷 P10814 离线二维数点 题意 给你一个长为 n n n 的序列 a a a&#xff0c;有 m m m 次询问&#xff0c…

vulkanscenegraph显示倾斜模型(5.9)-vsg中vulkan资源的编译

前言 上一章深入剖析了GPU资源内存及其管理&#xff0c;vsg中为了提高设备内存的利用率&#xff0c;同时减少内存(GPU)碎片&#xff0c;采用GPU资源内存池机制(vsg::MemoryBufferPools)管理逻辑缓存(VkBuffer)与物理内存(VkDeviceMemory)。本章将深入vsg中vulkan资源的编译(包含…

探秘 Python 网络编程:构建简单聊天服务器

在计算机网络的世界里&#xff0c;网络编程是实现不同设备之间通信的关键技术。Python 凭借其简洁的语法和强大的库支持&#xff0c;在网络编程领域有着广泛的应用。无论是构建简单的聊天服务器&#xff0c;还是开发复杂的网络应用&#xff0c;Python 都能轻松胜任。 1 理论基础…

Go语言Slice切片底层

Go语言&#xff08;Golang&#xff09;中切片&#xff08;slice&#xff09;的相关知识、包括切片与数组的关系、底层结构、扩容机制、以及切片在函数传递、截取、增删元素、拷贝等操作中的特性。并给出了相关代码示例和一道面试题。关键要点包括&#xff1a; 数组特性&#xf…

vue3 ts 自定义指令 app.directive

在 Vue 3 中&#xff0c;app.directive 是一个全局 API&#xff0c;用于注册或获取全局自定义指令。以下是关于 app.directive 的详细说明和使用方法 app.directive 用于定义全局指令&#xff0c;这些指令可以用于直接操作 DOM 元素。自定义指令在 Vue 3 中非常强大&#xff0…

基于python的机器学习(五)—— 聚类(二)

一、k-medoids聚类算法 k-medoids是一种聚类算法&#xff0c;它是基于k-means聚类算法的一种改进。k-medoids算法也是一种迭代算法&#xff0c;但是它将中心点限定为数据集中的实际样本点&#xff0c;而不是任意的点。 具体来说&#xff0c;k-medoids算法从数据集中选择k个初…

解释:指数加权移动平均(EWMA)

指数加权移动平均&#xff08;EWMA, Exponential Weighted Moving Average&#xff09; 是一种常用于时间序列平滑、异常检测、过程控制等领域的统计方法。相比普通移动平均&#xff0c;它对最近的数据赋予更高权重&#xff0c;对旧数据逐渐“淡化”。 ✅ 一、通俗理解 想象你…

Spring Boot 项目基于责任链模式实现复杂接口的解耦和动态编排!

全文目录&#xff1a; 开篇语前言一、责任链模式概述责任链模式的组成部分&#xff1a; 二、责任链模式的核心优势三、使用责任链模式解耦复杂接口1. 定义 Handler 接口2. 实现具体的 Handler3. 创建订单对象4. 在 Spring Boot 中使用责任链模式5. 配置责任链6. 客户端调用 四、…

COMSOL仿真遇到的两个小问题

最近跑热仿真的时候跑出了两个问题&#xff0c;上网查发现也没什么解决方式&#xff0c;最后自己误打误撞的摸索着解决了&#xff0c;在这里分享一下。 问题一 我当时一准备跑仿真就弹出了这个东西&#xff0c;但在此之前从未遇到 然后我试着在它说的路径中建立recoveries文件…

如何在英文学术写作中正确使用标点符号?

标点符号看似微不足道&#xff0c;但它们是书面语言的无名英雄。就像熟练的指挥家指挥管弦乐队一样&#xff0c;标点符号可以确保您的写作流畅、传达正确的含义并引起读者的共鸣。正如放错位置的音符会在音乐中造成不和谐一样&#xff0c;放错位置的逗号或缺少分号也会使您的写…

【深度学习与大模型基础】第10章-期望、方差和协方差

一、期望 ——————————————————————————————————————————— 1. 期望是什么&#xff1f; 期望&#xff08;Expectation&#xff09;可以理解为“长期的平均值”。比如&#xff1a; 掷骰子&#xff1a;一个6面骰子的点数是1~6&#x…

JAVA虚拟机(JVM)学习

入门 什么是JVM JVM&#xff1a;Java Virtual Machine&#xff0c;Java虚拟机。 JVM是JRE(Java Runtime Environment)的一部分&#xff0c;安装了JRE就相当于安装了JVM&#xff0c;就可以运行Java程序了。JVM的作用&#xff1a;加载并执行Java字节码&#xff08;.class&#…

【数据结构与算法】——堆(补充)

前言 上一篇文章讲解了堆的概念和堆排序&#xff0c;本文是对堆的内容补充 主要包括&#xff1a;堆排序的时间复杂度、TOP 这里写目录标题 前言正文堆排序的时间复杂度TOP-K 正文 堆排序的时间复杂度 前文提到&#xff0c;利用堆的思想完成的堆排序的代码如下&#xff08;包…

什么是柜台债

柜台债&#xff08;柜台债券业务&#xff09;是指通过银行等金融机构的营业网点或电子渠道&#xff0c;为投资者提供债券买卖、托管、结算等服务的业务模式。它允许个人、企业及机构投资者直接参与银行间债券市场的交易&#xff0c;打破了以往仅限机构参与的壁垒。以下是综合多…

【Android读书笔记】读书笔记记录

文章目录 一. Android开发艺术探索1. Activity的生命周期和启动模式1.1 生命周期全面分析 一. Android开发艺术探索 1. Activity的生命周期和启动模式 1.1 生命周期全面分析 onPause和onStop onPause后会快速调用onStop&#xff0c;极端条件下直接调用onResume 当用户打开新…