LINQ学习之旅——最后一站"LTX"之XML基本操作(下)

  上一节,讲解了LINQ TO XML基本操作中的创建,今天继续讲解LINQ TO XML操作的下半部分:输入输出、遍历、查询及修改。

  1.在LINQ TO  XML中的输出和输出操作主要由Save和Load两个方法来完成的。其中XDocumnet和XElement类提供了Save方法来把xml数据输出到指定文件、TextWriter对象以及XmlWriter对象中,下面是XElement类中常用的几个Save方法原型:

  public void Save(string fileName);

  public void Save(TextWriter textWriter);

  public void Save(XmlWriter writer);

  public void Save(string fileName, SaveOptions options);

  public void Save(TextWriter textWriter, SaveOptions options);

第一个方法原型就不再多说了,前几节在编写创建xml文档的示例中多次用到。第二个原型方法的参数是一个TextWriter对象,类TextWriter用来编写一个有序字符系列的编辑器。也是StreamWriter和StringWriter的抽象基类,将字符分别写入流和字符串;第三个方法原型的参数为一个XmlWriter对象,该类提供了只进、只读、不缓存的xml流生成方法。最后两种方法比起前三种就是多了一个类型为SaveOptions的参数,它用于设置xml输出的格式,是一个枚举类型,包含None、DisableFormatting和OmitDuplicateNamespaces枚举值,None表示序列化时对 XML 进行格式设置(缩进);DisableFormatting表示序列化时保留所有无关紧要的空白;OmitDuplicateNamespaces表示序列化时移除重复的命名空间声明。下面用示例来进一步说明Save使用:

i.xml输出:

 1         static void Main(string[] args)
2 {
3 XElement Sprites = new XElement("Sprites",
4 new XElement("Sprite",
5 new XElement("Profession", "法师"),
6 new XElement("Weapon", "魔杖")),
7 new XElement("Sprite",
8 new XAttribute("Profession", "战士"),
9 new XAttribute("Weapon", "屠龙刀")),
10 new XElement("Sprite",
11 new XElement("Profession","道士"),
12 new XElement("Weapon", "倚天剑")));
13
14 //保存到指定文件
15 Sprites.Save(@"d:\\Sprites.xml");
16
17 //保存到TextWriter
18 StringWriter sw = new StringWriter();
19 Sprites.Save(sw,SaveOptions.DisableFormatting);
20 Console.WriteLine(sw);
21
22 //保存到XmlWriter
23 XmlWriter xw = XmlWriter.Create(@"d:\\Sprites1.xml");
24 Sprites.Save(xw);
25 //写入文件
26 xw.Flush();
27
28 Console.Read();
29 }

ii.结果:

①Sprites.xml文档:

②运行结果:

③Sprites1.xml文档:

  输出xml数据用Save方法,那么输入就用Load方法,同样XDocumnet和XElement类提供了Load方法从xml文件、TextReader对象以及XmlReader对象将xml数据输入,另外还提供了Parse方法从字符串中提取xml数据。下面是XElement类中常用的几个Load方法:

  public static XElement Load(string uri);

  public static XElement Load(TextReader textReader);

  public static XElement Load(XmlReader reader);

  public static XElement Load(string uri, LoadOptions options);

  public static XElement Load(TextReader textReader, LoadOptions options);

  public static XElement Load(XmlReader reader, LoadOptions options);

从中可以看出Load方法和Save方法非常类似。这里就不再一一介绍,主要讲解一下其中涉及到的参数类型LoadOptions,它和SaveOptions一样也是一个枚举类型,用于输入时指定需要的处理,包含None、PreserveWhitespace、SetBaseUri和SetLineInfo四个枚举值。其中None不保留无关紧要的空白,也不加载基 URI 和行信息;PreserveWhitespace表示分析时保留无关紧要的空白;SetBaseUri表示在输入xml数据时加载基本URL信息,基URL信息可以通过XElement类的基类XObject的属性BaseUri读取;SetLineInfo表示输入xml数据时加载的行信息;下面通过实例来进一步说明Load方法的使用:

i.输入xml:

 1         static void Main(string[] args)
