如何在LINQ中将元素进行深拷贝到XML?


76

我想将LINQ复制到XML XElement。我要执行此操作的原因是文档中有一些节点要创建(在同一文档中)修改后的副本。我看不到执行此操作的方法。

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


丹尼尔-我认为您应该重新考虑对此问题的公认答案。
Jim G.

完成-我更改了接受的答案。
丹尼尔(Daniel Plaisted)

Answers:


138

无需修复。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);
}

6
我相信此示例中使用的构造函数通常称为Copy Constructor。这是XElementCopy构造函数的文档。还有一个XDocument复制构造函数。对我们来说幸运的是,LINQ to XML使得此操作变得容易。。。一般来说,深度复制(或克隆)可能不是那么简单。
DavidRR 2014年

1
开派对有点晚,但是第一个测试用例与浅表复制无关。这根本不是副本,它是对同一对象的第二次引用。您可以对C#中的所有非基本类型应用相同的原理。
UweB

文档正好显示了这一点,并说明了“以下示例创建XML树,创建树的克隆,然后调用DeepEquals,以测试两个XML树是否相等。” 。在该示例中,在调用复制构造函数之后添加了一个节点,并DeepEquals显示了两个节点现在不同。
亚伯

9

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

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

然后DstNode.Add(copy)添加它。做完了
Fraga

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对象实例化免受副作用的影响-这是功能编程的另一个标志。


当时这是一个非常敏锐的观察,确实确实发生什么(请参阅此处的示例代码)。
亚伯

-1

这应该工作:

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

不,不是。这样,您就忘记了复制注释,文本节点,处理指令,继承的命名空间节点,注释,base-uri等。更好的方法是使用copy-constructor new XElement(original)
亚伯

-3

我认为没有现有的机制可以让您执行XNode样式树的深层复制。我认为您还有两个选择。

  1. 按照建议执行操作,先转换为字符串,然后再转换为树
  2. 用访客模式写自己

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.