zoukankan      html  css  js  c++  java
  • [UWP]涨姿势UWP源码——RSS feed的获取和解析

      本篇开始具体分析涨姿势UWP这个APP的代码,首先从数据的源头着手,即RSS feed的获取和解析,相关的类为RssReader,所有和数据相关的操作均放在里面。

      涨姿势网站提供的RSS feed地址为http://www.zhangzishi.cc/feed,在UWP中想要通过发送http request并从URI接受http response,最简单的方式就是使用HttpClient

            public async Task<string> DownloadRssString()
            {
                var httpClient = new HttpClient();
                var result = await httpClient.GetStringAsync(new Uri("http://www.zhangzishi.cc/feed"));
                return result;
            }

      通过上面这个方法,我们会获取到最新的涨姿势的数据源,并且是以XML格式组织的。头部是一些命名空间的定义,接下来的channel节点定义了一些titledescription等信息,这里比较重要的是lastBuildDate,因为后面我们会根据这个字段来判断是否有新数据需要保存到本地,并刷姿势新闻列表。

    <rss version="2.0"
        xmlns:content="http://purl.org/rss/1.0/modules/content/"
        xmlns:wfw="http://wellformedweb.org/CommentAPI/"
        xmlns:dc="http://purl.org/dc/elements/1.1/"
        xmlns:atom="http://www.w3.org/2005/Atom"
        xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
        xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
      <channel>
        <title>涨姿势</title>
        <atom:link href="http://www.zhangzishi.cc/feed" rel="self" type="application/rss+xml" />
        <link>http://www.zhangzishi.cc</link>
        <description>骚年,来这里涨点姿势吧!</description>
        <lastBuildDate>Sun, 17 Jul 2016 04:37:46 +0800</lastBuildDate>
    </channel>
    </rss>

      APP核心的新闻内容对应数据源中Item节点,每一个Item就对应一条涨姿势的新闻。整个XML文件中会存在几十个Item节点。对Item节点进行解析后,我们会创建一个Item对象的集合,映射到UI界面的ListView上,同时也要分析并保存每一个Item节点的详细信息,在用户点击ListView的具体ListViewItem时,打开详细页面填充内容。比如下图右侧的详细内容较为简单,仅仅是一副图片。

      

      我们来看一个Item节点的Sample

        <item>
          <title>日本某高校一男生在女生生日派对上公开表白,青春真好</title>
          <link>http://www.zhangzishi.cc/20160717zh.html</link>
          <comments>http://www.zhangzishi.cc/20160717zh.html#comments</comments>
          <pubDate>Sun, 17 Jul 2016 04:37:46 +0800</pubDate>
          <dc:creator><![CDATA[丁丁]]></dc:creator>
          <category><![CDATA[世界观]]></category>
          <guid isPermaLink="false">http://www.zhangzishi.cc/?p=178981</guid>
          <description><![CDATA[日本某高校一男生在女生生日派对上公开表白。“在这个世界上我最喜欢的人是你,我会好好珍惜你的。”看得本公举全程一 [&#8230;]]]></description>
          <content:encoded>
            <![CDATA[<p style="color: #444444;">日本某高校一男生在女生生日派对上公开表白。“在这个世界上我最喜欢的人是你,我会好好珍惜你的。”看得本公举全程一直傻笑,青春真好啊~</p>
    <p><embed width="480" height="480" type="application/x-shockwave-flash" src="http://video.weibo.com/player/1034:7e3df996c2f5e9a1973974f0bb9e5e39/v.swf" allowscriptaccess="always" allowfullscreen="allowfullscreen" wmode="transparent" quality="high"></embed></p>
    <p>视频链接:<a style="color: #428bca;" href="http://weibo.com/p/2304447e3df996c2f5e9a1973974f0bb9e5e39" target="_blank">http://weibo.com/p/2304447e3df996c2f5e9a1973974f0bb9e5e39</a><img src="http://cdnjp.zhangzishi.cc/wp-content/uploads/2016/05/024045ftw.jpg" alt="" class="alignnone size-medium wp-image-171793" /></p>
    <p>微信订阅号 zhangzishi_weixin 合作请直接联系 tintin@zhangzishi.cc</p>
    ]]>
          </content:encoded>
          <wfw:commentRss>http://www.zhangzishi.cc/20160717zh.html/feed</wfw:commentRss>
          <slash:comments>12</slash:comments>
        </item>

      很容易就能分析出titlepubDatedescriptioncategory这些内容,我们会建立对应的Model对象来存储相关信息。同时我们也发现,详细内容放置在<content:encoded>节点,并加了<![CDATA[>>标签,包含在标签中的内容会被XML的解析器忽略,当作一般文本处理。所以你会看见content节点中包含了大量的HTML标签,这些HTML的内容会被作为整体的字符串存储在Item对象的ContentEncoded属性中。

        public class Item
        {
            public string Title { get; set; }
            public Uri Link { get; set; }
            public DateTime PublishedDate { get; set; }
            public string Creator { get; set; }
            public string Category { get; set; }
            public string Description { get; set; }
            public string ContentEncoded { get; set; }
            public string CoverImageUri { get; set; } 
        }

      XML文件的处理,我这里选择来System.Xml.Linq命名空间下的XDocument类来处理。在获取rss这个根的XElement后,在channel节点找到Item节点的集合,对Item进行解析:

            private Item ParseItemNode(XElement itemNode)
            {
                var item = new Item();
                item.Title = itemNode.Element("title").Value;
                string uriString = itemNode.Element("link").Value;
                if (string.IsNullOrEmpty(uriString) == false)
                {
                    item.Link = new Uri(uriString);
                }
                item.PublishedDate = DateTime.Parse(itemNode.Element("pubDate").Value);
    
                XNamespace dc = XmlNameSpaceDic["dc"];
                item.Creator = itemNode.Element(dc + "creator").Value;
                item.Category = itemNode.Element("category").Value;
                item.Description = itemNode.Element("description").Value;
                XNamespace content = XmlNameSpaceDic["content"];
                var contentEncoded = itemNode.Element(content + "encoded").Value;
                
                var allImageUri = GetAllImageUri(ref contentEncoded);
                item.CoverImageUri = allImageUri.FirstOrDefault();
                item.ContentEncoded = RemoveEmbedFlash(contentEncoded);
                return item;
            }

      这里稍微值得注意的是部分节点存在命名空间,在通过Element方法取值的时候,需要加上对应的命名空间才能成功。这里附上一个获取XML文件头部定义的命名空间的方法:

            private Dictionary<string, string> GetXmlNameSpaceDic(XElement rssNode)
            {
                var dic = new Dictionary<string, string>();
                foreach (var attribute in rssNode.Attributes().Where(_ => _.IsNamespaceDeclaration))
                {
                    dic.Add(attribute.Name.LocalName,attribute.Value);
                }
    
                return dic;
            }

      ParseItemNode方法中还做了一件特殊的事情,是去去正文中的图片地址,因为rss feed没有提供每条新闻的封面图片,我这里就通过正则表达式将正文的图片地址筛选出来,以第一张图片作为新闻的封面。正则表达式匹配项中有一个Group的概念,可以很好的选出img节点中的src属性,EditImageUri这个方法是为了给图片加上widthheight更好的适应不同尺寸的屏幕:

            private List<string> GetAllImageUri(ref string content)
            {
                var matchList = new List<string>();
                string pattern = "<img.+?src=["'](.+?)["'].*?>";
    
                var regex = new Regex(pattern, RegexOptions.IgnoreCase);
                foreach (Match match in regex.Matches(content))
                {
                    var uri = EditImageUri(match.Value);
                    if (uri != match.Value)
                    {
                        matchList.Add(match.Groups[1].Value);
                        content = content.Replace(match.Value, uri);
                    }
                }
    
                return matchList;
            }

      大体上RssReader这个类就分析完了,具体的代码有兴趣请去GitHub上查看,如果发现了bug还望不吝赐教,帮我提个pull request,万分感激。

      其实这个涨姿势UWPAPP属于闹着玩,网易云阅读WP版太简陋,看起来限制太多,思来想去自己动手丰衣足食,后面还会进一步补充功能,毕竟现在这个版本我用起来也不满意。

      GitHub

    https://github.com/manupstairs/ZhangZiShiRSSRead

      Windows Store

    https://www.microsoft.com/zh-cn/store/p/%e6%b6%a8%e5%a7%bf%e5%8a%bfuwp/9nblggh3zqd1

  • 相关阅读:
    【SCOI 2011】 糖果
    【POJ 3159】 Candies
    【POJ 1716】 Integer Intervals
    【POJ 2983】 Is the information reliable?
    【POJ 1364】 King
    【POJ 1201】 Intervals
    【POJ 1804】 Brainman
    6月10日省中提高组题解
    【POJ 3352】 Road Construction
    【POJ 1144】 Network
  • 原文地址:https://www.cnblogs.com/manupstairs/p/6107212.html
Copyright © 2011-2022 走看看