如何对 LINQtoXML 中的元素进行深度复制?

我想做一个 LINQtoXMLXElement 的深度副本。我想这样做的原因是,在文档中有一些节点,我想创建修改后的副本(在同一个文档中)。我看不出有什么方法可以做到这一点。

我可以将元素转换成 XML 字符串,然后重新解析它,但我想知道是否有更好的方法。

23925 次浏览

我不认为现有的机制允许您执行 XNode 样式树的深度副本。我觉得你有两个选择。

  1. 按照您建议的方法将字符串转换为一个字符串,然后返回到一棵树
  2. 用访问者模式在自己身上写字

访问者模式当然是可能的,但是它需要大量的工作和测试。我觉得你最好的选择是第一条。

看起来 ToString 和 parse 方法是最好的方法,下面是代码:

XElement copy = XElement.Parse(original.ToString());

C # 3.0 in a Nutshell直接举起:

当节点或属性被添加到元素(无论是通过函数构造还是 Add 方法)时,节点或属性的 Parent 属性被设置为该元素。一个节点只能有一个父元素: 如果将一个已经为父元素的节点添加到另一个父元素,则该节点将自动进行深度克隆。在下面的示例中,每个客户都有一份独立的地址副本:

var address = new XElement ("address",
new XElement ("street", "Lawley St"),
new XElement ("town", "North Beach")
);
var customer1 = new XElement ("customer1", address);
var customer2 = new XElement ("customer2", address);


customer1.Element ("address").Element ("street").Value = "Another St";
Console.WriteLine (
customer2.Element ("address").Element ("street").Value);   // Lawley St

这种自动复制使 X-DOM 对象实例化免于副作用ーー函数式编程的另一个标志。

没有必要重修旧好。XElement 的一个构造函数接受另一个 XElement 并对其进行深度复制:

XElement original = new XElement("original");
XElement deepCopy = new XElement(original);

下面是一些单元测试来演示:

[TestMethod]
public void XElementShallowCopyShouldOnlyCopyReference()
{
XElement original = new XElement("original");
XElement shallowCopy = original;
shallowCopy.Name = "copy";
Assert.AreEqual("copy", original.Name);
}


[TestMethod]
public void ShouldGetXElementDeepCopyUsingConstructorArgument()
{
XElement original = new XElement("original");
XElement deepCopy = new XElement(original);
deepCopy.Name = "copy";
Assert.AreEqual("original", original.Name);
Assert.AreEqual("copy", deepCopy.Name);
}

这应该会奏效:

var copy = new XElement(original.Name, original.Attributes(),
original.Elements() );