简体   繁体   English

使用 LINQ 对 Xelement 进行排序时遇到问题

[英]Having trouble sorting an Xelement with LINQ

I am trying to sort my XML below by the priority node, so the 1.0 is the highest and then they follow after.我正在尝试按优先级节点对下面的 XML 进行排序,因此 1.0 是最高的,然后它们紧随其后。 However everything I try wont return anything.但是我尝试的一切都不会返回任何东西。 Here is my code, the first chunk was a try I did that is just empty, the second chunk is my inline try that returns a null reference.这是我的代码,第一个块是我所做的尝试,它只是空的,第二个块是我的内联尝试,它返回 null 引用。

First:第一的:

 XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
            IEnumerable<XElement> list =
                from el in xelementList1.Elements(ns + "url")
                let priority = (int)el.Element(ns + "priority")
                orderby priority descending
                select el;

Second:第二:

XDocument xdocument = this.BuildXmlDocument((IEnumerable<XElement>)xelementList1.OrderByDescending(x => x.Element("priority")?.Value));

Document:文档:

<urlset xmlns:xhtml="http://www.w3.org/1999/xhtml" 
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https:///</loc>
<lastmod>2021-03-15</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https:///404/</loc>
<lastmod>2021-04-22</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https:///500/</loc>
<lastmod>2021-04-22</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https:///avalon-brochures/</loc>
<lastmod>2021-04-27</lastmod>
<changefreq>daily</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https:///contact-us/</loc>
<lastmod>2021-04-27</lastmod>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https:///cors-test/</loc>
<lastmod>2021-03-15</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>

You should separate the process of persisting your data (storage) from the process of handling the data.您应该将持久化数据(存储)的过程与处理数据的过程分开。 This makes your code:这使您的代码:

  • easier to understand, because procedures are smaller更容易理解,因为程序更小
  • easier to reuse, because you could use the same data handling if the data didn't come from XML, but for instance from JSON or a database -easier to change: if you want to persist the data in a different format, for instance JSON, or CSV, you won't have to change the LINQ parts更易于重用,因为如果数据不是来自 XML,但例如来自 JSON 或数据库,您可以使用相同的数据处理 - 更容易更改:如果您想以不同的格式保存数据,例如 Z0ECD11C1D1D748A , 或 CSV,您不必更改 LINQ 零件
  • Easier to unit test: you can test storing / retrieving your data without worrying about the LINQ parts: if in future you change the LINQ (for instance descending order, or order by different column), you won't have to change the unit tests about persistency.更容易进行单元测试:您可以测试存储/检索数据而无需担心 LINQ 部件:如果将来您更改 LINQ(例如降序或按不同列排序),您将不必更改单元测试关于持久性。

