2 Stimmen

.NET/C#: Verwendung von RSS.NET mit Stack Overflow Feeds: Wie behandelt man spezielle Eigenschaften von RSS-Elementen?

Ich bin Schreiben eines Stack Overflow API-Wrappers , derzeit bei http://soapidotnet.googlecode.com/ . Ich habe ein paar Fragen zum Parsen von SO-RSS-Feeds.

Ich habe mich für die Verwendung von RSS.NET um das RSS zu analysieren, aber ich habe ein paar Fragen zu meinem Code (den ich weiter unten in diesem Beitrag bereitgestellt habe).


Meine Fragen:

Zunächst einmal: Bin ich diese Attribute korrekt zu parsen ? Ich habe eine Klasse namens Question, die diese Eigenschaften hat.

Wie kann ich dann Analysieren Sie die <re:rank> RSS-Eigenschaft (verwendet für die Anzahl der Stimmen)? Ich bin nicht sicher, wie RSS.NET uns das ermöglicht. Soweit ich verstehe, ist es ein Element mit einem benutzerdefinierten Namespace.

Schließlich muss ich alle Eigenschaften manuell hinzufügen, wie derzeit in meinem Code? Gibt es eine Art von Deserialisierung die ich verwenden kann?


コード

Nachfolgend finden Sie meinen aktuellen Code zum Parsen von Feeds mit aktuellen Fragen:

   /// <summary>
    /// Utilises recent question feeds to obtain recently updated questions on a certain site.
    /// </summary>
    /// <param name="site">Trilogy site in question.</param>
    /// <returns>A list of objects of type Question, which represents the recent questions on a trilogy site.</returns>
    public static List<Question> GetRecentQuestions(TrilogySite site)
    {
        List<Question> RecentQuestions = new List<Question>();
        RssFeed feed = RssFeed.Load(string.Format("http://{0}.com/feeds",GetSiteUrl(site)));
        RssChannel channel = (RssChannel)feed.Channels[0];
        foreach (RssItem item in channel.Items)
        {
            Question toadd = new Question();
            foreach(RssCategory cat in item.Categories)
            {
                toadd.Categories.Add(cat.Name);
            }
            toadd.Author = item.Author;
            toadd.CreatedDate = ConvertToUnixTimestamp(item.PubDate).ToString();
            toadd.Id = item.Link.Url.ToString();
            toadd.Link = item.Link.Url.ToString();
            toadd.Summary = item.Description;

            //TODO: OTHER PROPERTIES
            RecentQuestions.Add(toadd);
        }
        return RecentQuestions;
    }

Hier ist der Code des SO-RSS-Feeds:

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:re="http://purl.org/atompub/rank/1.0"> 
    <title type="text">Top Questions - Stack Overflow</title> 
    <link rel="self" href="http://stackoverflow.com/feeds" type="application/atom+xml" /> 
    <link rel="alternate" href="http://stackoverflow.com/questions" type="text/html" /> 
    <subtitle>most recent 30 from stackoverflow.com</subtitle> 
    <updated>2009-11-28T19:26:49Z</updated> 
    <id>http://stackoverflow.com/feeds</id> 
    <creativeCommons:license>http://www.creativecommons.org/licenses/by-nc/2.5/rdf</creativeCommons:license> 

    <entry> 
        <id>http://stackoverflow.com/questions/1813483/averaging-angles-again</id> 
        <re:rank scheme="http://stackoverflow.com">0</re:rank> 
        <title type="text">Averaging angles... Again</title> 
        <category scheme="http://stackoverflow.com/feeds/tags" term="algorithm"/><category scheme="http://stackoverflow.com/feeds/tags" term="math"/><category scheme="http://stackoverflow.com/feeds/tags" term="geometry"/><category scheme="http://stackoverflow.com/feeds/tags" term="calculation"/> 
        <author><name>Lior Kogan</name></author> 
        <link rel="alternate" href="http://stackoverflow.com/questions/1813483/averaging-angles-again" /> 
        <published>2009-11-28T19:19:13Z</published> 
        <updated>2009-11-28T19:26:39Z</updated> 
        <summary type="html"> 
            &lt;p&gt;I want to calculate the average of a set of angles.&lt;/p&gt;