2 {
3 XElement loadSprites = XElement.Load(@"d:\\Sprites.xml",LoadOptions.SetBaseUri|LoadOptions.SetLineInfo);
4
5 //添加新元素
6 loadSprites.Elements("Sprite").Last().AddAfterSelf(
7 new XElement("Sprite",
8 new XAttribute("Profession","猎人"),
9 new XAttribute("Weapon","弓箭")
10 ));
11
12 //输出xml信息
13 Console.WriteLine(loadSprites);
14
15 Console.WriteLine("---------------------------------");
16
17 //获取文件基URL信息
18 string baseUri = loadSprites.BaseUri;
19 Console.WriteLine("xml基URL信息:{0}",baseUri);
20
21 Console.WriteLine("---------------------------------");
22
23 //输出xml中每一个元素的行信息
24 foreach (var s in loadSprites.DescendantsAndSelf())
25 {
26 Console.WriteLine("元素名称:{0} 行信息:{1}",s.Name,
27 ((IXmlLineInfo)s).HasLineInfo()?((IXmlLineInfo)s).LineNumber.ToString():"无行号");
28 }
29
30 Console.Read();
31 }

ii.结果:

从运行结果中可以看出新添加的Sprite元素没有行信息

  除了用Load方法,XElement类中还有Parse方法用于将一段字符串中提取XML数据,其方法原型有两个:

  public static XElement Parse(string text);

  public static XElement Parse(string text, LoadOptions options);

  下面用示例来说明Parse方法的使用:

i.Parse方法:

 1         static void Main(string[] args)
2 {
3 //xml字符串
4 string str_xml = @"<Sprites>
5 <Sprite>
6 <Profession>法师</Profession>
7 <Weapon>魔杖</Weapon>
8 </Sprite>
9 <Sprite>
10 <Profession>战士</Profession>
11 <Weapon>屠龙刀</Weapon>
12 </Sprite>
13 <Sprite>
14 <Profession>道士</Profession>
15 <Weapon>倚天剑</Weapon>
16 </Sprite>
17 </Sprites>";
18
19 XElement SpritesFromString = XElement.Parse(str_xml);
20 Console.WriteLine(SpritesFromString);
21
22 Console.Read();
23 }

ii.结果:

   2.除了xml的输入输出操作会经常用到外,对xml数据的遍历操作使用也是很频繁。在LINQ TO XML编程接口类中,主要通过属性和方法来遍历xml,其中最常用的遍历属性有:XNode类的NextNode属性和PreviousNode属性,XObject类的Document属性和Parent属性。NextNode属性用于返回当前节点的下一个节点,PreviousNode属性则返回当前节点上一个节点,Document属性返回当前节点的文档对象,Parent属性返回当前节点的父节点信息。下面通过示例来验证这四个属性的作用:

i.遍历属性:

 1         static void Main(string[] args)
2 {
3 //建立xml文档
4 XDocument document = new XDocument();
5
6 //建立节点
7 XNode node;
8 XElement SpritesForeach = new XElement("Sprites",
9 new XElement("Sprite",
10 new XElement("Profession", "法师"),
11 new XElement("Weapon", "魔杖")),
12
13 new XElement("Sprite",
14 node=new XElement("Profession", "战士"),
15 new XElement("Weapon", "屠龙刀")),
16
17 new XElement("Sprite",
18 new XElement("Profession", "道士"),
19 new XElement("Weapon", "倚天剑")));
20
21 //添加根元素到文档对象中
22 document.Add(SpritesForeach);
23
24 //当前节点上一个节点
25 Console.WriteLine("当前节点上一个节点:{0}",node.PreviousNode);
26
27 //当前节点
28 Console.WriteLine("当前节点:{0}",node);
29
30 //当前节点的下一个节点
31 Console.WriteLine("当前节点的下一个节点:{0}",node.NextNode);
32
33 //当前节点的文档对象
34 Console.WriteLine("当前节点的文档对象:{0}",node.Document);
35
36 //当前节点的父节点
37 Console.WriteLine("当前节点的父节点:{0}",node.Parent);
38
39 Console.Read();
40 }

