Pregunta

Quiero hacer una copia profunda de un LINQ to XML XElement. La razón por la que quiero hacer esto es que hay algunos nodos en el documento en los que quiero crear copias modificadas (en el mismo documento). No veo un método para hacer esto.

Podría convertir el elemento en una cadena XML y luego volver a analizarlo, pero me pregunto si hay una mejor manera.

¿Fue útil?

Solución

No hay necesidad de repasar. Uno de los constructores de XElement toma otro XElement y hace una copia profunda del mismo:

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

Aquí hay un par de pruebas de unidad para demostrar:

[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);
}

Otros consejos

Parece que el método ToString y volver a analizar es la mejor manera. Aquí está el código:

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

Levantado directamente de C # 3.0 en pocas palabras :

Cuando un nodo o atributo se agrega a un elemento (ya sea a través de la construcción funcional o mediante un método Agregar), la propiedad principal del nodo o atributo se establece en ese elemento. Un nodo solo puede tener un elemento principal: si agrega un nodo ya asignado a un segundo padre, el nodo se clonará automáticamente en profundidad. En el siguiente ejemplo, cada cliente tiene una copia de dirección separada:

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

Esta duplicación automática mantiene la instanciación de objetos X-DOM sin efectos secundarios, otro sello distintivo de la programación funcional.

Esto debería funcionar:

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

No creo que exista un mecanismo que le permita realizar una copia profunda de un árbol de estilo XNode. Creo que te quedan dos opciones.

  1. Haz lo que sugeriste para convertir a una cadena y luego regresa a un árbol
  2. Escribe en ti mismo con un patrón de visitante

El patrón de visitantes es ciertamente posible, pero llevará mucho trabajo y una prueba. Creo que tu mejor opción es # 1.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top