【问题标题】:Having trouble sorting an Xelement with LINQ使用 LINQ 对 Xelement 进行排序时遇到问题
【发布时间】:2021-04-27 21:35:51
【问题描述】:

我正在尝试按优先级节点对下面的 XML 进行排序,因此 1.0 是最高的,然后它们紧随其后。但是我尝试的一切都不会返回任何东西。这是我的代码,第一个块是我所做的尝试,它只是空的,第二个块是我的内联尝试,它返回一个空引用。

第一:

 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;

第二:

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

文档:

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

【问题讨论】:

  • 如果你在没有排序的情况下运行你的代码会返回任何东西吗?

标签: c# linq xelement


【解决方案1】:

您应该将持久化数据(存储)的过程与处理数据的过程分开。这使您的代码:

  • 更容易理解,因为程序更小
  • 更易于重用,因为如果数据不是来自 XML,而是来自 JSON 或数据库,您可以使用相同的数据处理 - 更容易更改:如果您想以不同的格式保存数据,例如 JSON 或 CSV,则无需更改 LINQ 部分
  • 更容易进行单元测试:您可以测试存储/检索数据而无需担心 LINQ 部分:如果您将来更改 LINQ(例如降序或按不同列排序),则无需更改关于持久性的单元测试。

(我不确定您的 XML 中有什么,在其余的答案中,我将称之为UrlModifications)

所以你需要两个单独的代码部分,甚至可能是单独的类:

  • 从 XML 文件中读取数据并将其转换为UrlModifications 序列的部分。类似:将UrlModifications 的序列存储在 XML 文件中。可能的扩展:从Stream 读/写。
  • 采用UrlModifications 序列并按优先级降序排列的部件。

是否值得为此创建单独的类,取决于您是否认为有人可能想要重用此代码或更改它,或者您是否想为其编写单元测试等。

读取/写入文件的 UrlModifications

首先是 UrlModification 类。我认为它会是这样的:

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

FrequencyDescription 是一个枚举。您可以将其更改为字符串,如果有人键入不受支持的值,这可能会出现问题。如果您不想受到 daily / hourly / weekly / ... 等值的限制,请考虑使用 TimeSpan。 Daily 将替换为 24 小时。无论如何,您都需要一个转换方法,因为要对这个值做任何事情,您需要将单词 Daily 转换为 TimeSpan 24 hours。

要读取并将其写入文件,我将创建一个存储库类(仓库意义上的存储库:您将项目存储在其中,然后您可以从中检索相同的项目,即使您已重新启动程序。

为了使这个类更加可重用,我不仅将它保存到一个文件中,还将它保存到一个 Stream 和一个 TextReader / TextWriter 中。这也将使单元测试更容易

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

Stream 的方法类似。

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

这隐藏了您加载/保存项目的格式。您可以将其更改为 JSON 格式,甚至 CSV。用户(=软件,而不是操作员)不会注意到差异。

如果您对此进行单元测试,您会发现 XML 格式与您的格式不完全相同。修复此问题的最简单方法是将 XML 属性添加到您的类:

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

你可能比我更了解 XML,所以我想你会明白其中的要点。

订购网址

我正在尝试按优先级节点对下面的 XML 进行排序,因此 1.0 是最高的,然后它们紧随其后。

一旦您创建了存储库,这将非常容易:

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

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

结论

通过将数据的存储方式与数据处理分开,您使代码更易于理解和单元测试。该代码具有高度的可重用性和可变性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多