LINQ学习笔记:更新一个X-DOM
更新一个X-DOM
更新元素和attributes我们可以有以下的几种方法:
- 调用SetValue或者重新赋值给Value属性(property)
- 调用SetElementValue或者SetAttributeValue
- 调用一个RemoveXXX方法
- 调用一个AddXXX或ReplaceXXX方法, 指定更新的内容
我们也可以对XElement对象的Name属性重新赋值达到更新目的
简单的值更新
成员 | 应用于 |
SetValue(object) | XElement, XAttribute |
Value | XElement, XAttribute |
SetValue用一个简单值更新了一个元素或者属性的内容. 更新Value property也可以完成相当的工作, 但其只接受string数据类型.
调用SetValue或者更新Value属性带来的影响就是它替换了所有的子节点:
1: XElement settings = new XElement ("settings",
2: new XElement ("timeout", 30)
3: );
4: settings.SetValue ("blah");
5: Console.WriteLine (settings.ToString( ));
6:
7: // RESULT: <settings>blah</settings>
更新子节点与属性
分类 | 成员 | 应用于 |
Add | Add(params object[]) | XContainer |
AddFirst(params object[]) | XContainer | |
Remove | RemoveNodes() | XContainer |
RemoveAttributes() | XElement | |
RemoveAll() | XElement | |
Update | ReplaceNodes(params object[]) | XContainer |
ReplaceAttributes(params object[]) | XElement | |
ReplaceAll(params object[]) | XElement | |
SetElementValue(XName, object) | XElement | |
SetAttributeValue(XName, object) | XElement |
在这一组方法中最方便方法是最后两个:SetElementValue和SetAttributeValue. 它们扮演了实例化XElement和XAttribute并将其加入一个父节点的快捷方式, 并替代了存在的指定名称的元素或属性.
1: XElement settings = new XElement ("settings");
2: settings.SetElementValue ("timeout", 30); // 新增子节点
3: settings.SetElementValue ("timeout", 60); // 更新子节点
Add方法添加一个子节点到一个元素或者文档中. AddFirst也一样, 但它将节点加入整个节点集合的开头而不是结尾. 我们也可以通过一次调用RemoveNodes或者RemoveAttributes将所有的子节点和子属性全部删除. RemoveAll相当于同时调用了这两个方法. ReplaceXXX方法等价于想调用Removing然后再次调用Adding. 对于输入参数他们拥有一个快照, 因此e.ReplaceNodes(e.Nodes)可以如期工作.
通过Parent节点更新
成员 | 应用于 |
AddBeforeSelf(params object[]) | XNode |
AddAfterSelf(params object[]) | XNode |
Remove() | XNode*, XAttribute* |
ReplaceWith(params object[]) | XNode |
方法AddBeforeSelf, AddAfterSelf, Remove和ReplaceWith不会对当前节点的子节点进行操作. 相反, 它们操作当前节点自己所在的集合. 这要求当前节点必须拥有一个父亲元素–否则, 异常将会抛出. AddBeforeSelf和AddAfterSelf对于将节点加入到任意位置是非常有用的:
1: XElement items = new XElement ("items",
2: new XElement ("one"),
3: new XElement ("three")
4: );
5: items.FirstNode.AddAfterSelf (new XElement ("two"));
输出结果为:
1: <items><one /><two /><three /></items>
即使要在一个包含多个元素的序列当中插入任意位置的节点也是非常有效率的, 因为其内部被保存为linked list.
Remove方法从父亲节点当中移除当前节点. ReplaceWith也是一样, 但其同时插入了新的节点到相同的位置. 例如:
1: XElement items = XElement.Parse
2: ("<items><one/><two/><three/></items>");
3: items.FirstNode.ReplaceWith
4: (new XComment ("One was here"));
其结果为:
1: <items><!--one was here--><two /><three/></items>
移除序列中的节点或属性
感谢System.Xml.Linq当中的扩展方法, 我们可以调用Remove来删除序列中的节点或者属性. 考虑以下下列的X-DOM:
1: XElement contacts = XElement.Parse (
2: @" <contacts>3: <customer name='Mary'/>
4: <customer name='Chris' archived='true'/>
5: <supplier name='Susan'>
6: <phone archived='true'>
7: <012345678
8: <!--confidential-->
9: </phone>
10: </supplier>
11: </contacts>");
以下的代码删除了所有的customers:
1: contacts.Elements ("customer").Remove();
下列的代码则删除所有的archived contacts(因此”Chris”将会消失)
1: contacts.Elements( )
2: .Where (e => (bool?) e.Attribute ("archived") == true)
3: .Remove( );
在内部, Remove方法首先读取所有匹配的元素到一个临时的列表当中, 然后枚举该临时列表并执行删除操作. 这避免了在删除的同时进行查询操作引起的错误.
如果我们使用Descendants()代替Elements(), 那么DOM当中所有archived的元素都将会消息, 我们将会得到如下的结果:
1: <contacts>
2: <customer name="Mary" />
3: <supplier name="Susan" />
4: </contacts>
下面的例子移除了所有在他们树节点任何地方包含了”confidential”注释的contacts:
1: contacts.Elements( )
2: .Where (
3: e => e.DescendantNodes( )
4: .OfType<XComment>( )
5: .Any (c => c.Value == "confidential")
6: ).Remove( );
结果为:
1: <contacts>
2: <customer name="Mary" />
3: <customer name="Chris" archived="true" />
4: </contacts>
如果我们使用以下的方法将会删除所有的comment节点:
1: contacts.DescendantNodes().OfType<XComment>().Remove();
待续!