http://www.cnblogs.com/mingmingruyuedlut/archive/2011/01/27/1946239.html
我的上一篇文章描述了用普通方法实现对xml文件的基本操作,感谢各位园友给我提的每一个建议,大家主要在说:用Linq去实现对xml的操作更加方便简洁,于是乎我就现学习了一下Linq to xml,由于是刚刚接触Linq,理解肯定不会很深,所以请各位园友不吝赐教,有建议尽管说,在此先谢过大家啦~
LINQ to XML 为创建 XML 元素提供了一种称为“函数构造”的有效方式。函数构造是指在单个语句中创建 XML 树的能力。
启用函数构造的 LINQ to XML 编程接口有几个重要功能:
XElement 构造函数可以对内容采用多种类型的参数。 例如,可以传递另一个 XElement 对象,该对象将成为一个子元素。 可以传递一个 XAttribute对象,该对象将成为该元素的一个属性。 也可以传递任何其他类型的对象,该对象将转换为字符串并成为该元素的文本内容。
XElement 函数采用类型为 Object 的 params 数组,因此可以向该构造函数传递任意数目的对象。 这使您可以创建具有复杂内容的元素。如果对象实
现 IEnumerable<T>,则枚举对象中的集合,并添加集合中的所有项。
如果集合包含 XElement 或 XAttribute 对象,则单独添加集合中的每一项。这一功能很重要,因为它允许您将 LINQ 查询的结果传递给构造函数。
本文的主要模块为:
① :生成xml文件
② :遍历xml文件的节点信息
③ :修改xml文件的节点信息
④ :向xml文件添加节点信息
⑤ :删除指定xml文件的节点信息
①:【生成xml文件】假设我们想生成这样的一个xml文件结构,如下所示:
用我的上篇文章也能够很容的实现,不过下面我要用Linq to xml的方式实现生成这个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 OperateXmlLinq
8 {
9 class Program
10 {
11 static void Main( string [] args)
12 {
13 // xml文件存储路径
14 string myXmlPath = " E:\\MyUsers.xml " ;
15 // 创建xml文件
16 GenerateXmlFile(myXmlPath);
17 }
18
19 private static void GenerateXmlFile( string xmlPath)
20 {
21 try
22 {
23 // 定义一个XDocument结构
24 XDocument myXDoc = new XDocument(
25 new XElement( " Users " ,
26 new XElement( " User " , new XAttribute( " ID " , " 111111 " ),
27 new XElement( " name " , " EricSun " ),
28 new XElement( " password " , " 123456 " ),
29 new XElement( " description " , " Hello I'm from Dalian " )
30 ),
31 new XElement( " User " , new XAttribute( " ID " , " 222222 " ),
32 new XElement( " name " , " Ray " ),
33 new XElement( " password " , " 654321 " ),
34 new XElement( " description " , " Hello I'm from Jilin " )
35 )
36 )
37 );
38 // 保存此结构(即:我们预期的xml文件)
39 myXDoc.Save(xmlPath);
40 }
41 catch (Exception ex)
42 {
43 Console.WriteLine(ex.ToString());
44 }
45 }
46 }
②:【遍历xml文件的节点信息】创造出了xml文件之后,我们就要知道如何获得xml文件的各个节点的信息,请看如下代码:
1 private static void GetXmlNodeInforOld( string xmlPath)
2 {
3 try
4 {
5 XDocument myXDoc = XDocument.Load(xmlPath);
6 XElement rootNode = myXDoc.Element( " Users " );
7 foreach (XElement node in rootNode.Elements( " User " ))
8 {
9 Console.WriteLine( " User ID = {0} " , node.Attribute( " ID " ).Value);
10
11 string name = node.Element( " name " ).Value;
12 string password = node.Element( " password " ).Value;
13 string description = node.Element( " description " ).Value;
14 Console.WriteLine( " name = {0} \npassword = {1} \ndescription = {2} " , name, password, description);
15 }
16 }
17 catch (Exception ex)
18 {
19 Console.WriteLine(ex.ToString());
20 }
21 }
22
23 private static void GetXmlNodeInformation( string xmlPath)
24 {
25 try
26 {
27 // 定义并从xml文件中加载节点(根节点)
28 XElement rootNode = XElement.Load(xmlPath);
29 // 查询语句: 获得根节点下name子节点(此时的子节点可以跨层次:孙节点、重孙节点......)
30 IEnumerable < XElement > targetNodes = from target in rootNode.Descendants( " name " )
31 select target;
32 foreach (XElement node in targetNodes)
33 {
34 Console.WriteLine( " name = {0} " , node.Value);
35 }
36
37 // 查询语句: 获取ID属性值等于"111111"并且函数子节点的所有User节点(并列条件用"&&"符号连接)
38 IEnumerable < XElement > myTargetNodes = from myTarget in rootNode.Descendants( " User " )
39 where myTarget.Attribute( " ID " ).Value.Equals( " 111111 " )
&& myTarget.HasElements
40 select myTarget;
41 foreach (XElement node in myTargetNodes)
42 {
43 Console.WriteLine( " name = {0} " , node.Element( " name " ).Value);
44 Console.WriteLine( " password = {0} " , node.Element( " password " ).Value);
45 Console.WriteLine( " description = {0} " , node.Element( " description " ).Value);
46 }
47 }
48 catch (Exception ex)
49 {
50 Console.WriteLine(ex.ToString());
51 }
52 }
上面用了两种方法去实现对xml文件节点信息的读取,第一种方法是那种比较老的模式:通过父节点获得它的子节点(一层一层的获得),然后获取目标节点的信息;第二中方法用到的是Linq to xml的查询模式,根据我们的需求获得符合条件的所有节点,然后对这些节点的信息进行读取。
接下来我们要简单的讲述一下Linq to xml的查询模式(语法一看便懂,这里就不过多阐述了),LINQ to XML 的一个最重要的性能优势(与 XmlDocument 相比)为:LINQ to XML 中的查询是静态编译的,而 XPath 查询则必须在运行时进行解释,此功能是 LINQ to XML 的内置功能。
在调试程序的时候我们发现,第二种方法的IEnumerable<XElement> targetNodes = from target in rootNode.Descendants("name") select target;的这句话执行完毕后,得到的targetNodes依然是null,直到遍历的时候才获得相应的对象信息,这种方式就做延迟执行,【延迟执行】:意味着表达式的计算延迟,直到真正需要它的实现值为止。 当必须操作大型数据集合,特别是在包含一系列链接的查询或操作的程序中操作时,延迟执行可以大大改善性能。在最佳情况下,延迟执行只允许对源集合的单个循环访问。
【注:查询条件写在where语句中,并列条件用"&&"符号连接,或条件用"||"符号连接】
③:【修改xml文件的节点信息】知道了如何查询xml文件的节点信息之后,对相应节点信息做相应的修改,就显得很容易了。请看如下代码:
1 private static void ModifyXmlNodeInforOld( string xmlPath)
2 {
3 try
4 {
5 XDocument myXDoc = XDocument.Load(xmlPath);
6 myXDoc.Element( " Users " ).Element( " User " ).Attribute( " ID " ).Value = " 777777 " ;
7 foreach (XElement node in myXDoc.Element( " Users " ).Elements( " User " ).Elements( " description " ))
8 {
9 node.SetValue( " Hello, I'm from China. " );
10 }
11 myXDoc.Save(xmlPath);
12 }
13 catch (Exception ex)
14 {
15 Console.WriteLine(ex.ToString());
16 }
17 }
18
19 private static void ModifyXmlNodeInformation( string xmlPath)
20 {
21 try
22 {
23 // 定义并从xml文件中加载节点(根节点)
24 XElement rootNode = XElement.Load(xmlPath);
25 // 查询语句: 获取ID属性值等于"222222"或者等于"777777"的所有User节点(或条件用"||"符号连接)
26 IEnumerable < XElement > targetNodes = from target in rootNode.Descendants( " User " )
27 where target.Attribute( " ID " ).Value == " 222222 "
|| target.Attribute( " ID " ).Value.Equals( " 777777 " )
28 select target;
29 // 遍历所获得的目标节点(集合)
30 foreach (XElement node in targetNodes)
31 {
32 // 将description节点的InnerText设置为"Hello, I'm from USA."
33 node.Element( " description " ).SetValue( " Hello, I'm from USA. " );
34 }
35 // 保存对xml的更改操作
36 rootNode.Save(xmlPath);
37 }
38 catch (Exception ex)
39 {
40 Console.WriteLine(ex.ToString());
41 }
42 }
这里也用了两种方法去获取相应节点信息的,具体过程请看代码就可以啦。
④:【向xml文件添加节点信息】下面的代码是向原有xml文件中添加一个节点
1 private static void AddXmlNodeInformation( string xmlPath)
2 {
3 try
4 {
5 // 定义并从xml文件中加载节点(根节点)
6 XElement rootNode = XElement.Load(xmlPath);
7 // 定义一个新节点
8 XElement newNode = new XElement( " User " , new XAttribute( " ID " , " 999999 " ),
9 new XElement( " name " , " Rose " ),
10 new XElement( " password " , " 456123 " ),
11 new XElement( " description " , " Hello, I'm from UK. " ));
12 // 将此新节点添加到根节点下
13 rootNode.Add(newNode);
14 // 保存对xml的更改操作
15 rootNode.Save(xmlPath);
16 }
17 catch (Exception ex)
18 {
19 Console.WriteLine(ex.ToString());
20 }
21 }
简单做一个总结:下面的方法将子内容添加到 XElement 或 XDocument 中:
方法 说明
Add 在 XContainer 的子内容的末尾添加内容。
AddFirst 在 XContainer 的子内容的开头添加内容。
下面的方法将内容添加为 XNode 的同级节点。 向其中添加同级内容的最常见的节点是 XElement,不过你也可以将有效的同级内容添加到其他类型的节点,
例如 XText 或 XComment。
方法 说明
AddAfterSelf 在 XNode 后面添加内容。
AddBeforeSelf 在 XNode 前面添加内容。
⑤:【删除指定xml文件的节点信息】如何将刚刚加入的那个节点删除掉呢?请看如下代码:
1 private static void DeleteXmlNodeInformation( string xmlPath)
2 {
3 try
4 {
5 // 定义并从xml文件中加载节点(根节点)
6 XElement rootNode = XElement.Load(xmlPath);
7 // 查询语句: 获取ID属性值等于"999999"的所有User节点
8 IEnumerable < XElement > targetNodes = from target in rootNode.Descendants( " User " )
9 where target.Attribute( " ID " ).Value.Equals( " 999999 " )
10 select target;
11
12 // 将获得的节点集合中的每一个节点依次从它相应的父节点中删除
13 targetNodes.Remove();
14 // 保存对xml的更改操作
15 rootNode.Save(xmlPath);
16 }
17 catch (Exception ex)
18 {
19 Console.WriteLine(ex.ToString());
20 }
21 }