&lt;p&gt;I know it has been discussed before (several times). The accepted answer was &lt;strong&gt;Compute unit vectors from the angles and take the angle of their average&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However this answer defines the average in a non intuitive way. The average of 0, 0 and 90 will be &lt;strong&gt;atan( (sin(0)+sin(0)+sin(90)) / (cos(0)+cos(0)+cos(90)) ) = atan(1/2)= 26.56 deg&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;I would expect the average of 0, 0 and 90 to be 30 degrees.&lt;/p&gt;

&lt;p&gt;So I think it is fair to ask the question again: How would you calculate the average, so such examples will give the intuitive expected answer.&lt;/p&gt;

        </summary> 
    </entry> 

usw.

Hier ist meine Frageklasse, falls es hilft:

    /// <summary>
    /// Represents a question.
    /// </summary>
    public class Question : Post //TODO: Have Question and Answer derive from Post
    {

        /// <summary>
        /// # of favorites.
        /// </summary>
        public double FavCount { get; set; }

        /// <summary>
        /// # of answers.
        /// </summary>
        public double AnswerCount { get; set; }

        /// <summary>
        /// Tags.
        /// </summary>
        public string Tags { get; set; }

    }

/// <summary>
    /// Represents a post on Stack Overflow (question, answer, or comment).
    /// </summary>
    public class Post
    {
        /// <summary>
        /// Id (link)
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// Number of votes.
        /// </summary>
        public double VoteCount { get; set; }
        /// <summary>
        /// Number of views.
        /// </summary>
        public double ViewCount { get; set; }
        /// <summary>
        /// Title.
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// Created date of the post (expressed as a Unix timestamp)
        /// </summary>
        public string CreatedDate
        {

            get
            {
                return CreatedDate;
            }
            set
            {
                CreatedDate = value;
                dtCreatedDate = StackOverflow.ConvertFromUnixTimestamp(StackOverflow.ExtractTimestampFromJsonTime(value));

            }

        }
        /// <summary>
        /// Created date of the post (expressed as a DateTime)
        /// </summary>
        public DateTime dtCreatedDate { get; set; }
        /// <summary>
        /// Last edit date of the post (expressed as a Unix timestamp)
        /// </summary>
        public string LastEditDate
        {

            get
            {
                return LastEditDate;
            }
            set
            {
                LastEditDate = value;
                dtLastEditDate = StackOverflow.ConvertFromUnixTimestamp(StackOverflow.ExtractTimestampFromJsonTime(value));

            }

        }
        /// <summary>
        /// Last edit date of the post (expressed as a DateTime)
        /// </summary>
        public DateTime dtLastEditDate { get; set; }
        /// <summary>
        /// Author of the post.
        /// </summary>
        public string Author { get; set; }
        /// <summary>
        /// HTML of the post.
        /// </summary>
        public string Summary { get; set; }
        /// <summary>
        /// URL of the post.
        /// </summary>
        public string Link { get; set; }
        /// <summary>
        /// RSS Categories (or tags) of the post.
        /// </summary>
        public List<string> Categories { get; set; }

    }

Vielen Dank im Voraus! Übrigens: Bitte unterstützen Sie das Bibliotheksprojekt! :)

10voto

Martin Peck Punkte 11292

Erstens habe ich RSS.NET noch nie benutzt, aber ich habe mich gefragt, ob Sie wissen, dass das .NET-Framework eine eigene RSS-API innerhalb der System.ServiceModel.Syncidation Namensraum. Der SyndicationFeed Klasse ist der Ausgangspunkt dafür.

Um Ihre Frage zu beantworten, habe ich ein kleines Beispiel geschrieben, das den Feed für diese Frage nimmt und die Titel , Autor , id et le Rang (das Erweiterungselement, an dem Sie interessiert sind) in die Konsole eingeben. Dies soll Ihnen zeigen, wie einfach diese API ist und wie man auf die Rang .

// load the raw feed
using (var xmlr = XmlReader.Create("https://stackoverflow.com/feeds/question/1813559"))
{
    // get the items within a feed
    var feedItems = SyndicationFeed
                        .Load(xmlr)
                        .GetRss20Formatter()
                        .Feed
                        .Items;

    // print out details about each item in the feed
    foreach (var item in feedItems)
    {
        Console.WriteLine("Title: {0}", item.Title.Text); 
        Console.WriteLine("Author: {0}", item.Authors.First().Name);
        Console.WriteLine("Id: {0}", item.Id);

        // the extensions assume that there can be more than one value, so get
        // the first or default value (default == 0)
        int rank = item.ElementExtensions
                        .ReadElementExtensions<int>("rank", "http://purl.org/atompub/rank/1.0")
                        .FirstOrDefault();

        Console.WriteLine("Rank: {0}", rank);  
    }
}

