82

我想制作一个 LINQ to XML XElement 的深层副本。我想这样做的原因是文档中有一些节点我想创建修改后的副本(在同一个文档中)。我没有看到这样做的方法。

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

4

5 回答 5

148

无需重新解析。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);
}
于 2008-12-10T15:35:21.423 回答
9

看起来 ToString 和 reparse 方法是最好的方法。这是代码:

XElement copy = XElement.Parse(original.ToString());
于 2008-10-16T18:17:41.823 回答
4

简而言之,直接从C# 3.0 中提取:

当节点或属性被添加到元素时(无论是通过函数构造还是 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 对象实例化没有副作用——函数式编程的另一个标志。

于 2008-10-17T14:00:47.347 回答
-1

这应该有效:

var copy = new XElement(original.Name, original.Attributes(),
                        original.Elements() );
于 2013-08-16T15:26:17.170 回答
-3

我不相信存在允许您执行 XNode 样式树的深层副本的现有机制。我认为你有两个选择。

  1. 按照您的建议执行转换为字符串,然后再转换回树
  2. 用访客模式写在自己身上

访问者模式当然是可能的,但需要大量工作才能进行测试。我认为你最好的选择是#1。

于 2008-10-16T17:58:21.517 回答