ii.结果:

  下面介绍XML中常用的遍历方法:XContainer类中的Nodes方法、Elements方法、Element方法和Descendants方法,XNode类中的Ancestors方法、NodesAfterSelf方法、NodesBeforeSelf方法、ElementsAfterSelf方法以及ElementsBeforeSelf方法,XElement类中的AncestorsAndSelf方法和DescendantsAndSelf方法。其中XContainer类中的Elements方法和Nodes方法相似,都是用于返回当前节点的子节点集合,只不过Elements方法返回的序列元素类型为XElement,而Nodes返回的集合元素类型是XNode,方法Element返回当前节点的下级元素中具有指定名称的第一个元素,而方法Descendants返回的是当前节点的直接子元素节点,还包括子元素节点的后代子元素节点。下面通过示例来具体说明XContainer类的遍历方法:

i.XContainer类的遍历方法:

 1         static void Main(string[] args)
2 {
3 //建立节点
4 XNode node;
5 //建立元素
6 XElement element;
7 //建立xml数据源
8 XElement SpritesForeach = new XElement("Sprites",
9 new XElement("Sprite",
10 new XElement("Profession", "法师"),
11 new XElement("Weapon", "魔杖")),
12
13 new XElement("Sprite",
14 node=new XElement("Profession", "战士"),
15 new XElement("Weapon", "屠龙刀")),
16
17 new XElement("Sprite",
18 new XElement("Profession", "道士"),
19 element = new XElement("Weapon", "倚天剑")));
20
21 //当前节点的下一级元素中第一个名为Sprite的元素
22 XElement CurrentElement = SpritesForeach.Element("Sprite");
23 Console.WriteLine("当前节点的下一级元素中第一个名为Sprite的元素:\n{0}",CurrentElement);
24
25 //当前节点所有下级节点
26 Console.WriteLine("当前节点所有下级节点:");
27 foreach (var n in CurrentElement.Nodes())
28 {
29 Console.WriteLine(n);
30 }
31
32 //当前节点所有的后代节点
33 Console.WriteLine("当前节点所有的后代节点:");
34 foreach (var n in CurrentElement.Descendants())
35 {
36 Console.WriteLine("元素名:{0}",n.Name);
37 Console.WriteLine(n);
38 Console.WriteLine("--------------------------------");
39 }
40
41 Console.Read();
42 }

ii.结果:

  XNode类的方法Ancestors用于返回当前节点的所有祖先节点,NodesAfterSelf方法和NodesBeforeSelf方法用于返回当前节点所有后续节点和所有前驱节点。ElementsAfterSelf方法与ElementsBeforeSelf方法和NodesAfterSelf方法和NodesBeforeSelf方法类似,只不过返回的结合元素类型不同。下面通过示例具体说明XNode类的遍历方法:

i.XNode类的遍历方法:

 1         static void Main(string[] args)
2 {
3 //建立节点
4 XNode node;
5 //建立元素
6 XElement element;
7 //建立xml数据源
8 XElement SpritesForeach = new XElement("Sprites",
9 new XElement("Sprite",
10 new XElement("Profession", "法师"),
11 new XElement("Weapon", "魔杖")),
12
13 new XElement("Sprite",
14 node=new XElement("Profession", "战士"),
15 new XElement("Weapon", "屠龙刀")),
16
17 new XElement("Sprite",
18 new XElement("Profession", "道士"),
19 element = new XElement("Weapon", "倚天剑")));
20
21 //当前节点的所有祖先元素
22 Console.WriteLine("当前节点的所有祖先元素:");
23 foreach (var e in node.Ancestors())
24 {
25 Console.WriteLine("元素名:{0}", e.Name);
26 Console.WriteLine(e);
27 Console.WriteLine("---------------------------------");
28 }
29
30 //当前节点的所有后续节点
31 Console.WriteLine("当前节点的所有后续节点:");
32 foreach (var n in node.NodesAfterSelf())
33 {
34 Console.WriteLine(n);
35 }
36
37 //当前节点的所有前驱节点
38 Console.WriteLine("当前节点的所有前驱节点:");
39 foreach (var n in node.NodesBeforeSelf())
40 {
41 Console.WriteLine(n);
42 }
43
44 Console.Read();
45 }