Der obige Code führt dazu, dass folgendes in die Konsole geschrieben wird...

Titel: .NET/C#: Verwendung von RSS.NET mit Stack Overflow Feeds: Wie man spezielle Eigenschaften von RSS-Elementen behandelt

Autor: Maxim Z.

Id: .NET/C#: Verwendung von RSS.NET mit Stack Overflow Feeds: Wie behandelt man spezielle Eigenschaften von RSS-Elementen?

Rang: 0

Weitere Informationen über die Klasse SyndicationFeed finden Sie hier...

http://msdn.microsoft.com/en-us/library/system.servicemodel.syndication.syndicationfeed.aspx

Einige Beispiele für das Lesen und Schreiben von erweiterten Werten aus RSS-Feeds finden Sie hier...

http://msdn.microsoft.com/en-us/library/bb943475.aspx

Im Hinblick auf die Erstellung Ihrer Question-Instanzen bin ich mir nicht sicher, ob es einen schnellen Erfolg mit Serialisierung gibt. Ich würde wahrscheinlich Ihren Code etwas mehr wie diese geschrieben haben...

var questions = from item in feedItems
                select
                    new Question
                        {
                            Title = item.Title.Text,
                            Author = item.Authors.First().Name,
                            Id = item.Id,
                            Rank = item.ElementExtensions.ReadElementExtensions<int>(
                                "rank", "http://purl.org/atompub/rank/1.0").FirstOrDefault()
                        };

... aber es tut so ziemlich das Gleiche.

Für die oben genannten Dinge müssen .NET 3.5-Bibliotheken installiert sein. Das Folgende erfordert nicht, aber C# 3.5 (das Assemblies erstellt, die auf .NET 2.0 abzielen)

Ich schlage vor, dass Sie keine benutzerdefinierten Typen erstellen, sondern stattdessen Erweiterungsmethoden für den Typ SyndicationItem schreiben. Wenn Sie Ihre Benutzer mit SyndicationType arbeiten lassen (ein Typ, der unterstützt, verstanden, dokumentiert usw. ist), aber Erweiterungsmethoden hinzufügen, um den Zugriff auf SO-spezifische Eigenschaften zu erleichtern, dann machen Sie den Benutzern das Leben leichter und sie können immer auf die SyndicationItem-API zurückgreifen, wenn Ihre SO-Erweiterungen nicht das tun, was sie wollen. Wenn Sie also zum Beispiel diese Erweiterungsmethode schreiben...

public static class SOExtensions
{
    public static int Rank(this SyndicationItem item)
    {
        return item.ElementExtensions
                   .ReadElementExtensions<int>("rank", "http://purl.org/atompub/rank/1.0")
                   .FirstOrDefault();
    }
}

... könnten Sie auf den Rang eines SyndicationItem wie folgt zugreifen...

Console.WriteLine("Rank: {0}", item.Rank());  

... und wenn SO dem Feed eine andere Erweiterungseigenschaft hinzufügt, die Sie nicht berücksichtigt haben, kann der Benutzer Ihrer API auf die ElementExtensions-Sammlung zurückgreifen.

Ein letztes Update...

Ich habe die Rss.NET-Bibliothek nicht verwendet, aber ich habe die Online-Dokumente gelesen. Nach einer ersten Lektüre dieser Dokumente würde ich vermuten, dass es keine Möglichkeit gibt, an das Erweiterungselement zu gelangen, auf das Sie zuzugreifen versuchen (den Rang des Elements). Wenn die RSS.NET-API den Zugriff auf die xml für ein bestimmtes RssItem erlaubt (und ich bin mir nicht sicher, ob dies der Fall ist), dann könnten Sie den Mechanismus der Erweiterungsmethode verwenden, um die RssItem-Klasse zu erweitern.

Ich finde die SyndicationFeed-API sehr leistungsfähig und sehr einfach zu handhaben, wenn also die Verwendung von .NET 3.5 für Sie eine Option ist, würde ich diese Richtung einschlagen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X