在向大家详细介绍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"
- 1.
- 2.
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);
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
上面的代码是将所有名称为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);
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
【编辑推荐】