2008-11-26 8 views
34

Mit .net 3.5 gibt es einen SyndicationFeed, der in einen RSS-Feed geladen wird und Ihnen erlaubt, LINQ darauf auszuführen. HierNicht-Standardelemente in einem SyndicationItem mit SyndicationFeed lesen

ist ein Beispiel für den RSS, die ich lade:

<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/"> 
<channel> 
    <title>Title of RSS feed</title> 
    <link>http://www.google.com</link> 
    <description>Details about the feed</description> 
    <pubDate>Mon, 24 Nov 08 21:44:21 -0500</pubDate> 
    <language>en</language> 
    <item> 
     <title>Article 1</title> 
     <description><![CDATA[How to use StackOverflow.com]]></description> 
     <link>http://youtube.com/?v=y6_-cLWwEU0</link> 
     <media:player url="http://youtube.com/?v=y6_-cLWwEU0" /> 
     <media:thumbnail url="http://img.youtube.com/vi/y6_-cLWwEU0/default.jpg" width="120" height="90" /> 
     <media:title>Jared on StackOverflow</media:title> 
     <media:category label="Tags">tag1, tag2</media:category> 
     <media:credit>Jared</media:credit> 
     <enclosure url="http://youtube.com/v/y6_-cLWwEU0.swf" length="233" type="application/x-shockwave-flash"/> 
    </item> 
</channel> 

Wenn ich Schleife durch die Elemente, kann ich den Titel und den Link durch die öffentlichen Eigenschaften von SyndicationItem zurück.

Ich kann nicht herausfinden, wie Sie die Attribute des Enclosure-Tags oder die Werte der Media-Tags erhalten. Ich habe versucht mit

SyndicationItem.ElementExtensions.ReadElementExtensions<string>("player", "http://search.yahoo.com/mrss/") 

Jede Hilfe mit diesen beiden?

Antwort

7

Ihr fehlt den Namespace. Mit LINQPad und Ihrem Beispiel Futter:

string xml = @" 
    <rss version='2.0' xmlns:media='http://search.yahoo.com/mrss/'> 
    <channel> 
     <title>Title of RSS feed</title> 
     <link>http://www.google.com</link> 
     <description>Details about the feed</description> 
     <pubDate>Mon, 24 Nov 08 21:44:21 -0500</pubDate> 
     <language>en</language> 
     <item> 
      <title>Article 1</title> 
      <description><![CDATA[How to use StackOverflow.com]]></description> 
      <link>http://youtube.com/?v=y6_-cLWwEU0</link> 
      <media:player url='http://youtube.com/?v=y6_-cLWwEU0' /> 
      <media:thumbnail url='http://img.youtube.com/vi/y6_-cLWwEU0/default.jpg' width='120' height='90' /> 
      <media:title>Jared on StackOverflow</media:title> 
      <media:category label='Tags'>tag1, tag2</media:category> 
      <media:credit>Jared</media:credit> 
      <enclosure url='http://youtube.com/v/y6_-cLWwEU0.swf' length='233' type='application/x-shockwave-flash'/> 
     </item> 
    </channel> 
    </rss> 
    "; 



XElement rss = XElement.Parse(xml); 
XNamespace media = "http://search.yahoo.com/mrss/"; 

var player = rss.Element("channel").Element("item").Element(media + "player").Attribute("url"); 
player.Dump(); 

Ergebnis: url = "http://youtube.com/?v=y6_-cLWwEU0"

Das Konstrukt an, betrachten: Element (media + " player "), die Linq anweist, den durch 'media' dargestellten Namespace sowie den Elementnamen 'player' zu verwenden.

Gehirnschaden muss meinerseits eingestellt werden, ich dachte, du benutzt Linq. Wie auch immer, Sie müssen den Namensraum berücksichtigen.

+1

Danke für die Antwort. Das einzige, was ich mir wünschte, wäre stark typisierte Namen anstelle von Strings. – Jared

10

Sie können eine Kombination aus LINQ und XPathNavigator verwenden, um die Syndikationserweiterungen eines Feedelements zu extrahieren (basierend auf dem Namespace-URI der Erweiterung). Bei Elementgehäusen sollten Sie die Objektelinksammlung auf Links mit einem RelationshipType von Gehäuse überprüfen.

Beispiel:

HttpWebRequest webRequest = WebRequest.Create("http://www.pwop.com/feed.aspx?show=dotnetrocks&filetype=master") as HttpWebRequest; 

