Reading non-standard elements in a SyndicationItem with SyndicationFeed

前端 未结 5 631
挽巷
挽巷 2020-12-02 09:08

With .net 3.5, there is a SyndicationFeed that will load in a RSS feed and allow you to run LINQ on it.

Here is an example of the RSS that I am loading:

<         


        
相关标签:
5条回答
  • 2020-12-02 09:11

    Your missing the namespace. Using LINQPad and your example feed:

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

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

    The construct to look at is: Element(media + "player") that tells Linq to use the namespace represented by 'media' as well as the element name 'player'.

    Brain damage must be setting in on my part, I thought you were using Linq. Anyway, you need to take the namespace into consideration.

    0 讨论(0)
  • 2020-12-02 09:15

    Here is how I managed to retrieve the enclosure link from a feed using 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);
                }
            }
        }
    }
    

    The output is as follows:

    Item Title: Podcast #50
    Item Links
    Link Title:
    URI: http://blog.stackoverflow.com/2009/04/podcast-50/
    RelationshipType: alternate
    MediaType:
    Length: 0
    Link Title:
    URI: http://itc.conversationsnetwork.org/audio/download/ITC.SO-Episode50-2009.04.21.mp3
    RelationshipType: enclosure
    MediaType: audio/mpeg
    Length: 36580016

    You can identify the enclosure link from its relationship type.

    0 讨论(0)
  • 2020-12-02 09:26

    This should give you an idea on how to do it:

    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 讨论(0)
  • 2020-12-02 09:30

    Whether you're retrieving the non-XML contents of extension elements or XElement items, you might want to consider using a generic helper function like:

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

    Depending on whether the elements are guaranteed to be there or whether you are putting this into a reusable library, you may need to add additional defensive programming.

    0 讨论(0)
  • 2020-12-02 09:33

    You can use a combination of LINQ and XPathNavigator to extract the syndication extensions of a feed item (based on namespace URI of the extension). For item enclosures, you will want to examine the item links collection for links that have a RelationshipType of enclosure.

    Example:

    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 讨论(0)
提交回复
热议问题