Як зробити глибоку копію елемента в LINQ у XML?


76

Я хочу зробити глибоку копію LINQ до XML XElement. Причиною того, що я хочу це зробити, є те, що в документі є кілька вузлів, для яких я хочу створити змінені копії (в тому самому документі). Я не бачу методу, щоб це зробити.

Я міг би перетворити елемент на XML-рядок, а потім провести його повторний аналіз, але мені цікаво, чи є кращий спосіб.


Даніель - Я думаю, вам слід переглянути прийняту відповідь на це питання.
Jim G.

Готово - я змінив прийняту відповідь.
Деніел Пліс

Відповіді:


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
Я вважаю, що конструктор, використаний у цьому прикладі, загалом відомий як конструктор копіювання . Ось документ для XElementконструктора копіювання . Існує також XDocumentконструктор копіювання . На наше щастя, LINQ to XML полегшує це ... загалом, глибоке копіювання (або клонування) може багато разів бути не таким простим.
DavidRR

1
Трохи запізнився на вечірку, але перший тест не має нічого спільного з неглибоким копіюванням. Це зовсім не копія, це друге посилання на той самий об’єкт. Ви можете застосувати той самий принцип до всіх непримітивних типів у C #.
UweB

В документи показують саме це , і пояснити «Наступний приклад створює XML - дерево, створює клон дерева, а потім викликає DeepEquals, який перевіряє , є чи два XML - дерева є рівними.» . У цьому прикладі вузол додається після виклику конструктора копіювання, і разом з DeepEqualsним показано, що два вузли тепер різні.
Абель

9

Схоже, метод ToString та reparse - найкращий спосіб. Ось код:

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

потім DstNode.Add (скопіювати), щоб додати його. Готово.
Fraga

4

Піднято безпосередньо з C # 3.0 в двох словах :

Коли вузол або атрибут додаються до елемента (будь то за допомогою функціональної конструкції або методу Add), властивість батьківського вузла або атрибута встановлюється для цього елемента. Вузол може мати лише один батьківський елемент: якщо ви додаєте вже батьківський вузол до другого батьківського, вузол автоматично глибоко клонується. У наступному прикладі кожен клієнт має окрему копію адреси:

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 тощо. Кращим способом є використання конструктора копіювання new XElement(original).
Абель

-3

Я не вірю, що існує існуючий механізм, який дозволяє виконувати глибоку копію дерева стилів XNode. Думаю, у вас залишилося два варіанти.

  1. Зробіть так, як ви запропонували, перетворити на рядок, а потім знову в дерево
  2. Напишіть на собі за шаблоном відвідувача

Шаблон відвідувача, безсумнівно, можливий, але для цього потрібно буде багато перевірити. Я думаю, що ваш найкращий варіант - No1.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.