ii.结果:

  XElement类的AncestorsAndSelf方法和DescendantsAndSelf方法,分别用于返回当前元素和当前元素的所有祖先元素和返回当前元素和当前元素的所有后代元素。下面通过示例具体说明XElement类的遍历方法:

i.XElement类的遍历方法:

 1         static void Main(string[] args)
2 {
3 //建立节点
4 XNode node;
5 //建立元素
6 XElement element;
7 //建立xml数据源
8 XElement SpritesForeach = new XElement("Sprites",
9 new XElement("Sprite",
10 new XElement("Profession", "法师"),
11 new XElement("Weapon", "魔杖")),
12
13 new XElement("Sprite",
14 node=new XElement("Profession", "战士"),
15 new XElement("Weapon", "屠龙刀")),
16
17 new XElement("Sprite",
18 new XElement("Profession", "道士"),
19 element = new XElement("Weapon", "倚天剑")));
20
21 //当前元素和其所有的祖先元素
22 Console.WriteLine("当前元素和其所有的祖先元素:");
23 foreach (var e in element.AncestorsAndSelf())
24 {
25 Console.WriteLine("元素名:{0}",e.Name);
26 Console.WriteLine(e);
27 Console.WriteLine("----------------------------------");
28 }
29
30 //当前元素和其所有的后代元素
31 Console.WriteLine("当前元素和其所有的后代元素:");
32 foreach (var e in element.DescendantsAndSelf())
33 {
34 Console.WriteLine("元素名:{0}", e.Name);
35 Console.WriteLine(e);
36 Console.WriteLine("----------------------------------");
37 }
38
39 Console.Read();
40 }

ii.结果:

  3.同样的,在LINQ TO XML中也提供了许多方法和属性来修改XML节点的内容,其中属性中最常用的就是很多LINQ TO XML编程接口类中都有的Value属性,通过它来修改XML节点或元素中的值。而方法就更多了,包括添加节点、修改节点和删除节点等操作。XContainer类中的添加节点方法有Add和AddFirst方法,删除节点的方法有RemoveNodes,其中Add方法用于添加为当前节点的子节点,如果当前节点已经包含子节点,则将新的节点追加为最后一个子节点。而AddFirst方法则是将指定的节点添加为当前节点的第一个子节点。RemoveNodes方法用于将当前节点下的子节点删除。下面通过示例来具体说明XContainer类中修改xml的方法:

i.XContainer类的xml修改方法:

 1  static void Main(string[] args)
2 {
3 //建立节点
4 XNode node;
5
6 //建立元素
7 XElement element;
8
9 //建立xml数据源
10 XElement Sprites = new XElement("Sprites",
11 new XElement("Sprite01",
12 new XElement("Profession", "法师"),
13 new XElement("Weapon", "魔杖")),
14 new XElement("Sprite",
15 new XElement("Profession", "战士"),
16 node = new XElement("Weapon", "屠龙刀")),
17 element= new XElement("Sprite",
18 new XAttribute("Profession", "道士"),
19 new XAttribute("Weapon", "倚天剑")));
20
21
22 //添加为最后一个子节点
23 Sprites.Add(new XElement("Sprite",
24 new XAttribute("Profession", "猎人"),
25 new XAttribute("Weapon", "弓箭")
26 ));
27
28 //添加为第一个子节点
29 Sprites.AddFirst(new XElement("Sprite",
30 new XAttribute("Profession", "骑士"),
31 new XAttribute("Weapon", "方天画戟")
32 ));
33
34 //删除子节点
35 Sprites.Element("Sprite01").RemoveNodes();
36
37 Console.WriteLine(Sprites);
38
39 Console.Read();
40 }

ii.结果:

  除了类XContainer中的方法可以修改节点外,还有就是XNode类中的AddAfterSelf方法和AddBeforeSelf方法,前者将指定内容添加为自身节点的前一个节点,后者则将指定内容添加为自身节点的后一个节点。删除自身节点则是用XNode类中的Remove方法。下面通过示例来具体说明XNode类中修改xml的方法:

i.XNode类的xml修改方法:

 1  static void Main(string[] args)
