2008-11-26 6 views
34

Avec .net 3.5, il y a un flux de syndication qui se chargera dans un flux RSS et vous permettra d'exécuter LINQ dessus.Lecture d'éléments non standard dans un SyndicationItem avec SyndicationFeed

Voici un exemple de RSS que je suis le chargement:

<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> 

Quand je boucle à travers les éléments, je peux récupérer le titre et le lien à travers les propriétés publiques de SyndicationItem.

Je n'arrive pas à comprendre comment obtenir les attributs de l'étiquette de boîtier ou les valeurs des étiquettes de média. J'ai essayé d'utiliser

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

Vous avez besoin d'aide avec ces outils?

Répondre

7

Il vous manque l'espace de noms. En utilisant LINQPad et votre exemple alimentation:

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(); 

résultat: url = "http://youtube.com/?v=y6_-cLWwEU0"

La construction à regarder est: Element (médias + " player ") qui indique à Linq d'utiliser l'espace de noms représenté par" media "ainsi que le nom de l'élément" player ".

Les dommages au cerveau doivent être mis en place de ma part, je pensais que vous utilisiez Linq. Quoi qu'il en soit, vous devez prendre en compte l'espace de noms.

+1

Merci pour la réponse. La seule chose que j'aimerais pouvoir avoir serait des noms fortement typés au lieu de chaînes. – Jared

10

Vous pouvez utiliser une combinaison de LINQ et XPathNavigator pour extraire les extensions de syndication d'un élément de fil (en fonction de l'espace de nom URI de l'extension). Pour les pièces jointes, vous devez examiner la collection de liens d'éléments pour les liens ayant un RelationshipType de enclosure.

Exemple:

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

Ça m'a beaucoup aidé! Si vous souhaitez obtenir l'attribut url, vérifiez XPathNavigator.GetAttribute ("url", ""); – walteronassis

15

Voici comment je réussi à récupérer le lien d'enceinte à partir d'une alimentation en utilisant SyndicationFeed.

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); 
      } 
     } 
    } 
} 

La sortie est la suivante:

article Titre: Podcast # 50
Article Liens
Lien Titre:
URI : http://blog.stackoverflow.com/2009/04/podcast-50/
RelationshipType: remplacement
MediaType:
Longueur: 0
Titre du lien:
URI: http://itc.conversationsnetwork.org/audio/download/ITC.SO-Episode50-2009.04.21.mp3
RelationshipType: enceinte
MediaType: audio/mpeg
Longueur: 36580016

Vous pouvez identifier le lien de l'enceinte de son type de relation.

35

Cela devrait vous donner une idée sur la façon de le faire:

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

J'aime cette réponse pour sa simplicité et parce qu'elle utilise la classe SyndicationFeed utilisée par l'OP. Cependant, cela ne retourne pas la propriété 'enclosure' dont ils avaient besoin. Est-ce que je manque quelque chose? – Joshua

13

Que vous récupérez le contenu non XML des éléments d'extension ou des éléments XElement, vous voudrez peut-être envisager d'utiliser une fonction d'aide générique comme:

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

Selon que les éléments sont garantis d'être là ou si vous êtes pu Dans une bibliothèque réutilisable, vous devrez peut-être ajouter une programmation défensive supplémentaire.

+3

Vous ne savez pas pourquoi cela n'est pas modifié plus haut. Une solution agréable, propre et unifilaire. Travaille pour moi! – egandalf

+0

Meilleure réponse pour l'instant – Wingjam

Questions connexes