I have an XML file like this:
<file name="picture1.jpg"/>
<file name="file1.txt"/>
<folder name="subfolder">
<file name="picture2.jpg"/>
<file name="file2.txt"/>
<folder name="anotherfolder">
<file name="file3.txt"/>
</folder>
</folder>
<folder name="anotherfolder">
</folder>
It needs to be sorted like this:
<folder name="anotherfolder">
</folder>
<file name="file1.txt"/>
<file name="picture1.jpg"/>
<folder name="subfolder">
<folder name="anotherfolder">
<file name="file3.txt"/>
</folder>
<file name="file2.txt"/>
<file name="picture2.jpg"/>
</folder>
The code I have to sort is:
public static XDocument Sort(XDocument file)
{
return new XDocument(Sort(file.Root));
}
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;
}
It does the job...but only partly. It sorts FILE based on name attribute separately from FOLDER. I would like them to be considered together for the sorted xml. What should be done?
Actually this code does not order child elements by name attribute; it sorts by element name:
orderby child.Name.ToString()
What you need to do is get the value of the "name" attribute (case sensitive!) instead. This is possible with child.Attribute("name")
, but you need to get the .Value
of this while watching out for null
attributes; the code is going to be slightly awkward to write inline.
Personally I find this version with child.Attributes
(that returns a collection) more convenient:
orderby child.Attributes("name").Select(a => a.Value).FirstOrDefault()