C# 如何在C中按节点属性对XML文件排序
没有要求任何人为我编写此解决方案-只是寻找最佳方法的指导。我正在VS2015中使用C代码隐藏处理一个.aspx文件 我发现了无数解释如何对XML文件中的节点进行排序的线程。但是,我还没有找到任何关于如何根据公共子节点属性对具有相同结构的多个XML文件进行排序的线索 我的情况:我有一个包含数百个XML文件的目录,简单地说,从0001.XML到6400.XML。每个XML文件都具有相同的结构。我想根据子节点的属性对文件而不是节点进行排序 每个XML文件都有一个项父节点,还有子节点年份、语言和作者等。例如:C# 如何在C中按节点属性对XML文件排序,c#,asp.net,xml,visual-studio,C#,Asp.net,Xml,Visual Studio,没有要求任何人为我编写此解决方案-只是寻找最佳方法的指导。我正在VS2015中使用C代码隐藏处理一个.aspx文件 我发现了无数解释如何对XML文件中的节点进行排序的线程。但是,我还没有找到任何关于如何根据公共子节点属性对具有相同结构的多个XML文件进行排序的线索 我的情况:我有一个包含数百个XML文件的目录,简单地说,从0001.XML到6400.XML。每个XML文件都具有相同的结构。我想根据子节点的属性对文件而不是节点进行排序 每个XML文件都有一个项父节点,还有子节点年份、语言和作者等。
<item id="0001">
<year>2011</year>
<language id="English" />
<author sortby="Smith">John F. Smith</author>
<content></content>
</item>
如果我不想按0001到6400的顺序列出文件,而是想根据item/author节点的@sortby属性按字母顺序列出它们,我该怎么做
我的一个想法是创建一个临时XML文件,收集每个XML文件所需的信息。然后,我可以对临时XML文件进行排序,然后循环遍历节点,以正确的顺序显示文件。像这样的
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
这有意义吗?有更聪明的方法吗?编辑:现在我想起来了,您可能想要的是文件内容而不是文件名,如果是这样的话,您可以用包含文件内容的字符串集合替换本例中的items数组,并使用GetAuthor遍历该字符串并返回作者名 我认为最好的解决方案是将这些文件名添加到某种可以排序的集合中。这将获取您的文件名并将其添加到查找:
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<string, string> author in lookup)
{
foreach (string file in author)
{
Console.WriteLine(String.Format("{0}: {1}", author.Key, file ));
}
}
如果您决定根据多个条件对列表进行排序,则必须采用不同的方法创建自定义对象,将这些对象添加到列表中并使用自定义IComparer,但如果您只关心作者姓名,本示例将允许您避免所有这些。如果我正确理解您的意思,我会这样做:
SortedDictionary<string, string> dict = new SortedDictionary<string, string>();
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,文件名将按照字典功能进行排序。有两种方法可以按照XML文件节点的内部文本对XML文件的数据进行排序 使用Linq 您可以按childnode的元素将所有项加载到list和orderby。 您可以创建一个函数,其中一个参数是childnode的名称。 可以使用XSLT进行转换 有关更多详细信息,请参阅 希望能有帮助 您可以使用加载项并按以下方式对其排序:
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();
如果需要文件名,还可以选择包含文件名和项目的对象:
分类
我们可以用以下代码显示使用LINQ to 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中包含反xml
fileName属性,该属性包含XML文件的路径
假设目标目录中有以下xml文件:
0001.xml
这个代码的输出是:
文件名:c:\temp\teste\0002.xml
Xml内容:
2012
阿尔贝托·蒙泰罗
================
文件名:c:\temp\teste\0001.xml
Xml内容:
2011
约翰·F·史密斯
================
如您所见,XML 0002.XML出现在第一个位置,然后0001.XML文件是否包含多个项,是否要将项反序列化为对象以供以后使用?您可以使用加载所有项,然后仅使用linq对其排序。如果可以使用SQL Server,在数据库中存储项目比在文件系统中存储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);
<item id="0001">
<year>2011</year>
<language id="English" />
<author sortby="Smith">John F.Smith</author>
<content></content>
</item>
<item id="0002">
<year>2012</year>
<language id="Portuguese" />
<author sortby="Monteiro">Alberto Monteiro</author>
<content></content>
</item>
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("================");
}
}