Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort XML files by a node attribute in C#

Not asking for anyone to code this solution for me - just looking for guidance on the best approach. I'm working on an .aspx file in VS2015 using C# code behind.

I've found countless threads explaining how to sort nodes within an XML file. But, I have not found any threads on how to sort multiple XML files with the same structure, according to a common child node attribute.

My situation: I have a directory of hundreds of XML files named, simply, 0001.xml through 6400.xml. Each XML file has the same structure. I want to sort the files (not the nodes) according to the attribute of a child node.

Each XML file has an "item" parent node and has child nodes "year", "language", and "author", among others. For example:

<item id="0001">
   <year>2011</year>
   <language id="English" />
   <author sortby="Smith">John F. Smith</author>
   <content></content>
</item>

If, instead of listing the files in order 0001 thru 6400, I instead want to list them in alphabetical order according to the item/author node's @sortby attribute, how would I do that?

One idea that I had was to create a temporary XML file that gathers the information needed from each XML file. Then, I can sort the temporary XML file and then loop through the nodes to display the files in the proper order. Something like this...

XDocument tempXML = new XDocument();
// add parent node of <items>

string[] items = Directory.GetFiles(directory)
foreach (string item in items)
{
   // add child node of <item> with attributes "filename", "year", "language", and "author"
}

// then sort the XML nodes according to attributes

Does this make sense? Is there a smarter way to do this?

like image 691
TJM Avatar asked Jan 06 '23 22:01

TJM


1 Answers

Sorting

We can show xml files sorted using a bit of LINQ to Xml, with this following code:

var xmlsWithFileName = Directory.GetFiles(directory)
                                .Select(fileName => new { fileName, xml = XDocument.Parse(File.ReadAllText(fileName)) })
                                .OrderBy(tuple => tuple.xml.Element("item").Element("author").Attribute("sortby").Value);

Each element of xmlsWithFileName will have

  • xml property, that contains de XML in XDocument
  • fileName property, that contains the path of the XML file

Assuming that in your target directory you have this xml files:

0001.xml

<item id="0001">
   <year>2011</year>
   <language id="English" />
   <author sortby="Smith">John F.Smith</author>
   <content></content>
</item>

0002.xml

<item id="0002">
   <year>2012</year>
   <language id="Portuguese" />
   <author sortby="Monteiro">Alberto Monteiro</author>
   <content></content>
</item>

You can use this code to test

public static void ShowXmlOrderedBySortByAttribute(string directory)
{
    var xmlsWithFileName = Directory.GetFiles(directory)
                                    .Select(fileName => new { fileName, xml = XDocument.Parse(File.ReadAllText(fileName)) })
                                    .OrderBy(tuple => tuple.xml.Element("item").Element("author").Attribute("sortby").Value);

    foreach (var xml in xmlsWithFileName)
    {
        Console.WriteLine($"Filename: {xml.fileName}{Environment.NewLine}Xml content:{Environment.NewLine}");
        Console.WriteLine(xml.xml.ToString());
        Console.WriteLine("================");
    }
}

And the output of this code is:

Filename: c:\temp\teste\0002.xml
Xml content:

<item id="0002">
  <year>2012</year>
  <language id="Portuguese" />
  <author sortby="Monteiro">Alberto Monteiro</author>
  <content></content>
</item>
================
Filename: c:\temp\teste\0001.xml
Xml content:

<item id="0001">
  <year>2011</year>
  <language id="English" />
  <author sortby="Smith">John F.Smith</author>
  <content></content>
</item>
================

As you can see, the XML 0002.xml appear in first position, then the 0001.xml

like image 50
Alberto Monteiro Avatar answered Jan 15 '23 22:01

Alberto Monteiro