using (Stream stream = webRequest.GetResponse().GetResponseStream()) 
{ 
    XmlReaderSettings settings = new XmlReaderSettings(); 
    settings.IgnoreComments  = true; 
    settings.IgnoreWhitespace = true; 

    using(XmlReader reader = XmlReader.Create(stream, settings)) 
    { 
     SyndicationFeed feed = SyndicationFeed.Load(reader); 

     foreach(SyndicationItem item in feed.Items) 
     { 
      // Get values of syndication extension elements for a given namespace 
      string extensionNamespaceUri   = "http://www.itunes.com/dtds/podcast-1.0.dtd"; 
      SyndicationElementExtension extension = item.ElementExtensions.Where<SyndicationElementExtension>(x => x.OuterNamespace == extensionNamespaceUri).FirstOrDefault(); 
      XPathNavigator dataNavigator   = new XPathDocument(extension.GetReader()).CreateNavigator(); 

      XmlNamespaceManager resolver = new XmlNamespaceManager(dataNavigator.NameTable); 
      resolver.AddNamespace("itunes", extensionNamespaceUri); 

      XPathNavigator authorNavigator  = dataNavigator.SelectSingleNode("itunes:author", resolver); 
      XPathNavigator subtitleNavigator = dataNavigator.SelectSingleNode("itunes:subtitle", resolver); 
      XPathNavigator summaryNavigator  = dataNavigator.SelectSingleNode("itunes:summary", resolver); 
      XPathNavigator durationNavigator = dataNavigator.SelectSingleNode("itunes:duration", resolver); 

      string author = authorNavigator != null ? authorNavigator.Value : String.Empty; 
      string subtitle = subtitleNavigator != null ? subtitleNavigator.Value : String.Empty; 
      string summary = summaryNavigator != null ? summaryNavigator.Value : String.Empty; 
      string duration = durationNavigator != null ? durationNavigator.Value : String.Empty; 

      // Get attributes of <enclosure> element 
      foreach (SyndicationLink enclosure in item.Links.Where<SyndicationLink>(x => x.RelationshipType == "enclosure")) 
      { 
       Uri url    = enclosure.Uri; 
       long length   = enclosure.Length; 
       string mediaType = enclosure.MediaType; 
      } 
     } 
    } 
} 
+0

Das hat mir sehr geholfen! Wenn Sie das url-Attribut erhalten möchten, überprüfen Sie XPathNavigator.GetAttribute ("url", ""); – walteronassis

15

Hier ist, wie ich es geschafft, die Gehäuse-Link von einem Feed abrufen SyndicationFeed verwenden.

static void Main(string[] args) 
{ 
    var feedUrl = "http://blog.stackoverflow.com/index.php?feed=podcast"; 

    using (var feedReader = XmlReader.Create(feedUrl)) 
    { 
     var feedContent = SyndicationFeed.Load(feedReader); 

     if (null == feedContent) return; 

     foreach (var item in feedContent.Items) 
     { 
      Debug.WriteLine("Item Title: " + item.Title.Text); 

      Debug.WriteLine("Item Links"); 
      foreach (var link in item.Links) 
      { 
       Debug.WriteLine("Link Title: " + link.Title); 
       Debug.WriteLine("URI: " + link.Uri); 
       Debug.WriteLine("RelationshipType: " + link.RelationshipType); 
       Debug.WriteLine("MediaType: " + link.MediaType); 
       Debug.WriteLine("Length: " + link.Length); 
      } 
     } 
    } 
} 

Der Ausgang ist wie folgt:

Titel: Podcast # 50
Artikel Weblinks
Link-Titel:
URI: http://blog.stackoverflow.com/2009/04/podcast-50/
Relationship: wechsel
Media:
Länge: 0
Link-Titel:
URI: http://itc.conversationsnetwork.org/audio/download/ITC.SO-Episode50-2009.04.21.mp3
Relationship: Gehäuse
Media: audio/mpeg
Länge: 36580016

Sie können die Gehäuse-Link aus seinem Beziehungstyp identifizieren.

35

Dies sollte Ihnen eine Idee, wie es zu tun:

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

SyndicationFeed feed = reader.Read(); 

foreach (var item in feed.Items) 
{ 
    foreach (SyndicationElementExtension extension in item.ElementExtensions) 
    { 
     XElement ele = extension.GetObject<XElement>(); 
     Console.WriteLine(ele.Value); 
    } 
} 
+0

Ich mag diese Antwort für ihre Einfachheit und weil sie die vom OP verwendete SyndicationFeed-Klasse verwendet. Dies gibt jedoch nicht die "Gehäuse" -Eigenschaft, die sie benötigt ausgesetzt. Fehle ich etwas? – Joshua

13

Ob Sie die Nicht-XML-Inhalte von Erweiterungselementen oder XElement Artikel abrufen, möchten Sie vielleicht Verwenden Sie eine generische Hilfsfunktion wie:

private static T GetExtensionElementValue<T>(SyndicationItem item, string extensionElementName) 
{ 
     return item.ElementExtensions.First(ee => ee.OuterName == extensionElementName).GetObject<T>(); 
} 

Je nachdem, ob die Elemente garantiert da sind oder ob Sie pu sind Wenn Sie dies in eine wiederverwendbare Bibliothek integrieren, müssen Sie möglicherweise zusätzliche defensive Programmierung hinzufügen.

+3

Nicht sicher, warum das nicht höher modded ist. Eine nette, saubere, einzeilige Lösung. Funktioniert bei mir! – egandalf

+0

Beste Antwort bisher – Wingjam