So recently I was dealing with an internal program that was easily confused and would create XML files with the elements in the wrong order for the schemas used in other internal programs that read these Xml files.  I started looking for a fast way to reorder these elements and found this forum post which while on the right track was a bit more complicated than I really needed.  So I came up with this solution.

 

Bad File Good File
<data name="ConfigName">
  <One>Item One</One>
  <Three>
    <A>Item A</A>
    <C>Item C</C>
    <C>Item C-2</C>
    <B>Item B</B>
  </Three>
  <Two>Item Two</Two>
</data>
<data name="ConfigName">
  <One>Item One</One>
  <Two>Item Two</Two>
  <Three>
    <A>Item A</A>
    <B>Item B</B>
    <C>Item C</C>
    <C>Item C-2</C>
  </Three>
</data>

 

Reorder Solution

string[] rootOrder = new string[] { "One", "Two", "Three" };
string[] threeOrder = new string[] { "A", "B", "C" };
          
XDocument xdoc = XDocument.Load("file.xml");
Reorder(xdoc, rootOrder);
Reorder(xdoc.Root.Elements("Three"), threeOrder);

void Reorder(XDocument xdoc, params string[] order)
{
  xdoc.Root.ReplaceWith(Reorder(xdoc.Root, order));
}

void Reorder(IEnumerable<XElement> els, params string[] order)
{
  foreach (XElement el in els.ToArray())
    el.ReplaceWith(Reorder(el, order));
}

XElement Reorder(XElement root, params string[] order)
{
  return new XElement(root.Name,
                      from el in order
                      select root.Elements(el),
                      root.Attributes());
}

For those needing VB.NET

Module Module1

    Sub Main()
        Dim rootOrder() As String = {"One", "Two", "Three"}
        Dim threeOrder() As String = {"A", "B", "C"}

        Dim xdoc As XDocument = XDocument.Load("file.xml")

        Reorder(xdoc, rootOrder)
        Reorder(xdoc.Root.Elements("Three"), threeOrder)

        xdoc.Save("good.xml")
    End Sub

Private Sub Reorder(ByVal xdoc As XDocument, ByVal ParamArray order() As String)
        xdoc.Root.ReplaceWith(Reorder(xdoc.Root, order))
    End Sub

Private Sub Reorder(ByVal els As IEnumerable(Of XElement), ByVal ParamArray order() As String)
        For Each el As XElement In els.ToArray()
            el.ReplaceWith(Reorder(el, order))
        Next
    End Sub

Private Function Reorder(ByVal root As XElement, ByVal order As String()) As XElement
        Return New XElement(root.Name,
                         (From el In order
                         Let x As IEnumerable(Of XElement) = root.Elements(el)
                         Select x), root.Attributes())
    End Function
End Module