(I'm not sure what's in your XML, In the rest of the answer I'll call this UrlModifications ) (我不确定您的 XML 中有什么,在答案的 rest 中我称之为UrlModifications

So you need two separate parts of code, maybe even separate classes:所以你需要两个单独的代码部分,甚至可能是单独的类:

  • A part that reads the data from an XML file and converts it into a sequence of UrlModifications .从 XML 文件中读取数据并将其转换为UrlModifications序列的部件。 Similar: store a sequence of UrlModifications in an XML file.类似:将一系列UrlModifications存储在 XML 文件中。 Possible extensions: read/write from a Stream .可能的扩展:从Stream读/写。
  • A part that takes a sequence of UrlModifications and orders them by descending priority.采用一系列UrlModifications并按优先级降序排列它们的部分。

Whether it is worth to make separate classes for this, depends on whether you think someon might want to reuse this code, or change it, or whether you want to write unit tests for it, etc.是否值得为此创建单独的类,取决于您是否认为某人可能想要重用此代码或更改它,或者您是否想为它编写单元测试等。

Read/Write UrlModifications to a file读/写 UrlModifications 到文件

First the class UrlModification.首先是class UrlModification。 I think it will be something like this:我认为它会是这样的:

class UrlModification
{
    public string Location {get; set;}
    public DateTime LastModifiedDate {get; set; }
    public FrequencyDescription ChangeFrequency {get; set;}
    public decimal Priority {get; set;}
}

FrequencyDescription is an enum. FrequencyDescription 是一个枚举。 You can change it to a string, which might give problems if someone types un unsupported value.您可以将其更改为字符串,如果有人键入不受支持的值,这可能会出现问题。 If you don't want to be limited by values like daily / hourly / weekly /... , consider to use a TimeSpan.如果您不想受到daily / hourly / weekly /...等值的限制,请考虑使用 TimeSpan。 Daily will be replaced by 24 hours. Daily将改为 24 小时。 You will need a conversion method anyway, because to do anything with this value, you'll need to convert the word Daily into TimeSpan 24 hours .无论如何,您将需要一个转换方法,因为要使用此值执行任何操作,您需要将单词Daily转换为TimeSpan 24 hours

To Read and Write this to a file, I'll create a repository class (Repository in the sense of a warehouse: you store items in it, and later you can retrieve the same item from it, even if you have restarted the program.要读取并将其写入文件,我将创建一个存储库 class(仓库意义上的存储库:您将项目存储在其中,然后您可以从中检索相同的项目,即使您已重新启动程序。

To make the class a bit more reusable, I will not only save it to a file, but also to a Stream and a TextReader / TextWriter.为了使 class 更具可重用性,我不仅将其保存到文件中,还将保存到 Stream 和 TextReader / TextWriter 中。 This will also make the unit test easier这也将使单元测试更容易

class UrlModificationRepository
{
    public IList<UrlModifiction> Load(string fileName)
    {
        using (var textReader = File.OpenText(fileName))
        {
            return Load(textReader);
        }
    }

    public IList<UrlModification> Load(System.IO.TextReader textReader)
    {
        return (UrlModification[]) serializer.Deserialize(textReader);
    }
}

The method for a Stream is similar. Stream 的方法类似。

The Save methods are also one-liners: Save 方法也是单行的:

public void Save(string fileName, IEnumerable<UrlModification> urlModifications)
{
    using (var textWriter = File.CreateText(fileName))
    {
        this.Save(textWriter, urlModifications);
    }
}

public void Save(TextWriter textWriter, IEnumerable<UrlModification> urlModifications)
{
    serializer.Serialize(textWriter, urlModifications.ToArray());
}

This has hidden the format in which you load / save items.这隐藏了您加载/保存项目的格式。 You can change it in JSON format, or even CSV.您可以将其更改为 JSON 格式,甚至 CSV。 Users (=software, not operators) won't notice the difference.用户(=软件,而不是操作员)不会注意到差异。

If you unit test this, you will see that the XML format is not exactly the same format as yours.如果您对此进行单元测试,您将看到 XML 格式与您的格式不完全相同。 The easiest way to repair this is to add XML attributes to your class:修复此问题的最简单方法是将 XML 属性添加到 class 中:

public class UrlModification
{
    [XmlElement("Loc")]
    public string Location { get; set; }

    [XmlElement("LastMod", DataType = "date")]
    public DateTime LastModifiedDate { get; set; }
    public FrequencyDescription ChangeFrequency { get; set; }
    public decimal Priority { get; set; }
}

You probably know XML better than I do, so I guess you'll get the gist.你可能比我更了解 XML,所以我想你会明白要点的。

Order the URL订购 URL

I am trying to sort my XML below by the priority node, so the 1.0 is the highest and then they follow after.我正在尝试按优先级节点对下面的 XML 进行排序,因此 1.0 是最高的,然后它们紧随其后。

Once you've created the repository, this will be very easy:创建存储库后,这将非常容易:

string fileName = ...
UrlModificationRepository repository = new UrlModidificationRepository();

var urlsOrderedByDescendingPriority = repository.Load(fileName)
    .OrderByDescending(urlModification => urlModification.Priority);

Conclusion结论

By separating how the data is stored from the data processing, you made the code easier to understand and unit test.通过将数据的存储方式与数据处理分开,您使代码更易于理解和单元测试。 The code is highly reusable and changeable.该代码具有高度可重用性和可变性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM