۱۳۸۸/۰۵/۲۳

استفاده از LINQ to XML جهت خواندن فيدهاي RSS


مثال زير را به عنواني نمونه‌اي از كاربرد LINQ to XML براي خواندن فيدهاي RSS كه اساسا به فرمت XML هستند مي‌توان ارائه داد.
ابتدا كد كامل مثال را در نظر بگيريد:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace LinqToRSS
{
public static class LanguageExtender
{
public static string SafeValue(this XElement input)
{
return (input == null) ? string.Empty : input.Value;
}

public static DateTime SafeDateValue(this XElement input)
{
return (input == null) ? DateTime.MinValue : DateTime.Parse(input.Value);
}
}

public class RssEntry
{
public string Title { set; get; }
public string Description { set; get; }
public string Link { set; get; }
public DateTime PublicationDate { set; get; }
public string Author { set; get; }
public string BlogName { set; get; }
public string BlogAddress { set; get; }
}

public class Rss
{
static XElement selectDate(XElement date1, XElement date2)
{
return date1 ?? date2;
}

public static List<RssEntry> GetEntries(string feedUrl)
{
//applying namespace in an XElement
XName xn = XName.Get("{http://purl.org/dc/elements/1.1/}creator");//{namespace}root
XName xn2 = XName.Get("{http://purl.org/dc/elements/1.1/}date");

var feed = XDocument.Load(feedUrl);
if (feed.Root == null) return null;

var items = feed.Root.Element("channel").Elements("item");
var feedQuery =
from item in items
select new RssEntry
{
Title = item.Element("title").SafeValue(),
Description = item.Element("description").SafeValue(),
Link = item.Element("link").SafeValue(),
PublicationDate =
selectDate(item.Element(xn2), item.Element("pubDate")).SafeDateValue(),
Author = item.Element(xn).SafeValue(),
BlogName = item.Parent.Element("title").SafeValue(),
BlogAddress = item.Parent.Element("link").SafeValue()
};

return feedQuery.ToList();
}
}

class Program
{
static void Main(string[] args)
{
List<RssEntry> entries = Rss.GetEntries("http://weblogs.asp.net/aspnet-team/rss.aspx");
if (entries != null)
foreach (var item in entries)
Console.WriteLine(item.Title);

Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}

توضيحات:
1- در اين مثال فقط جهت سهولت بيان آن در يك صفحه، تمامي كلاس‌هاي تعريف شده در يك فايل آورده شدند. اين روش صحيح نيست و بايد به ازاي هر كلاس يك فايل جدا در نظر گرفته شود.
2- كلاس LanguageExtender از قابليت extension methods سي شارپ 3 استفاده مي‌كند. به اين صورت كلاس XElement دات نت بسط يافته و دو متد به آن اضافه مي‌شود كه به سادگي در كدهاي خود مي‌توان از آن‌ها استفاده كرد. هدف آن هم بررسي نال بودن يك آيتم دريافتي و ارائه‌ي حاصلي امن براي اين مورد است.
3- كلاس RssEntry به جهت استفاده در خروجي كوئري LINQ تعريف شد. مي‌خواهيم خروجي نهايي، يك ليست جنريك از نوع RssEntry باشد.
4- متد اصلي برنامه، GetEntries است. اين متد آدرس اينترنتي يك فيد را دريافت كرده و پس از آناليز، آن‌را به صورت يك ليست بر مي‌گرداند.

<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>Latest Microsoft Blogs</title>
<link>http://weblogs.asp.net/aspnet-team/default.aspx</link>
<description />
<dc:language>en</dc:language>
<generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator>
<item>
<title>Comments on my recent benchmarks.</title>
<link>http://misfitgeek.com/blog/aspnet/comments-on-my-recent-benchmarks/</link>
<pubDate>Mon, 10 Aug 2009 23:33:59 GMT</pubDate>
<guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7166225</guid>
<dc:creator>Misfit Geek: msft</dc:creator>
<slash:comments>0</slash:comments>
<wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/aspnet-team/rsscomments.aspx?PostID=7166225</wfw:commentRss>
<comments>http://misfitgeek.com/blog/aspnet/comments-on-my-recent-benchmarks/#comments</comments>
<description>Overall I’ve been pretty impressed ...</description>
<category domain="http://weblogs.asp.net/aspnet-team/archive/tags/ASP.NET/default.aspx">ASP.NET</category>
</item>
</channel>
</rss>
براي نمونه خروجي يك فيد مي‌تواند به صورت فوق باشد. آيتم‌هاي آن به صورت قابل بيان است:
var items = feed.Root.Element("channel").Elements("item");
و نكته مهمي كه اينجا وجود دارد، اعمال فضاهاي نام بكار رفته در اين فايل xml پيشرفته مي‌باشد. براي اعمال فضاهاي نام به يكي از دو روش زير مي‌توان عمل كرد:

XName.Get("{mynamespace}root");
//or
XName.Get("root", "mynamespace");