在向大家详细介绍LINQ to XML之前,首先让大家了解下LINQ to XML元素,然后全面介绍LINQ to XML。
对于LINQ to XML元素的更新操作,关键就是在于查询上面,如何有效并准确的查询到目标元素是一个比较有挑战性的问题,这就像SQL语句一样对于同一个查询不同的写法和关系连接效率就不一样,这个读者需要自己多加练习。在上面的代码段中,我们去查找所有属性为PartNumber=872-AA的元素并将其更新为Hello。那么如果想操作元素值,只需将修改查询条件为:
- var partNos = from item in xelem.Descendants("ProductName")
- where item.Value == "Lawnmower"
XML文档的元素名称更新相比较于值更新要麻烦许多。由于XML文档结构是一个类树形结构,学过数据结构的读者知道要更新一个树节点的指针,最少需要三个步骤:
A. 查找目标树节点的父节点
B. 将先前的节点的孩子转移到新节点
C. 将父节点的子节点替换(如果需要还要用算法重新排序树)。
所以我们也需要用同样的逻辑来处理XML节点的更新。那么相比较DOM文档对象和LINQ to XML元素名称更新操作,LINQ to XML的步骤要简单许多。
- XElement xel = XElement.Load(@"example.xml");
- var itemNos = from item in xel.Descendants("Item")
- select item;
- int n = itemNos.Count();
- for (int i=0; i<n; i++)
- {
- // 新创建节点
- XElement nEl = new XElement("Element");
- // 转移孩子节点
- nEl.Add(itemNos.ElementAt(0).Elements());
- // 替换
- itemNos.ElementAt(0).ReplaceWith(nEl);
- }
- Console.Write(xel);
上面的代码是将所有名称为Item的元素替换成名称为Element。细心的读者可以看到我在for循环中获取itemNos的孩子都使用0这个索引值,为什么呢?这是因为在枚举器中如果前面的对象消失那么索引位置就会下移,那么当我们替换一个元素后,下一个元素的索引自动变为0,所以我们只要循环指定次数就可以遍历所有元素来。这也是为什么不用foreach的原因。那么我们进一步的出思考XML名称替换这个问题。我们会发现LINQ to XML的XElement类提供了4个方法用来支持该功能:ReplaceAll, ReplaceAttributes, ReplaceNodes和ReplaceWith。这四个方法除了ReplaceWith是操作本元素以为,其他的都是操作元素的孩子或是属性内容。这里提供的好处是如果我们想遍历替换操作,就不必去重复的查询目标元素。
最后,我们讨论一下如何利用LINQ to XML来删除一个元素。对于类树形结构的数据来说,删除一个元素意味着两种情况:一、删除本节点和其所有子节点;二、只删除本节点。而在删除节点之前,我们需要先定位到目标节点,所以要先进行查询操作:
- XElement xelem = XElement.Load(@"example.xml");
- var partNos = from item in xelem.Descendants("Item")
- where item.Attributes("PartNumber").Single().Value == "872-AA"
- select item;
- partNos.Remove();
- Console.Write(xelem);
【编辑推荐】