‏نمایش پست‌ها با برچسب xml. نمایش همه پست‌ها
‏نمایش پست‌ها با برچسب xml. نمایش همه پست‌ها

۱۳۹۰/۰۷/۰۱

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


اگر به گوگل ريدر دقت كرده باشيد، دو گزينه‌ي به اشتراك گذاري دارد: 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 مقدار دهي شود. پس از آن به صورت خودكار بر روي كل برنامه تاثير خواهد گذاشت.


۱۳۹۰/۰۵/۱۷

نگاشت JSON به كلاس‌هاي معادل آن


يكي از مواردي كه عموما در برنامه نويسي با آن سر و كار داريم، parse اطلاعات با فرمت‌هاي مختلف است. از CSV تا XML تا ... JSON .
در مورد كار با XML در دات نت فريم ورك، فضاهاي نام مرتبط زيادي وجود دارند؛ براي مثال System.Xml.Linq و System.Xml . همچنين يك روش ديگر هم براي كار با اطلاعات XML ايي در دات نت وجود دارد. مي‌شود كلاس معادل يك فايل XML را توليد و سپس اطلاعات آن‌را به اين كلاس نگاشت كرد. اطلاعات بيشتر : (^). اين برنامه كار خود مايكروسافت است.
در مورد JSON از دات نت سه و نيم به بعد كارهايي صورت گرفته مانند : (^). اما آنچنان دلچسب نيست. جهت رفع اين خلاء كتابخانه‌ي سورس باز و بسيار كاملي در اين زمينه به نام JSON.NET تهيه شده كه از اين آدرس قابل دريافت است: (^)
و خبر خوب اينكه امكان تهيه كلاس‌هاي معادل اطلاعات JSON ايي هم مدتي‌است توسط برنامه نويس‌هاي مستقل تهيه شده است. يا مي‌توان از امكانات توكار دات نت استفاده كرد يا از كتابخانه‌‌هايي مانند JSON.NET يا از هيچكدام! مي‌توان يك راست كل اطلاعات JSON ايي دريافتي را به يك يا چند كلاس معادل آن نگاشت كرد:
  • و يا يك ابزار آنلاين مشابه: json2csharp

۱۳۸۸/۰۲/۰۸

استفاده از Google Analytics API در دات نت فريم ورك


بالاخره گوگل كار تهيه API مخصوص ابزار Analytics خود را به پايان رساند و اكنون برنامه نويس‌ها مي‌توانند همانند ساير سرويس‌هاي گوگل از اين ابزار گزارشگيري نمايند.
خلاصه كاربردي اين API ، دو صفحه تعاريف پروتكل (+) و ريز مواردي (+) است كه مي‌توان گزارشگيري نمود.
هنوز كتابخانه google-gdata جهت استفاده از اين API به روز رساني نشده است؛ بنابراين در اين مقاله سعي خواهيم كرد نحوه كار با اين API را از صفر بازنويسي كنيم.
مطابق صفحه تعاريف پروتكل، سه روش اعتبارسنجي جهت دريافت اطلاعات API معرفي شده است كه در اينجا از روش ClientLogin كه مرسوم‌تر است استفاده خواهيم كرد.
مطابق مثالي كه در آن صفحه قرار دارد، اطلاعاتي شبيه به اطلاعات زير را بايد ارسال و دريافت كنيم:

POST /accounts/ClientLogin HTTP/1.1
User-Agent: curl/7.15.1 (i486-pc-linux-gnu) libcurl/7.15.1
OpenSSL/0.9.8a zlib/1.2.3 libidn/0.5.18
Host: www.google.com
Accept: */*
Content-Length: 103
Content-Type: application/x-www-form-urlencoded
accountType=GOOGLE&Email=userName@google.com&Passwd=myPasswrd&source=curl-tester-1.0&service=analytics

HTTP/1.1 200 OK
Content-Type: text/plain
Cache-control: no-cache
Pragma: no-cache
Date: Mon, 02 Jun 2008 22:08:51 GMT
Content-Length: 497
SID=DQ...
LSID=DQAA...
Auth=DQAAAG8...
در دات نت فريم ورك، اين‌كار را به صورت زير مي‌توان انجام داد:
        string getSecurityToken()
{
if (string.IsNullOrEmpty(Email))
throw new NullReferenceException("Email is required!");

if (string.IsNullOrEmpty(Password))
throw new NullReferenceException("Password is required!");

WebRequest request = WebRequest.Create("https://www.google.com/accounts/ClientLogin");
request.Method = "POST";

string postData = "accountType=GOOGLE&Email=" + Email + "&Passwd=" + Password + "&service=analytics&source=vahid-testapp-1.0";
byte[] byteArray = Encoding.ASCII.GetBytes(postData);

request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;

using (Stream dataSt = request.GetRequestStream())
{
dataSt.Write(byteArray, 0, byteArray.Length);
}

string auth = string.Empty;
using (WebResponse response = request.GetResponse())
{
using (Stream dataStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(dataStream))
{
string responseFromServer = reader.ReadToEnd().Trim();
string[] tokens = responseFromServer.Split('\n');
foreach (string token in tokens)
{
if (token.StartsWith("SID="))
continue;

if (token.StartsWith("LSID="))
continue;

if (token.StartsWith("Auth="))
{
auth = token.Substring(5);
}
else
{
throw new AuthenticationException("Error authenticating Google user " + Email);
}
}
}
}
}

return auth;

}

همانطور كه ملاحظه مي‌كنيد به آدرس https://www.google.com/accounts/ClientLogin ، اطلاعات postData با متد POST ارسال شده (دقيقا مطابق توضيحات گوگل) و سپس از پاسخ دريافتي، مقدار نشانه Auth را جدا نموده و در ادامه عمليات استفاده خواهيم كرد. وجود اين نشانه در پاسخ دريافتي به معناي موفقيت آميز بودن اعتبار سنجي ما است و مقدار آن در طول كل عمليات بايد نگهداري شده و مورد استفاده مجدد قرار گيرد.
سپس مطابق ادامه توضيحات API گوگل بايد ليست پروفايل‌هايي را كه ايجاد كرده‌ايم پيدا نمائيم:

string getAvailableProfiles(string authToken)
{
return fetchPage("https://www.google.com/analytics/feeds/accounts/default", authToken);
}

متد fetchPage را از پيوست اين مقاله مي‌توانيد دريافت نمائيد. خروجي يك فايل xml است كه با انواع و اقسام روش‌هاي موجود قابل آناليز است، از كتابخانه‌هاي XML دات نت گرفته تا Linq to xml و يا روش serialization كه من روش آخر را ترجيح مي‌دهم.
مرحله بعد، ساخت URL زير و دريافت مجدد اطلاعات مربوطه است:
            string url = string.Format("https://www.google.com/analytics/feeds/data?ids={0}&metrics=ga:pageviews&start-date={1}&end-date={2}", id, from, to);
return fetchPage(url, auth);
و سپس آناليز اطلاعات xml دريافتي، جهت استخراج تعداد بار مشاهده صفحات يا pageviews استفاده شده در اين مثال. ليست كامل مواردي كه قابل گزارشگيري است، در صفحه Dimensions & Metrics Reference گوگل ذكر شده است.

فايل‌هاي كلاس‌هاي مورد استفاده را از اينجا دريافت نمائيد.‌

مثالي در مورد نحوه استفاده از آن:
            CGoogleAnalytics cga = new CGoogleAnalytics
{
Email = "username@gmail.com",
Password = "password",
From = DateTime.Now.Subtract(TimeSpan.FromDays(1)),
To = DateTime.Now.Subtract(TimeSpan.FromDays(1))
};
List<CGoogleAnalytics.SitePagePreviews> pagePreviews =
cga.GetTotalNumberOfPageViews();

foreach (var list in pagePreviews)
{
//string site = list.Site;
//int pw = list.PagePreviews;
}

۱۳۸۷/۱۲/۱۷

دريافت مناسبت‌هاي سال 1388 از يك فايل XML


هميشه با نزديك شدن آخر سال، به روز كردن مناسبت‌هاي تقويم سال بعد ضروري مي‌شود. دوستان لينوكسي ما هم در اين مورد زحمت كشيده و برنامه‌اي را تهيه كرده‌اند كه از آدرس زير قابل دريافت است:
http://download.gna.org/jalali-calendar/

پس از دريافت برنامه، مناسبت‌هاي سال 1388 در فايل 1388.xml قابل مشاهده است (با تقدير و تشكر از زحمات اين عزيزان). فرض كنيد مي‌خواهيم اين اطلاعات را به اس كيوال سرور منتقل كنيم.
فرمت اين فايل به شكل زير است:

<?xml version="1.0" encoding="UTF-8"?>
<cal1388>
<day>
<num>1/1</num>
<desc>عید نوروز، لحظه تحويل سال:ساعت 15 و 13 دقيقه و 39 ثانيه </desc>
</day>
</cal1388>

حداقل سه راه حل براي انجام اينكار (خواندن فايل xml توسط اس كيوال سرور) موجود است:

راه اول:

SELECT '1388' saal,
X.day.query('num').value('.', 'nVARCHAR(50)') rooz_maah,
X.day.query('desc').value('.', 'nVARCHAR(max)') tozih
FROM (
SELECT CAST(x AS XML)
FROM OPENROWSET(
BULK
'c:\1388.xml',
SINGLE_BLOB
) AS T(x)
) AS T(x)
CROSS APPLY x.nodes('cal1388/day') AS X(day);

راه دوم:

DECLARE @MyXML XML

SELECT @MyXML = CAST(x AS XML)
FROM OPENROWSET(
BULK
'c:\1388.xml',
SINGLE_BLOB
) AS T(x)

SELECT 1388 saal,
nref.value('num[1]', 'nvarchar(50)') rooz_maah,
nref.value('desc[1]', 'nvarchar(max)') tozih

FROM @MyXML.nodes('//day') AS R(nref)

راه سوم:
DECLARE @MyXML XML
DECLARE @handle INT

SELECT @MyXML = CAST(x AS XML)
FROM OPENROWSET(
BULK
'c:\1388.xml',
SINGLE_BLOB
) AS T(x)

EXEC sp_xml_preparedocument @handle OUTPUT,
@MyXML

SELECT 1388 saal,
*
FROM OPENXML(@handle, '/cal1388/day', 2) WITH
(num VARCHAR(20), [desc] NVARCHAR(MAX))

EXEC sp_xml_removedocument @handle

اكنون كه مي‌توانيم اطلاعات اين فايل را select كنيم، Insert آن ساده است . براي مثال:
INSERT INTO tblMonasebat
(
saal,
rooz_mah,
tozih
)
SELECT '1388' saal,
nref.value('num[1]', 'nvarchar(50)') rooz_maah,
nref.value('desc[1]', 'nvarchar(max)') tozih
FROM @MyXML.nodes('//day') AS R(nref)

بديهي است امكان مقدار دهي @MyXML به صورت يك رشته كه حاوي محتويات فايل است نيز مهيا مي‌باشد (بجاي خواندن از فايل).

براي مطالعه‌ي بيشتر
XML Support in Microsoft SQL Server 2005
Beginning SQL Server 2005 XML Programming

۱۳۸۷/۱۱/۰۵

خواندن اطلاعات API فيدبرنر


مطلبي را در سايت راديكال 2 در مورد نمايش تعداد خواننده يك فيد ديدم كه پياده سازي آن با سي شارپ و xml serialization به صورت زير است:

using System;
using System.Xml;
using System.Xml.Serialization;

namespace Test
{
/// <summary>
/// كلاسي جهت نمايش تعداد خواننده فيد وبلاگ شما
/// <example>CFeedBurner data = new CFeedBurner { FeedID = "fhphjt61bueu08k93ehujpu234" };
/// MessageBox.Show(data.Circulation().ToString());</example>
/// </summary>
class CFeedBurner
{
/// <summary>
/// آي دي فيد شما زمانيكه به فيد برنر لاگين كرده‌ايد در تايتل صفحه مربوطه
/// </summary>
public string FeedID { get; set; }

/// <summary>
/// نگاشت فيد به يك كلاس
/// </summary>
/// <returns>كلاس متناظر با فيد</returns>
/// <exception cref="Exception">لطفا شماره شناسايي فيد را وارد كنيد</exception>
rsp deserializeFromXML()
{
if (FeedID == null)
throw new Exception("لطفا شماره شناسايي فيد را وارد كنيد");

XmlSerializer deserializer =
new XmlSerializer(typeof(rsp));
using (XmlReader reader = XmlReader.Create(
string.Format("https://feedburner.google.com/api/awareness/1.0/GetFeedData?id={0}", FeedID)))
{
return (rsp)deserializer.Deserialize(reader);
}
}

/// <summary>
/// دريافت تعداد خواننده فيد
/// </summary>
/// <returns>آمار فيد</returns>
/// <exception cref="Exception">اطلاعات فيد شما قابل دريافت نيست</exception>
public int Circulation()
{
rsp data = deserializeFromXML();
if (data == null || data.feed == null || data.feed.Length == 0)
throw new Exception("اطلاعات فيد شما قابل دريافت نيست");

if (data.feed[0].entry == null || data.feed[0].entry.Length == 0)
throw new Exception("اطلاعات فيد شما قابل پردازش نيست");

return int.Parse(data.feed[0].entry[0].circulation);
}
}
}

كلاس rsp از فايل xml فيد استاندارد سايت فيدبرنر درست شده است. روش توليد آن‌را قبلا توضيح داده بودم. به سادگي اجراي دو سطر زير است:

xsd.exe GetFeedData.xml
xsd.exe GetFeedData.xsd /c

دريافت فايل‌هاي كلاس‌هاي نامبرده شده.

۱۳۸۷/۰۸/۲۱

خواندن فيد گزارش آب و هواي ياهو با استفاده از روش Xml serialization


در مطلب قبلي (در مورد كتابخانه anti-xss مايكروسافت) از روش xml serialization براي خواندن فايل xml حملات استفاده كرديم.
ايجاد اين كلاس و نگاشت اشياء با توجه به ساختار ساده آن به صورت دستي و به‌سادگي انجام شد. اكنون به مثال زير دقت بفرمائيد:
سرويس آب و هواي ياهو براي شهرهاي مختلف ايران از طريق لينك زير قابل استفاده است:
http://weather.yahoo.com/regional/IRXX.html
اگر به صفحات شهرهاي مختلف مراجعه نمائيد، يك فيد rss هم مشاهده خواهيد كرد، براي مثال در مورد تهران داريم:
http://weather.yahooapis.com/forecastrss?p=IRXX0018&u=c
ساختار اين فايل xml تا حدودي با يك rss استاندارد تطابق دارد. اما اگر به سورس xml آن دقت كنيم تگ‌هاي ديگري را نيز مشاهده خواهيم كرد كه براي مثال دما ، تاريخ و شرايط جوي را به صورت دقيقي و با استفاده از اصول xml ارائه مي‌دهند.

<yweather:condition text="Partly Cloudy" code="29" temp="10" date="Tue, 11 Nov 2008 5:30 pm IRT" />

خوب، براي دريافت اين اطلاعات چه بايد كرد؟ يكي از روش‌هاي متداول براي كار با اين نوع داده‌ها، استفاده از كلاس DataSet در دات نت و فراخواني متد ReadXml آن است (يك آدرس اينترنتي را هم مي‌تواند دريافت كند). سپس مطابق روش‌هاي معمول ADO.Net مي‌توان به تگ‌ها ومقادير آنها دسترسي داشت.
روش‌ بالا هر چند مشكلي ندارد اما به زيبايي كار با خواص يك كلاس متناظر با آن فايل xml نيست. اما در اينجا براي استفاده از روش xml serialization يك مشكل وجود دارد! ايجاد دستي اين كلاس كه بيانگر عملكرد آن فايل xml است كار ساده‌اي نيست.
خوشبختانه به همراه SDK‌ دات نت فريم ورك 2، برنامه‌اي به نام xsd.exe نيز همراه است كه كار ايجاد يك كلاس cs يا vb را از يك فايل xml جهت اين منظور انجام مي‌دهد (اين برنامه براي مثال در مسير C:\Program Files\Microsoft.NET\SDK\v2.0\Bin قرار دارد).

براي ايجاد فايل كلاس به صورت خودكار از روي يك فايل xml موجود بايد به ترتيب زير عمل كرد:
الف) ايجاد فايل xsd متناظر (XML Schema Definition)
براي اينكار در خط فرمان تايپ كنيد:
xsd.exe file.xml

نكته 1:
روش ديگر انجام اين كار : فايل xml را در VS.net باز كنيد، از منوي بالاي صفحه گزينه xml را انتخاب نموده و بر روي دكمه Create Schema كليك كنيد.

ب) ايجاد فايل cs يا vb از روي فايل(هاي) xsd ايجاد شده
در اينجا براي فيد آب و هواي ياهو سه فايل xsd توليد خواهد شد. براي تبديل آنها به كلاس cs بايد دستور زير را در خط فرمان اجرا كرد:

Xsd.exe file_1.xsd file_2.xsd file_3.xsd /c

اين مورد نكته مهمي است و تنها اگر يكي از فايل‌ها اينجا ذكر شوند، كلاس ناقصي تشكيل خواهد شد. (براي نمونه فايل xssAttacks.xml مطلب قبلي، ساختار ساده‌اي داشته و تنها به يك فايل xsd ختم خواهد شد)

نكته 2:
براي انتخاب زبان VB (با توجه به اين‌كه پيش فرض آن CS است) مي‌توان به صورت زير عمل كرد:
xsd.exe file.xsd /c  /l:vb

نكته 3:
براي توليد فايل xsd ، از برنامه Infer.exe نيز مي‌توان استفاده كرد (خروجي نهايي دقيق‌تري را ارائه مي‌دهد). اين برنامه را از اينجا دريافت كنيد.

تصاوير زير مقايسه دو فايل كلاس نهايي توليد شده از xsd هاي اين دو برنامه است:






پس از طي اين مراحل فايل كلاس ما براي xml serialization آماده خواهد شد. مرحله بعد دريافت اطلاعات و نگاشت آن به اين كلاس توليد شده است:

public static rss DeserializeFromXML()
{
XmlSerializer deserializer =
new XmlSerializer(typeof(rss));
using (XmlReader reader = XmlReader.Create("http://weather.yahooapis.com/forecastrss?p=IRXX0018&u=c"))
{
return (rss)deserializer.Deserialize(reader);
}
}

كلاس rss از فيد xml و فايل‌هاي xsd آن كه توليد كرديم به صورت خودكار ايجاد شده است.
اكنون براي مثال خواندن وضعيت فعلي جوي از فيد دريافتي به سادگي زير است:

rss data = DeserializeFromXML();
MessageBox.Show(data.channel.item.condition.text);