在信息爆炸的时代,我们需要一种高效的方式来获取感兴趣的内容,并及时了解最新的动态。RSS和Atom订阅正是这样一种工具,它们允许我们订阅我们喜欢的网站、博客或新闻源,以便将最新的内容推送到我们的阅读器。本文将向您展示如何使用C#编程语言实现RSS和Atom订阅,帮助您更高效地阅读并获取所需信息。
下面正式开始订阅过程 (文章末尾附带完整代码):
- 引入命名空间和创建接口:
首先,在代码开头引入System.Xml命名空间,它提供了XML文档处理的相关类和方法。然后,定义一个接口IFeedParser,该接口包含一个Parse方法,用于解析订阅源并返回内容。
using System.Xml;
- 实现AtomFeedParser:
接下来,我们创建AtomFeedParser类,它实现了IFeedParser接口,并重写了Parse方法。在该方法中,我们使用HttpClient类来下载订阅源,并使用XmlDocument类加载XML文档。我们还使用XmlNamespaceManager类来处理XML命名空间,并使用XPath表达式选择所需的节点。然后,我们遍历每个节点,提取标题、链接、摘要、内容和发布时间等信息,并将其封装为FeedItem对象。最后,将所有的FeedItem对象添加到列表中,并返回该列表。
public class AtomFeedParser : IFeedParser
{
public async Task<List<FeedItem>> Parse(string url)
{
var feedItems = new List<FeedItem>();
var httpClient = new HttpClient();
var feed = await httpClient.GetStringAsync(url);
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(feed);
var nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
nsManager.AddNamespace("atom", "http://www.w3.org/2005/Atom");
var entries = xmlDoc.SelectNodes("//atom:entry", nsManager);
foreach (XmlNode entry in entries!)
{
var title = entry.SelectSingleNode("atom:title", nsManager)?.InnerText;
var link = entry.SelectSingleNode("atom:link", nsManager)?.Attributes!["href"]!.Value;
var summary = entry.SelectSingleNode("atom:summary", nsManager)?.InnerText;
var content = entry.SelectSingleNode("atom:content", nsManager)?.InnerText;
var published = entry.SelectSingleNode("atom:published", nsManager)?.InnerText;
feedItems.Add(new FeedItem
{
Title = title, Link = link, Content = content, Summary = summary, Published = published
});
}
return feedItems;
}
}
- 实现RssFeedParser:
类似地,我们创建RssFeedParser类,也实现了IFeedParser接口,并重写了Parse方法。在这个方法中,我们使用与AtomFeedParser类似的逻辑来解析RSS订阅源。
public class RssFeedParser : IFeedParser
{
public async Task<List<FeedItem>> Parse(string url)
{
var feedItems = new List<FeedItem>();
var httpClient = new HttpClient();
var feed = await httpClient.GetStringAsync(url);
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(feed);
var nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
nsManager.AddNamespace("rss", "http://rss2.org/schema/");
nsManager.AddNamespace("content", "http://purl.org/rss/1.0/modules/content/");
var entries = xmlDoc.SelectNodes("//rss/channel/item", nsManager);
foreach (XmlNode entry in entries!)
{
var title = entry.SelectSingleNode("./title", nsManager)?.InnerText;
var link = entry.SelectSingleNode("./link", nsManager)?.InnerText;
var summary = entry.SelectSingleNode("./description", nsManager)?.InnerText;
var content = entry.SelectSingleNode("./content:encoded", nsManager)?.InnerText;
var published = entry.SelectSingleNode("./pubDate", nsManager)?.InnerText;
feedItems.Add(new FeedItem
{
Title = title, Link = link, Content = content, Summary = summary, Published = published
});
}
return feedItems;
}
}
- 创建FeedItem类:
接下来,我们创建FeedItem类,用于表示订阅项的各个属性,如标题、链接、内容、摘要和发布时间。
public class FeedItem
{
public string? Title;
public string? Link;
public string? Content;
public string? Summary;
public string? Published;
}
- 创建辅助方法CreateFeedParser
private static IFeedParser CreateFeedParser(string type)
{
if (type.Contains("atom"))
return new AtomFeedParser();
else if (type.Contains("rss"))
return new RssFeedParser();
throw new ArgumentException("Invalid feed URL");
}
在这个辅助方法中,我们根据传入的类型参数选择创建适当的IFeedParser
实例,即AtomFeedParser
或RssFeedParser
。
- 编写主程序测试功能:
最后,我们在Main
方法中调用ParseFeed
方法,传入一个订阅源的URL。这里我们选择了一个示例URL(我的博客:https://shiyu.dev),并使用了RSS作为类型参数。然后,我们通过foreach
循环遍历返回的FeedItem
列表,并输出每个订阅项的标题。
public static class Program
{
private static IFeedParser CreateFeedParser(string type)
{
if (type.Contains("atom"))
return new AtomFeedParser();
else if (type.Contains("rss"))
return new RssFeedParser();
throw new ArgumentException("Invalid feed URL");
}
public static async Task Main()
{
var test = CreateFeedParser("rss");
var res = await test.Parse("https://shiyu.dev/rss/");
foreach (var item in res)
{
// 输出订阅到的标题
Console.WriteLine(item.Title);
}
}
}
至此,我们已经完成了使用C#实现RSS和Atom订阅的代码。
附带完整代码:
using System.Xml;
namespace CSharp
{
public interface IFeedParser
{
Task<List<FeedItem>> Parse(string url);
}
public class AtomFeedParser : IFeedParser
{
public async Task<List<FeedItem>> Parse(string url)
{
var feedItems = new List<FeedItem>();
var httpClient = new HttpClient();
var feed = await httpClient.GetStringAsync(url);
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(feed);
var nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
nsManager.AddNamespace("atom", "http://www.w3.org/2005/Atom");
var entries = xmlDoc.SelectNodes("//atom:entry", nsManager);
foreach (XmlNode entry in entries!)
{
var title = entry.SelectSingleNode("atom:title", nsManager)?.InnerText;
var link = entry.SelectSingleNode("atom:link", nsManager)?.Attributes!["href"]!.Value;
var summary = entry.SelectSingleNode("atom:summary", nsManager)?.InnerText;
var content = entry.SelectSingleNode("atom:content", nsManager)?.InnerText;
var published = entry.SelectSingleNode("atom:published", nsManager)?.InnerText;
feedItems.Add(new FeedItem
{
Title = title, Link = link, Content = content, Summary = summary, Published = published
});
}
return feedItems;
}
}
public class RssFeedParser : IFeedParser
{
public async Task<List<FeedItem>> Parse(string url)
{
var feedItems = new List<FeedItem>();
var httpClient = new HttpClient();
var feed = await httpClient.GetStringAsync(url);
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(feed);
var nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
nsManager.AddNamespace("rss", "http://rss2.org/schema/");
nsManager.AddNamespace("content", "http://purl.org/rss/1.0/modules/content/");
var entries = xmlDoc.SelectNodes("//rss/channel/item", nsManager);
foreach (XmlNode entry in entries!)
{
var title = entry.SelectSingleNode("./title", nsManager)?.InnerText;
var link = entry.SelectSingleNode("./link", nsManager)?.InnerText;
var summary = entry.SelectSingleNode("./description", nsManager)?.InnerText;
var content = entry.SelectSingleNode("./content:encoded", nsManager)?.InnerText;
var published = entry.SelectSingleNode("./pubDate", nsManager)?.InnerText;
feedItems.Add(new FeedItem
{
Title = title, Link = link, Content = content, Summary = summary, Published = published
});
}
return feedItems;
}
}
public class FeedItem
{
public string? Title;
public string? Link;
public string? Content;
public string? Summary;
public string? Published;
}
public static class Program
{
private static IFeedParser CreateFeedParser(string type)
{
if (type.Contains("atom"))
return new AtomFeedParser();
else if (type.Contains("rss"))
return new RssFeedParser();
throw new ArgumentException("Invalid feed URL");
}
public static async Task Main()
{
var test = CreateFeedParser("rss");
var res = await test.Parse("https://shiyu.dev/rss/");
foreach (var item in res)
{
// 输出订阅到的标题
Console.WriteLine(item.Title);
}
}
}
}