如何按C#中的节点属性对XML文件进行排序

不要求任何人为我编写这个解决方案 – 只需寻找最佳方法的指导。 我正在使用C#代码在VS2015中处理.aspx文件。

我发现无数线程解释了如何在XML文件中对节点进行排序。 但是,根据常见的子节点属性,我还没有找到关于如何使用相同结构对多个XML文件进行排序的任何线程。

我的情况:我有一个名为0001.xml到6400.xml的数百个XML文件的目录。 每个XML文件都具有相同的结构。 我想根据子节点的属性对文件(而不是节点)进行排序。

每个XML文件都有一个“项目”父节点,并且具有子节点“年”,“语言”和“作者”等。 例如:

 2011  John F. Smith   

如果我不是按照0001到6400的顺序列出文件,而是根据项目/作者节点的@sortby属性按字母顺序列出它们,我该怎么做?

我的一个想法是创建一个临时XML文件,收集每个XML文件所需的信息。 然后,我可以对临时XML文件进行排序,然后循环遍历节点以按正确的顺序显示文件。 这样的东西……

 XDocument tempXML = new XDocument(); // add parent node of  string[] items = Directory.GetFiles(directory) foreach (string item in items) { // add child node of  with attributes "filename", "year", "language", and "author" } // then sort the XML nodes according to attributes 

这有意义吗? 有更聪明的方法吗?

排序

我们可以使用以下代码显示使用一些LINQ到Xml排序的xml文件:

 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); 

xmlsWithFileName的每个元素都有

  • xml属性,包含XDocument中的de XML
  • fileName属性,包含XML文件的路径

假设在目标目录中有这个xml文件:

0001.xml

  2011  John F.Smith   

0002.xml

  2012  Alberto Monteiro   

您可以使用此代码进行测试

 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("================"); } } 

这段代码的输出是:

 Filename: c:\temp\teste\0002.xml Xml content:  2012  Alberto Monteiro   ================ Filename: c:\temp\teste\0001.xml Xml content:  2011  John F.Smith   ================ 

如您所见, XML 0002.xml出现在第一个位置 ,然后出现在 0001.xml中

编辑:现在我考虑一下,你可能想要文件内容而不是文件名,如果是这样的话,你可以用这个例子中的“items”数组替换包含文件内容和使用的字符串集合GetAuthor遍历该字符串并返回作者姓名。

我认为最好的解决方案是将这些文件名添加到可以排序的某种集合中。 这将获取您的文件名并将其添加到Lookup:

 var lookup = items.ToLookup(a => GetAuthor(a)).OrderBy(a => a.Key); 

这将依赖于使用文件名获取作者姓名的方法:

 private string GetAuthor(string filename) { string author = String.Empty; // get author name logic return author; } 

最后,通过您的列表进行交流:

 foreach (IGrouping author in lookup) { foreach (string file in author) { Console.WriteLine(String.Format("{0}: {1}", author.Key, file )); } } 

如果您决定要根据多个条件对列表进行排序,则必须采用不同的方法并创建自定义对象,将其添加到列表中并使用自定义IComparer,但此示例将允许您避免如果你只关心作者的名字那么多。

如果我理解你说的正确,我就会这样做:

 SortedDictionary dict = new SortedDictionary(); var files = Directory.GetFiles(@"[path to files]", "*.xml"); foreach (var item in files) { XDocument doc = XDocument.Load(item); var sortvalue = (from lv1 in doc.Descendants("somesortvalue") select lv1.Value).First(); dict.Add(sortvalue, item); } 

然后你可以在dict.keys上做一个foreach,文件名将按字典function排序。

有两种方法可以通过它的节点的InnerText对XML文件的数据进行排序

  1. 使用Linq您可以通过Elementnode的元素加载所有Item to list和orderby。 您可以创建一个函数,其中一个para是childnode的名称来执行此操作。
  2. 您可以使用XSLT进行转换

有关更多详细信息,请参阅XMLElement的InnerText对XML文件进行排序

希望它有所帮助!

您可以使用XElement加载项目并按以下方式对它们进行排序:

 var items = System.IO.Directory.GetFiles(@"path", "*.xml") .Select(file => System.Xml.Linq.XElement.Load(file)); .OrderBy(x => x.Element("author").Attribute("sortby").Value) .ToList(); 

此外,如果需要文件名,可以选择包含FileNameItem:的对象Item:

 var items = System.IO.Directory.GetFiles(@"path", "*.xml") .Select(file => new { FileName = file, Item = System.Xml.Linq.XElement.Load(file) }) .OrderBy(x => x.Item.Element("author").Attribute("sortby").Value) .Select(x=>x.FileName) /*or .Select(x=>x.Item)*/ .ToList();