如何在LINQ to XML中对元素进行深层复制?

时间:2008-10-16 17:52:02

标签: .net linq-to-xml

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

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

5 个答案:

答案 0 :(得分:117)

无需重新分析。 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);
}

答案 1 :(得分:8)

看起来像ToString和重新分析方法是最好的方法。这是代码:

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

答案 2 :(得分:3)

直接从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对象实例化无副作用 - 这是函数式编程的另一个标志。

答案 3 :(得分:0)

这应该有效:

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

答案 4 :(得分:-2)

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

  1. 按照您的建议转换为字符串然后返回树
  2. 用访客模式写自己
  3. 访客模式当然是可能的,但是需要大量的工作才能进行测试。我认为你最好的选择是#1。