Empty Elements and Self-Closing Tags

Last January, I blogged about an approach to normalizing LINQ to XML trees.  That post is based on another post, Manually Cloning LINQ to XML Trees.  In those posts, my code to clone an element would clone a self-closing element (<Tag/>) as self-closing, and an empty element with a start and end tag (<Tag></Tag>) as an element with start and end tag.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOCBut, in fact, this was not necessary – empty elements can be always serialized as self-closing elements – the XML specification states, “The representation of an empty element is either a start-tag immediately followed by an end-tag, or an empty-element tag."

Further, per the specification, “the empty-element tag SHOULD be used, and SHOULD only be used, for elements which are declared EMPTY”.  This means that it’s always safe to serialize an empty element as a self-closing element, but sometimes it’s not correct to serialize an empty element with a start and end tag.

Originally, the code to clone an element looked like this:

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;
}),
(!element.IsEmpty && !element.Nodes().OfType<XText>().Any()) ? "" : null
);
}

I’ve revised both of the above referenced posts to remove the code to exactly serialize empty elements as they were in the source document.  The new code looks like this:

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 = XElement.Parse("<Root></Root>");
Console.WriteLine("Original tree");
Console.WriteLine(root);
Console.WriteLine();
Console.WriteLine("Cloned tree");
XElement rootClone = CloneElement(root);
Console.WriteLine(rootClone);
}

The code is simpler and more correct.  When you run this example, it produces:

Original tree
<Root></Root>

Cloned tree
<Root />

Thanks to Sean Hederman for pointing this out.