۱۳۹۰/۰۷/۰۱

گوگل ريدر و افزودن توضيحات


اگر به گوگل ريدر دقت كرده باشيد، دو گزينه‌ي به اشتراك گذاري دارد: share و share with note .


اگر گزينه‌ي share with note را انتخاب كرده و توضيحي را ارسال يا اضافه كنيم، اين توضيحات، به فيد از نوع Atom اشتراك‌ها هم اضافه مي‌شود. مثلا:

<?xml version="1.0"?>
<feed xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:gr="http://www.google.com/schemas/reader/atom/" 
   xmlns:idx="urn:atom-extension:indexing" 
   xmlns="http://www.w3.org/2005/Atom" 
   idx:index="no" 
   gr:dir="ltr">

 ...
   
  <entry gr:crawl-timestamp-msec="1316627782108">
    ...
    <gr:annotation>
      <content type="html">text-text-text</content>
      <author>
        <name>Vahid</name>
      </author>
    </gr:annotation>
 ...
  </entry>
  
    ...
  
</feed>



اين افزونه استاندارد نيست و همانطور كه در قسمت xmlns:gr اطلاعات فوق مشخص است، در فضاي نام http://www.google.com/schemas/reader/atom/ معنا پيدا مي‌كند. از دات نت سه و نيم به بعد هم كلاسي جهت خواندن فيدهاي استاندارد وجود دارد (تعريف شده در فضاي نام System.ServiceModel.Syndication). اما چگونه مي‌توان اين افزونه‌ي غير استاندارد را با كمك امكانات توكار دات نت خواند؟
روش كار با استفاده از ElementExtensions هر آيتم يك فيد است؛ به صورت زير :

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

namespace Linq2Rss
{
    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 string Annotation { set; get; }
    }

    public static class AtomReader
    {
        private static string getAtomAnnotation(this SyndicationElementExtensionCollection items)
        {
            if (!items.Any()) return string.Empty;
            var item = items.Where(x => x.OuterName.ToLowerInvariant() == "annotation").FirstOrDefault();
            if (item == null) return string.Empty;

            var element = item.GetObject<XElement>();
            var content = element.Element("{http://www.w3.org/2005/Atom}content");
            return content == null ? string.Empty : content.Value;
        }

        public static IList<RssEntry> GetEntries(string feedUrl)
        {
            using (var reader = XmlReader.Create(feedUrl))
            {
                var feed = SyndicationFeed.Load(reader);
                if (feed == null) return null;

                return feed.Items.Select(x =>
                    new RssEntry
                    {
                        Title = x.Title.Text,
                        Author = x.Authors.Any() ? x.Authors.First().Name : string.Empty,
                        Description = x.Content == null ? string.Empty : ((TextSyndicationContent)x.Content).Text,
                        Link = x.Links.Any() ? x.Links.First().Uri.AbsoluteUri : string.Empty,
                        PublicationDate = x.PublishDate.UtcDateTime,
                        BlogName = x.SourceFeed.Title.Text,
                        BlogAddress = x.SourceFeed.Links.Any() ? x.SourceFeed.Links.First().Uri.AbsoluteUri : string.Empty,
                        Annotation = x.ElementExtensions.getAtomAnnotation()

                    }).ToList();
            }
        }
    }
}

در اين مثال به كمك متد الحاقي getAtomAnnotation، مجموعه‌ي SyndicationElementExtensionCollection هر آيتم يك فيد بررسي شده، در بين اين‌ها، موردي كه از نوع annotation باشد انتخاب و سپس content آن استخراج مي‌گردد.


نكته‌اي ديگر:
اكثر كلاس‌هاي موجود در فضاهاي نام مرتبط با XML در دات نت امكان خواندن اطلاعات را از يك Uri هم دارند؛ مانند مثال فوق و متد XmlReader.Create بكارگرفته شده در آن. اما اگر بخواهيم حين خواندن اطلاعات، يك پروكسي را نيز به پروسه جاري اضافه كنيم، به نظر خاصيت يا متدي جهت انجام اينكار وجود ندارد. براي رفع اين مشكل مي‌توان يك پروكسي سراسري را تعريف كرد. تنها كافي است خاصيت System.Net.WebRequest.DefaultWebProxy مقدار دهي شود. پس از آن به صورت خودكار بر روي كل برنامه تاثير خواهد گذاشت.