2008-11-26 17 views
34

Con .net 3.5, hay una SyndicationFeed que se cargará en una fuente RSS y le permitirá ejecutar LINQ en ella.Lectura de elementos no estándar en un SyndicationItem con SyndicationFeed

Aquí se muestra un ejemplo de la RSS que estoy de carga:

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

Cuando recorrer los elementos, que pueda volver el título y el enlace a través de las propiedades públicas de SyndicationItem.

Parece que no puedo entender cómo obtener los atributos de la etiqueta del gabinete, o los valores de las etiquetas de medios. Intenté usar

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

¿Alguna ayuda con alguno de estos?

Respuesta

7

Le falta el espacio de nombre. Usando LINQPad y su ejemplo de alimentación:

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

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

El constructo a tener en cuenta es: Elemento (Media + " jugador ") que le dice a Linq que use el espacio de nombres representado por 'medios', así como el nombre del elemento 'jugador'.

El daño cerebral debe ser de mi parte, pensé que estaba usando Linq. De todos modos, debes tener en cuenta el espacio de nombres.

+1

Gracias por la respuesta. Lo único que desearía poder tener serían nombres fuertemente tipados en lugar de cadenas. – Jared

10

Puede utilizar una combinación de LINQ y XPathNavigator para extraer las extensiones de sindicación de un elemento de fuente (en función del URI de espacio de nombres de la extensión). Para los cierres de elementos, querrá examinar la colección de enlaces de elementos para los enlaces que tienen un tipo RelationshipType de .

Ejemplo:

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

¡Eso me ayudó mucho! En caso de que desee obtener el atributo url, marque XPathNavigator.GetAttribute ("url", ""); – walteronassis

15

Aquí es cómo me las arreglé para recuperar el enlace de un recinto de alimentación utilizando 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 salida es la siguiente:

título del artículo: Podcast # 50
elemento vincula
Enlace Título:
URI: http://blog.stackoverflow.com/2009/04/podcast-50/
RelationshipType: alternas
MediaType:
Longitud: 0
Título del enlace:
URI: http://itc.conversationsnetwork.org/audio/download/ITC.SO-Episode50-2009.04.21.mp3
RelationshipType: recinto
MediaType: audio/mpeg
Longitud: 36580016

Puede identificar el vínculo recinto de su tipo de relación.

35

Esto debe darle una idea de cómo hacerlo:

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

Me gusta esta respuesta por su simplicidad y porque usa la clase SyndicationFeed utilizada por el OP. Sin embargo, esto no devuelve la propiedad 'recinto' que necesitaban expuesta. ¿Me estoy perdiendo de algo? – Joshua

13

Sea que la recuperación de los contenidos que no son XML de elementos de extensión o artículos XElement, es posible que desee Considere el uso de una función auxiliar genérica como:

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

Dependiendo de si los elementos están garantizados para estar allí o si usted es pu Al convertir esto en una biblioteca reutilizable, es posible que deba agregar programación defensiva adicional.

+3

No estoy seguro de por qué esto no se modifica más alto. Una solución agradable, limpia y de una línea. ¡Funciona para mi! – egandalf

+0

La mejor respuesta hasta el momento – Wingjam

Cuestiones relacionadas