【转】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"); //保存咯 //下面都是清除数据,释放资源
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 的完整代码 :
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Xml.Linq;
6
7 namespace Linq_to_XML
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 //createXML();
14 //ReadXML();
15 EditXML();
16 }
17
18 /// <summary>
19 /// linq to xml--创建xml文档
20 /// </summary>
21 public static void createXML()
22 {
23 var xDoc = new XDocument(new XElement("Root",
24 new XElement("Student",
25 new XAttribute("Id", 1), //添加属性
26 new XElement("name", "Tom"),
27 new XElement("age", 18)
28 ),
29 new XElement("Student",
30 new XAttribute("Id", 2), //属性
31 new XElement("name", "Jim"),
32 new XElement("age", 20)
33 )
34 )
35 );
36 xDoc.Save(Console.Out); //为了方便,我直接输出到控制台观看结果
37 xDoc.Save("Student.xml"); //保存
38 }
39
40 /// <summary>
41 /// linq to xml--读取xml文档
42 /// </summary>
43 public static void ReadXML()
44 {
45
46 XDocument xDoc = XDocument.Load("Student.xml"); //加载xml文档,(相对路劲)
47
48 /*这里用Descendants(xName)的好处是可以跨层次,跨节点,而不像Element
49 比如要找到所有的Student节点。
50 Element: xDoc.Element("Root").Elements() 这里必须是从根节点到子节点一级一级找。
51 Descendants:xDoc.Descendants("Student") 跨了 根节点 Root 直接在根节点下找
52 */
53 var E1 = from item in xDoc.Descendants("Student") //找到所有Student元素
54 select item;
55
56 E1.ToList().ForEach(it => Console.WriteLine(it));
57
58 Console.WriteLine("");
59 Console.WriteLine("-----------分割线1-----------");
60
61 //找到学生属性Id=1的学生。显示学生姓名和年龄
62 var E2 = from item in xDoc.Descendants("Student")
63 where item.Attribute("Id").Value == "1"
64 select new
65 {
66 name = item.Element("name").Value,
67 age = item.Element("age").Value
68 };
69 E2.ToList().ForEach(it => Console.WriteLine(string.Format("姓名:{0},年龄:{1}", it.name, it.age)));
70
71 Console.WriteLine("");
72 Console.WriteLine("-----------分割线2-----------");
73
74 //如果学生Id=1有多个,而你只想显示第一个。则用FirstOrDefault(),返回满足条件的第一个元素
75 var E3 = (from item in xDoc.Descendants("Student")
76 where item.Attribute("Id").Value == "1"
77 select new
78 {
79 name = item.Element("name").Value,
80 age = item.Element("age").Value
81 }).FirstOrDefault();
82
83 //因为此时返回的结果已不是集合,可直接输出
84 Console.WriteLine("姓名为:" + E3.name + "年龄为:" + E3.age);
85
86 Console.WriteLine("");
87 Console.WriteLine("-----------分割线3-----------");
88
89 //显示所有学生的姓名和年龄
90 var E4 = from item in xDoc.Descendants("Student")
91 select new
92 {
93 name = item.Element("name").Value,
94 age = item.Element("age").Value
95 };
96 E4.ToList().ForEach(it => Console.WriteLine(string.Format("姓名:{0},年龄为:{1}", it.name, it.age)));
97
98 //以上仅仅是举了些简单的例子,实际中还得根据需要灵活运用。记住。xml是区分大小写的。所以要注意属性名和元素名的大小写要一致
99
100 }
101
102 /// <summary>
103 /// linq to xml--编辑xml文档
104 /// </summary>
105 public static void EditXML()
106 {
107 XDocument xDoc = XDocument.Load("Student.xml"); //加载xml文档
108
109 //现在你发现学生的姓名和年龄不能满足需求,需要添加一个性别信息 ,那就得添加一个元素<sex>male</sex>
110 var E5 = from item in xDoc.Descendants("Student") //找到所有(元素名为Student)学生节点
111 select item;
112
113 E5.ToList().ForEach(it => it.SetElementValue("sex", "male")); //当然。这是给所有的学生都添加性别为male
114 xDoc.Save(Console.Out); //这里为了方便查看修改后的内容。输出到控制台看结果,此时是在内存中。并没有保存到磁盘 下同
115
116 Console.WriteLine("-----------分割线1-----------");
117
118 //这是把第一个学生为mail 第二个学生为female
119 foreach (var item in E5)
120 {
121 if (item.Attribute("Id").Value.Equals("1"))
122 item.SetElementValue("sex", "male");
123 else
124 item.SetElementValue("sex", "female");
125 }
126 xDoc.Save(Console.Out);
127
128 Console.WriteLine("-----------分割线2-----------");
129
130 //知道添加元素了。现在你添加一个学生也是如此简单,班级来了个插班生。需添加第三个学生,多加一张课桌
131 var E6 = from item in xDoc.Descendants("Root") //找到根节点(班级)下所有的(学生)的元素
132 select item;
133
134 //先拼好要添加的元素
135 var content = new XElement("Student",
136 new XAttribute("Id", "3"),
137 new XElement("name", "Jack"),
138 new XElement("age", "22"),
139 new XElement("sex", "gay")
140 );
141
142 E6.ToList().ForEach(it => it.LastNode.AddAfterSelf(content)); //在最后一个(学生)节点后添加新(座位)元素
143 xDoc.Save(Console.Out);
144
145 Console.WriteLine("-----------分割线3-----------");
146
147 //当发现学生Id=1的学生姓名不能是英文。需修改成中文
148 var E7 = from item in xDoc.Descendants("Student")
149 where item.Attribute("Id").Value.Equals("1")
150 select item;
151
152 //找到name元素,修改value。同理。修改age一样。。扩展:SetAttributeValue(name,value)添加属性
153 E7.ToList().ForEach(it => it.Element("name").SetValue("汤姆"));
154 xDoc.Save(Console.Out);
155 Console.WriteLine("-----------分割线4-----------");
156
157 //当汤姆退学。需删除元素(课桌)
158 var E18 = from item in xDoc.Descendants("Student")
159 where item.Element("name").Value.Equals("汤姆") //找到汤姆这个学生
160 select item;
161
162 //删除满足条件的节点(同学),最后只剩下id=2和id=3的节点(学生) 以下三句效果相同
163 E18.Remove();
164 //E8.ToList().ForEach(it => it.Element("name").Parent.Remove());
165 //E8.ToList().ForEach(it => it.Element("age").Parent.Remove());
166 xDoc.Save(Console.Out);
167
168 //记住:1、一个xml文档(XDocument)只能有一个跟节点(Root),文档中不能有相同的元素名(XElement),如果你添加相同的XElement。会覆盖之前的value
169
170 //xDoc.Save("Student.xml"); //保存修改后内容:这里是把xml加载到内存。在内存中修改后再保存到磁盘的。这里保存名不一定是 Student.xml 名字可以随便取。跟之前的Student.xml已经没有任何关系。
171 }
172 }
173 }
序列化和反序列化完整代码:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Xml.Serialization;
6 using System.IO;
7 using System.Xml;
8
9 namespace XMLSerialize
10 {
11 class Program
12 {
13 static void Main(string[] args)
14 {
15 Person ps = new Person() { name = "李四", age = 20 };
16
17 #region 实体类的序列化和反序列化
18 XmlHelper.serializeToXml(ps);
19 Person p = XmlHelper.DeserializerXml<Person>("Info.xml");
20 Console.WriteLine("实体类反序列化结果:");
21 Console.WriteLine("姓名:" + p.name + "年龄:" + p.age);
22 #endregion
23 Console.WriteLine("---------分割线-------");
24 #region 集合类的序列化和反序列化
25 Persons pos = new Persons() { data = new List<Person> { ps } };
26 //pos.data = new List<Person>() { ps };
27 XmlHelper.serializeToXml(pos);
28 Persons po = XmlHelper.DeserializerXml<Persons>("Info.xml");
29 Console.WriteLine("集合类反序列化结果:");
30 po.data.ForEach(item => Console.WriteLine("姓名:" + item.name + "年龄:" + item.age));
31 #endregion
32 }
33 }
34 /// <summary>
35 /// 实体类序列化
36 /// </summary>
37 [Serializable]
38 [XmlRoot("Root")] //这表明序列化xml文档时。自定义节点名
39 public class Person
40 {
41 //[XmlIgnore] //此字段不序列化
42 public string name { get; set; }
43 public int age { get; set; }
44 }
45 /// <summary>
46 /// 集合类序列化
47 /// </summary>
48 public class Persons
49 {
50 public List<Person> data { get; set; }
51 }
52 /// <summary>
53 /// 序列化与反序列化帮助类--XMLHelper
54 /// </summary>
55 public class XmlHelper
56 {
57 /// <summary>
58 /// serializer
59 /// </summary>
60 /// <typeparam name="T"></typeparam>
61 /// <param name="obj">要序列化的实例</param>
62 public static void serializeToXml<T>(T obj)
63 {
64 XmlSerializer serialize = new XmlSerializer(typeof(T));
65 using (XmlTextWriter xtw = new XmlTextWriter("Info.xml", Encoding.Default))
66 serialize.Serialize(xtw, obj);
67 }
68 /// <summary>
69 /// Deserialize
70 /// </summary>
71 /// <typeparam name="T">泛型-反序列化后的类型</typeparam>
72 /// <param name="data">反序列化的xml文档</param>
73 /// <returns></returns>
74 public static T DeserializerXml<T>(string data)
75 {
76 XmlSerializer Deserializer = new XmlSerializer(typeof(T));
77 using (XmlTextReader xtr = new XmlTextReader(data))
78 return (T)Deserializer.Deserialize(xtr);
79 }
80 }
81 }
到这里就结束了。初出茅庐。还请多多指教,谢谢!!
参考资料:
1.https://blog.csdn.net/dyllove98/article/details/8708323
【转】XDocument简单入门的更多相关文章
- XDocument简单入门
[+] 1.什么是XML? 2.XDocument和XmlDocument的区别? 3.XDocument 4.XmlDocument 5.LINQ to XML 6.XML序列化与反序列化 因为 ...
- 用IntelliJ IDEA创建Gradle项目简单入门
Gradle和Maven一样,是Java用得最多的构建工具之一,在Maven之前,解决jar包引用的问题真是令人抓狂,有了Maven后日子就好过起来了,而现在又有了Gradle,Maven有的功能它都 ...
- [原创]MYSQL的简单入门
MYSQL简单入门: 查询库名称:show databases; information_schema mysql test 2:创建库 create database 库名 DEFAULT CHAR ...
- Okio 1.9简单入门
Okio 1.9简单入门 Okio库是由square公司开发的,补充了java.io和java.nio的不足,更加方便,快速的访问.存储和处理你的数据.而OkHttp的底层也使用该库作为支持. 该库极 ...
- emacs最简单入门,只要10分钟
macs最简单入门,只要10分钟 windwiny @2013 无聊的时候又看到鼓吹emacs的文章,以前也有几次想尝试,结果都是玩不到10分钟就退出删除了. 这次硬着头皮,打开几篇文章都看完 ...
- 【java开发系列】—— spring简单入门示例
1 JDK安装 2 Struts2简单入门示例 前言 作为入门级的记录帖,没有过多的技术含量,简单的搭建配置框架而已.这次讲到spring,这个应该是SSH中的重量级框架,它主要包含两个内容:控制反转 ...
- Docker 简单入门
Docker 简单入门 http://blog.csdn.net/samxx8/article/details/38946737
- Springmvc整合tiles框架简单入门示例(maven)
Springmvc整合tiles框架简单入门示例(maven) 本教程基于Springmvc,spring mvc和maven怎么弄就不具体说了,这边就只简单说tiles框架的整合. 先贴上源码(免积 ...
- git简单入门
git简单入门 标签(空格分隔): git git是作为程序员必备的技能.在这里就不去介绍版本控制和git产生的历史了. 首先看看常用的git命令: git init git add git comm ...
随机推荐
- Ajax 如何执行 Response.Redirect
Ajax 直接对服务端的Response.Redirect是不感冒的, 另觅途径, 具体可行办法如下: Web Service 服务端: public WXService() { if (!IsVal ...
- Linux系统忘记管理员密码(CentOS、RHEL、Ubuntu)
Linux系统忘记管理员密码(CentOS.RHEL.Ubuntu) 系统使用过程中,尤其是生产环境中.万一忘记管理员密码,该怎么办?是不是很绝望? 1.RHEL 7.0 重启主机进入引导界面键入e键 ...
- numpy.reshape()
数组新的shape属性应该要与原来的配套,如果等于-1的话,那么Numpy会根据剩下的维度计算出数组的另外一个shape属性值.
- python index()函数
python内置index()函数 index() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,该方法与 python ...
- swoft| 源码解读系列一: 好难! swoft demo 都跑不起来怎么破? docker 了解一下呗~
title: swoft| 源码解读系列一: 好难! swoft demo 都跑不起来怎么破? docker 了解一下呗~description: 阅读 sowft 框架源码, swoft 第一步, ...
- Windows 操作系统如何使程序开机自启
Windows 操作系统如何开机自启 一.前言: 作为一只运维开发,很多时候需要将自己的小工具做开机自启.在 Linux 的世界里,如果你希望一个程序可以开机自启,那么可以在/etc/rc.d/rc. ...
- Squid代理服务器(二)——配置Squid服务器
一.传统代理 (一)需求分析 局域网内,客户机访问自家的Web服务器,通过Squid代理服务器访问Web服务器,再由Squid反馈给客户机;在Squid主机上,构建Squid为客户机访问网站提供代理服 ...
- jquery选项卡效果
效果图: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...
- 使用FFmpeg进行视频抽取音频,之后进行语音识别转为文字
1.首先需要下载FFmpeg: 2.Gradle依赖 def void forceVersion(details, group, version) { if (details.requested.gr ...
- [摸鱼]cdq分治 && 学习笔记
待我玩会游戏整理下思绪(分明是想摸鱼 cdq分治是一种用于降维和处理对不同子区间有贡献的离线分治算法 对于常见的操作查询题目而言,时间总是有序的,而cdq分治则是耗费\(O(logq)\)的代价使动态 ...