LINQ to XML XElement のディープ コピーを作成したいと考えています。これを行う理由は、(同じドキュメント内に) 変更されたコピーを作成したいノードがドキュメント内にあるためです。これを行う方法がわかりません。
要素を XML 文字列に変換して再解析することもできますが、もっと良い方法はないかと考えています。
LINQ to XML XElement のディープ コピーを作成したいと考えています。これを行う理由は、(同じドキュメント内に) 変更されたコピーを作成したいノードがドキュメント内にあるためです。これを行う方法がわかりません。
要素を XML 文字列に変換して再解析することもできますが、もっと良い方法はないかと考えています。
再解析する必要はありません。XElement のコンストラクターの 1 つは、別の 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);
}
ToString と reparse メソッドが最善の方法のようです。コードは次のとおりです。
XElement copy = XElement.Parse(original.ToString());
一言で言えば、C#3.0から直接持ち上げた:
ノードまたは属性が要素に追加されると (機能構築または Add メソッドを介して)、ノードまたは属性の Parent プロパティがその要素に設定されます。ノードは 1 つの親要素のみを持つことができます。既に親になっているノードを 2 番目の親に追加すると、ノードは自動的にディープ クローンされます。次の例では、顧客ごとに個別の住所のコピーがあります。
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() );
XNode スタイル ツリーのディープ コピーを実行できる既存のメカニズムがあるとは思えません。あなたには2つの選択肢が残っていると思います。
訪問者パターンは確かに可能ですが、テストにはかなりの作業が必要です。あなたの最良の選択肢は#1だと思います。