Welcome to MSDN Blogs Sign in | Join | Help
Manually Cloning LINQ to XML Trees

[Blog Map]

(July 1, 2009 - Updated - OK to normalize empty elements to an element with a self-closing tag.) 

There are a variety of circumstances where you want to clone a LINQ to XML tree while making modifications to the cloned tree.  It’s possible to write a very small amount of recursive code to do this.  I’ve posted elsewhere about normalizing a LINQ to XML tree, and in that post, I use the coding approach that I present here.

You can, of course, clone an XML tree using the XElement or XDocument constructors, however you have no control over the cloning process.

The gist of the technique is to write a recursive function that clones an element.  In its simplest form, here is the code to clone a tree:

static XElement CloneElement(XElement element)

{

    return new XElement(element.Name,

        element.Attributes(),

        element.Nodes().Select(n =>

            {

                XElement e = n as XElement;

                if (e != null)

                    return CloneElement(e);

                return n;

            }

        )

    );

}

 

static void Main(string[] args)

{

    XElement root = new XElement("Root",

        new XAttribute("a", 1),

        new XElement("Child", 1),

        new XElement("Child", 2),

        new XComment("This is a comment.")

    );

 

    XElement root2 = CloneElement(root);

    Console.WriteLine(root);

    Console.WriteLine("==========");

    Console.WriteLine(root2);

    Console.WriteLine();

}

 

The default behavior of CloneElement is to normalize an empty element (<Tag></Tag>) to a self-closing element (<Tag/>).  This is correct behavior - the XML specification basically states that the two forms of markup are equivalent.  Further, if an element is declared to be EMPTY, only a self-closing tag will do, whereas any empty element can be converted to a self-closing tag, so it's always safe to convert to self-closing.  This is the default behavior of LINQ to XML.

We can modify the CloneElement method to customize the cloned tree.  If, say, we want to remove all namespace attributes and remove all comment nodes, we can write it like this:

static XElement CloneElement(XElement element)

{

    return new XElement(element.Name,

        element.Attributes().Where(a => !a.IsNamespaceDeclaration),

        element.Nodes().Select(n =>

        {

            if (n is XComment)

                return null;

            XElement e = n as XElement;

            if (e != null)

                return CloneElement(e);

            return n;

        }

        )

    );

}

 

static void Main(string[] args)

{

    XNamespace aw = "http://www.adventureworks.com";

    XElement root = new XElement(aw + "Root",

        new XAttribute(XNamespace.Xmlns + "aw", aw.NamespaceName),

        new XAttribute("a", 1),

        new XElement(aw + "Child", 1),

        new XElement(aw + "Child", 2),

        new XComment("This is a comment.")

    );

 

    XElement root2 = CloneElement(root);

    Console.WriteLine(root);

    Console.WriteLine("==========");

    Console.WriteLine(root2);

}

 

This produces the following output:

<aw:Root xmlns:aw="http://www.adventureworks.com" a="1">

  <aw:Child>1</aw:Child>

  <aw:Child>2</aw:Child>

  <!--This is a comment.-->

</aw:Root>

==========

<Root a="1" xmlns="http://www.adventureworks.com">

  <Child>1</Child>

  <Child>2</Child>

</Root>

Posted: Wednesday, January 28, 2009 12:33 AM by EricWhite

Comments

Pavel Minaev [MSFT] said:

I always wondered why the standard XLINQ API doesn't have some sort of visitor for creating a new tree from the old one. With that, and some creative use of predicates, I think we could actually get almost on par with XSLT for tree rewriting (I still prefer it to XLINQ because of the conciseness and clarity of XSLT transforms which only need to modify a few specific nodes out of many).

By the way, I've posted here under the alias 'int19h' previously. Now it's new job, new email, and new blog account :)

# January 30, 2009 7:47 PM

Microsoft XML Team's WebLog said:

In certain scenarios, it is important to be able to compare two XML trees for equivalence. For example,

# February 16, 2009 1:37 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker