Sorting all the elements in a XDocument

You already have a method to sort the elements. Just apply it recursively:

private static XElement Sort(XElement element)
{
    return new XElement(element.Name,
            from child in element.Elements()
            orderby child.Name.ToString()
            select Sort(child));
}

private static XDocument Sort(XDocument file)
{
    return new XDocument(Sort(file.Root));
}

Note that this strips all non-element nodes (attributes, text, comments, etc.) from your document.


If you want to keep the non-element nodes, you have to copy them over:

private static XElement Sort(XElement element)
{
    return new XElement(element.Name,
            element.Attributes(),
            from child in element.Nodes()
            where child.NodeType != XmlNodeType.Element
            select child,
            from child in element.Elements()
            orderby child.Name.ToString()
            select Sort(child));
}

private static XDocument Sort(XDocument file)
{
    return new XDocument(
            file.Declaration,
            from child in file.Nodes()
            where child.NodeType != XmlNodeType.Element
            select child,
            Sort(file.Root));
}

THIS METHOD MAKES A REAL DOCUMENT EXTENSION AND PRESERVES THE ATTRIBUTES AND TEXT VALUES

I came up with this based off a few different posts and code from here and there... Thanks to all who contributed!

Within the same namespace (not the same class) add the following...

public static void Sort(this XElement source, bool bSortAttributes = true)
{
    //Make sure there is a valid source
    if (source == null) throw new ArgumentNullException("source");

    //Sort attributes if needed
    if (bSortAttributes)
    {
        List<XAttribute> sortedAttributes = source.Attributes().OrderBy(a => a.ToString()).ToList();
        sortedAttributes.ForEach(a => a.Remove());
        sortedAttributes.ForEach(a => source.Add(a));
    }

    //Sort the children IF any exist
    List<XElement> sortedChildren = source.Elements().OrderBy(e => e.Name.ToString()).ToList();
    if (source.HasElements)
    {
        source.RemoveNodes();
        sortedChildren.ForEach(c => c.Sort(bSortAttributes));
        sortedChildren.ForEach(c => source.Add(c));
    }
}

To use the document extension...

//Load the xDoc
XDocument xDoc = XDocument.Load("c:\test.xml");

//Sort the root element
xDoc.Root.Sort();

Here is an updated example that will include all attributes when performing the sort.

private static XElement Sort(XElement element)
{
    XElement newElement = new XElement(element.Name,
        from child in element.Elements()
        orderby child.Name.ToString()
        select Sort(child));
    if (element.HasAttributes)
    {
        foreach (XAttribute attrib in element.Attributes())
        {
            newElement.SetAttributeValue(attrib.Name, attrib.Value);
        }
    }
    return newElement;
}

private static XDocument Sort(XDocument file)
{
    return new XDocument(Sort(file.Root));
}

This post helped me a lot, because I did not want to perform an XML sort using XSLT since I did not want to reformat the XML. I searched all around for a simple solution to perform an XML sort using C# and ASP.NET and I was delighted when I found this thread. Thanks to all, this did exactly what I needed.