2 {
3 //建立节点
4 XNode node;
5
6 //建立元素
7 XElement element;
8
9 //建立xml数据源
10 XElement Sprites = new XElement("Sprites",
11 new XElement("Sprite01",
12 new XElement("Profession", "法师"),
13 new XElement("Weapon", "魔杖")),
14 new XElement("Sprite",
15 new XElement("Profession", "战士"),
16 node = new XElement("Weapon", "屠龙刀")),
17 element= new XElement("Sprite",
18 new XAttribute("Profession", "道士"),
19 new XAttribute("Weapon", "倚天剑")));
20
21 //添加为自身节点的前一个节点
22 node.AddBeforeSelf(new XElement("Weapon", "雪饮刀"));
23
24 //添加为自身节点的后一个节点
25 node.AddAfterSelf(new XElement("Weapon", "狼牙棒"));
26
27 //删除自身节点
28 Sprites.FirstNode.Remove();
29
30 Console.WriteLine(Sprites);
31
32 Console.Read();
33 }

ii.结果:

  还有就是用XElement类方法来修改xml中的元素内容,同时它也提供了Attribute方法来辅助Value属性对xml属性内容进行修改,或直接用SetAttributeValue来代替,SetElementValue方法用于修改指定元素的值。而删除自身所有子节点和属性则用RemoveAll方法,删除元素属性用RemoveAttributes方法。下面通过示例来具体说明XElement类中修改xml的属性和方法:

i.XElement类的xml修改属性和方法:

 1  static void Main(string[] args)
2 {
3 //建立节点
4 XNode node;
5
6 //建立元素
7 XElement element;
8
9 //建立xml数据源
10 XElement Sprites = new XElement("Sprites",
11 new XElement("Sprite01",
12 new XElement("Profession", "法师"),
13 new XElement("Weapon", "魔杖")),
14 new XElement("Sprite",
15 new XElement("Profession", "战士"),
16 node = new XElement("Weapon", "屠龙刀")),
17 element= new XElement("Sprite",
18 new XAttribute("Profession", "道士"),
19 new XAttribute("Weapon", "倚天剑")));
20
21 //Name属性修改
22 Sprites.Element("Sprite01").Name="Sprite";
23
24 //Value属性修改
25 element.Attribute("Weapon").Value="火麟剑";
26 //
27 //element.SetAttributeValue("Weapon", "火麟剑");
28
29 //删除元素属性
30 element.RemoveAttributes();
31
32 //
33 //删除自身所有子节点和属性
34 //element.RemoveAll();
35
36 Console.WriteLine(Sprites);
37
38 Console.Read();
39 }

ii.结果:

  最后来说说LINQ TO XML中查询,看到查询你就应该会回忆起之前在LINQ TO Object系列当中所讲的标准查询操作符,其实这些查询符在LINQ TO XML中也依然受用,只不过操作的序列元素的类型可能会是XElement或XNode等等。那么在这里就简单地用一个示例来说明一下LINQ TO XML中的查询操作:

i.xml源文件:

Sprites.xml
 1 <?xml version="1.0" encoding="utf-8" ?>
2 <Sprites>
3 <Sprite>
4 <Profession>法师</Profession>
5 <Weapon>魔杖</Weapon>
6 </Sprite>
7 <Sprite>
8 <Profession>战士</Profession>
9 <Weapon>屠龙刀</Weapon>"
10 </Sprite>
11 <Sprite>
12 <Profession>道士</Profession>
13 <Weapon>倚天剑</Weapon>
14 </Sprite>
15 </Sprites>

ii.XML查询操作:

 1         static void Main(string[] args)
2 {
3 //读取xml文件
4 XElement xml = XElement.Load("Sprites.xml");
5
6 //查询所有元素名为Sprite的元素
7 var sprites = from s in xml.Descendants("Sprite")
8 select new {
9 Profession = s.Element("Profession").Value,
10 Weapon=s.Element("Weapon").Value
11 };
12
13 //输出sprites信息
14 foreach (var s in sprites)
15 {
16 Console.WriteLine("精灵职业:{0}",s.Profession);
17 Console.WriteLine("主要武器:{0}",s.Weapon);
18 Console.WriteLine("----------------------------------------");
19 }
20
21 Console.Read();
22 }

iii.结果:

 

posted @ 2011-09-25 00:02  Rookie_J  阅读(1955)  评论(1编辑  收藏  举报