查找具有特定属性的元素
XElement root = XElement.Load("PurchaseOrder.xml");
IEnumerable<XElement> address =
from el in root.Elements("Address")
where (string)el.Attribute("Type") == "Billing"
select el;
foreach (XElement el in address)
Console.WriteLine(el);
输出为:
<Address Type="Billing">
<Name>Tai Yee</Name>
<Street>8 Oak Avenue</Street>
<City>Old Town</City>
<State>PA</State>
<Zip>95819</Zip>
<Country>USA</Country>
</Address>
内存中 XML 树修改与函数构造
就地修改 XML 树是更改 XML 文档形状的传统方法。 典型的应用程序将文档加载到数据存储区(如 DOM 或 LINQ to XML);使用编程接口插入节点、删除节点或更改节点的内容;然后将 XML 保存到文件或通过网络传输。
LINQ to XML 允许使用另一种可在许多方案中使用的方法:函数构造。 函数构造将修改数据视为转换问题,而不是数据存储区的具体操作。 如果您采用某种数据表示形式并有效地将其从一种形式转换为另一种形式,其结果等效于您采用一个数据存储区并对其以某种方式进行操作以采用另一种形状。 函数构造方法的关键是将查询的结果传递给 XDocument 和 XElement 构造函数。
此示例假设您想修改下面的简单 XML 文档,使属性变为元素。 本节首先介绍传统的就地修改方法。 然后显示函数构造方法。XML文件:
<?xml version="1.0" encoding="utf-8" ?>
<Root Data1="123" Data2="456">
<Child1>Content</Child1>
</Root>
您可以编写一些过程代码以便从属性创建元素,然后删除属性,如下所示:
XElement root = XElement.Load("Data.xml");
foreach (XAttribute att in root.Attributes()) {
root.Add(new XElement(att.Name, (string)att));
}
root.Attributes().Remove();
Console.WriteLine(root);
输出结果为:
<Root>
<Child1>Content</Child1>
<Data1>123</Data1>
<Data2>456</Data2>
</Root>
函数构造方法
相比之下,函数方法包含用于形成新树的代码、从源树中选择元素和属性并在将其添加到新树中时进行相应的转换。 函数方法如下所示:
XElement root = XElement.Load("Data.xml");
XElement newTree = new XElement("Root",
root.Element("Child1"),
from att in root.Attributes()
select new XElement(att.Name, (string)att)
);
Console.WriteLine(newTree);
在本例中,函数示例一点也不比第一个示例简短,而且一点也不比第一个示例简单。 但如果要对一个 XML 树进行很多更改,则非函数方法将变得非常复杂,而且会显得很笨拙。 相比之下,使用函数方法时,您只需形成所需的 XML,嵌入适当的查询和表达式以提取需要的内容。 函数方法生成的代码更易于维护。
请注意,在本例中,函数方法的执行效果可能没有树操作方法好。 主要问题是函数方法创建了更多短生存期的对象。 但是,如果使用函数方法能够提高程序员的效率,则折中也是一种有效的方式。
这是一个很简单的示例,但它显示了这两种方法之间基本原理上的差异。 对于转换较大的 XML 文档,函数方法可以产生更高的效率增益。
向 XML 树中添加元素、属性和节点
下面的方法将子内容添加到 XElement 或 XDocument 中:
方法 说明
Add 在 XContainer 的子内容的末尾添加内容。
AddFirst 在 XContainer 的子内容的开头添加内容。
下面的方法将内容添加为 XNode 的同级节点。 向其中添加同级内容的最常见的节点是 XElement,不过你也可以将有效的同级内容添加到其他类型的节点,例如 XText 或 XComment。
方法 说明
AddAfterSelf 在 XNode 后面添加内容。
AddBeforeSelf 在 XNode 前面添加内容。
示例:
XElement srcTree = new XElement("Root",
new XElement("Element1", 1),
new XElement("Element2", 2),
new XElement("Element3", 3),
new XElement("Element4", 4),
new XElement("Element5", 5)
);
XElement xmlTree = new XElement("Root",
new XElement("Child1", 1),
new XElement("Child2", 2),
new XElement("Child3", 3),
new XElement("Child4", 4),
new XElement("Child5", 5)
);
xmlTree.Add(new XElement("NewChild", "new content"));
xmlTree.Add(
from el in srcTree.Elements()
where (int)el > 3
select el
);
// Even though Child9 does not exist in srcTree, the following statement will not
// throw an exception, and nothing will be added to xmlTree.
xmlTree.Add(srcTree.Element("Child9"));
Console.WriteLine(xmlTree);
输出结果:
<Root>
<Child1>1</Child1>
<Child2>2</Child2>
<Child3>3</Child3>
<Child4>4</Child4>
<Child5>5</Child5>
<NewChild>new content</NewChild>
<Element4>4</Element4>
<Element5>5</Element5>
</Root>
修改 XML 树中的元素、属性和节点
下表汇总了修改元素、元素的子元素或元素属性 (Attribute) 时可以使用的方法和属性 (Property)。
下面的方法修改 XElement 。
方法 |
说明 |
XElement ..::.Parse |
用已分析的 XML 替换元素。 |
XElement ..::.RemoveAll |
移除元素的所有内容(子节点和属性)。 |
XElement ..::.RemoveAttributes |
移除元素的属性。 |
XElement ..::.ReplaceAll |
替换元素的所有内容(子节点和属性)。 |
XElement ..::.ReplaceAttributes |
替换元素的属性。 |
XElement ..::.SetAttributeValue |
设置属性的值。 如果该属性不存在,则创建该属性。 如果值设置为 null,则移除该属性。 |
XElement ..::.SetElementValue |
设置子元素的值。 如果该元素不存在,则创建该元素。 如果值设置为 null,则移除该元素。 |
XElement ..::.Value |
用指定的文本替换元素的内容(子节点)。 |
XElement ..::.SetValue |
设置元素的值。 |
下面的方法修改 XAttribute 。
方法 |
说明 |
XAttribute ..::.Value |
设置属性的值。 |
XAttribute ..::.SetValue |
设置属性的值。 |
下面的方法修改 XNode (包括 XElement 或 XDocument )。
方法 |
说明 |
XNode ..::.ReplaceWith |
用新内容替换节点。 |
下面的方法修改 XContainer ( XElement 或 XDocument )。
方法 |
说明 |
XContainer ..::.ReplaceNodes |
用新内容替换子节点。 |
XElement.SetElementValue 方法
此方法旨在简化将名称/值对列表用作子元素集时的维护。维护列表时,需要添加对、修改对或删除对。如果调用此方法将不存在的名称作为子元素传递,则此方法会为您创建一个子元素。如果您调用此方法来传递一个现有子元素的名称,则此方法会将此子元素的值更改为指定的值。如果您为 value 传递了 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing),则此方法会移除子元素。
// Create an element with no content
XElement root = new XElement("Root");
// Add some name/value pairs.
root.SetElementValue("Ele1", 1);
root.SetElementValue("Ele2", 2);
root.SetElementValue("Ele3", 3);
Console.WriteLine(root);
// Modify one of the name/value pairs.
root.SetElementValue("Ele2", 22);
Console.WriteLine(root);
// Remove one of the name/value pairs.
root.SetElementValue("Ele3", null);
Console.WriteLine(root);
输出结果:
<Root>
<Ele1>1</Ele1>
<Ele2>2</Ele2>
<Ele3>3</Ele3>
</Root>
<Root>
<Ele1>1</Ele1>
<Ele2>22</Ele2>
<Ele3>3</Ele3>
</Root>
<Root>
<Ele1>1</Ele1>
<Ele2>22</Ele2>
</Root>
XElement.SetAttributeValue 方法
此方法旨在简化将名称/值对列表用作属性集时的维护。维护列表时,需要添加对、修改对或删除对。如果调用此方法将不存在的名称作为属性传递,则此方法会为您创建一个属性。如果调用此方法来传递现有属性的名称,则此方法将会属性的值修改为指定的值。如果您为 value 传递了 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing),则此方法会移除该属性。
此方法将引发 Changed 和 Changing 事件。
将值分配给具有指定名称的属性。如果不存在具有指定名称的属性,则添加新属性。如果值为 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing),则删除具有指定名称的属性(如果存在)。
// Create an element with no content.
XElement root = new XElement("Root");
// Add some name/value pairs.
root.SetAttributeValue("Att1", 1);
root.SetAttributeValue("Att2", 2);
root.SetAttributeValue("Att3", 3);
Console.WriteLine(root);
// Modify one of the name/value pairs.
root.SetAttributeValue("Att2", 22);
Console.WriteLine(root);
// Remove one of the name/value pairs.
root.SetAttributeValue("Att3", null);
Console.WriteLine(root);
输出结果为:
<Root Att1="1" Att2="2" Att3="3" />
<Root Att1="1" Att2="22" Att3="3" />
<Root Att1="1" Att2="22" />
XNode.ReplaceWith 方法
使用指定的内容替换此节点。
XElement xmlTree = new XElement("Root",
new XElement("Child1", "child1 content"),
new XElement("Child2", "child2 content"),
new XElement("Child3", "child3 content"),
new XElement("Child4", "child4 content"),
new XElement("Child5", "child5 content")
);
XElement child3 = xmlTree.Element("Child3");
child3.ReplaceWith(
new XElement("NewChild", "new content")
);
Console.WriteLine(xmlTree);
输出结果:
<Root>
<Child1>child1 content</Child1>
<Child2>child2 content</Child2>
<NewChild>new content</NewChild>
<Child4>child4 content</Child4>
<Child5>child5 content</Child5>
</Root>
从 XML 树中移除元素、属性和节点
可以修改 XML 树,移除元素、属性和其他类型的节点。
从 XML 文档中移除单个元素或单个属性的操作非常简单。 但是,若要移除多个元素或属性的集合,则应首先将一个集合具体化为一个列表,然后从该列表中删除相应元素或属性。 最好的方法是使用 Remove 扩展方法,该方法可以实现此操作。
这么做的主要原因在于,从 XML 树检索的大多数集合都是用延迟执行生成的。 如果不首先将集合具体化为列表,或者不使用扩展方法,则可能会遇到某类 Bug。
示例:
此示例演示三种移除元素的方法。 第一种,移除单个元素。 第二种,检索元素的集合,使用 Enumerable.ToList<(Of <(TSource>)>) 运算符将它们具体化,然后移除集合。 最后一种,检索元素的集合,使用 Remove 扩展方法移除元素。
XElement root = XElement.Parse(@"<Root>
<Child1>
<GrandChild1/>
<GrandChild2/>
<GrandChild3/>
</Child1>
<Child2>
<GrandChild4/>
<GrandChild5/>
<GrandChild6/>
</Child2>
<Child3>
<GrandChild7/>
<GrandChild8/>
<GrandChild9/>
</Child3>
</Root>");
root.Element("Child1").Element("GrandChild1").Remove();
root.Element("Child2").Elements().ToList().Remove();
root.Element("Child3").Elements().Remove();
Console.WriteLine(root);
输出结果为:
<Root>
<Child1>
<GrandChild2 />
<GrandChild3 />
</Child1>
<Child2 />
<Child3 />
</Root>