我正在构建一个RSS提要解析器,这样以后,我可以在我的word新闻博客上检索最近的博客文章,并在我的其他网站上显示最近的文章。这段代码并不打算实现完整的RSS规范。它只需要处理Wordpress提供的提要。
我无法利用System.Xml.Linq,因为我无法在.Net核心上获得对它的引用。
<?xml version="1.0" encoding="UTF-8"?>
<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/"
xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
>
<channel>
<title>Christopher J. McClellan</title>
<atom:link href="https://christopherjmcclellan.wordpress.com/feed/" rel="self" type="application/rss+xml" />
<link>https://christopherjmcclellan.wordpress.com</link>
<description>Visual Basic, C#, and the Art of Being a Modern Man</description>
<lastBuildDate>Thu, 27 Jul 2017 22:12:44 +0000</lastBuildDate>
<language>en</language>
<sy:updatePeriod>hourly</sy:updatePeriod>
<sy:updateFrequency>1</sy:updateFrequency>
<generator>http://wordpress.com/</generator>
<cloud domain='christopherjmcclellan.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
<url>https://s2.wp.com/i/buttonw-com.png</url>
<title>Christopher J. McClellan</title>
<link>https://christopherjmcclellan.wordpress.com</link>
</image>
<atom:link rel="search" type="application/opensearchdescription+xml" href="https://christopherjmcclellan.wordpress.com/osd.xml" title="Christopher J. McClellan" />
<atom:link rel='hub' href='https://christopherjmcclellan.wordpress.com/?pushpress=hub'/>
<item>
<title>How to See Memory and CPU Usage for All Your Docker Containers on CentOS 6</title>
<link>https://christopherjmcclellan.wordpress.com/2017/07/22/docker-container-memory-usage/</link>
<comments>https://christopherjmcclellan.wordpress.com/2017/07/22/docker-container-memory-usage/#comments</comments>
<pubDate>Sat, 22 Jul 2017 11:40:25 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[DevOps]]></category>
<category><![CDATA[Programming]]></category>
<category><![CDATA[Docker]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/?p=2075</guid>
<description><![CDATA[I run a bunch of Docker containers on a single CentOS 6 server with a limited amount of memory. (I only recently bumped it from 0.5 to 1 whole whopping gig!) Before I bring another container online, I like to check to see how much room I’ve got. Being the newest versions of Docker aren’t […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=2075&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2017/07/22/docker-container-memory-usage/feed/</wfw:commentRss>
<slash:comments>3</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
</item>
<item>
<title>Go away. It will all be waiting for you when you return. </title>
<link>https://christopherjmcclellan.wordpress.com/2017/06/10/go-away-it-will-all-be-waiting-for-you-when-you-return/</link>
<comments>https://christopherjmcclellan.wordpress.com/2017/06/10/go-away-it-will-all-be-waiting-for-you-when-you-return/#respond</comments>
<pubDate>Sat, 10 Jun 2017 12:41:57 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[Life]]></category>
<category><![CDATA[Programming]]></category>
<category><![CDATA[work life balance]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/2017/06/10/go-away-it-will-all-be-waiting-for-you-when-you-return/</guid>
<description><![CDATA[I realize that my posts here have become a bit infrequent and erratic. If you’re a frequent reader, you know that I changed jobs early this year. I didn’t just change jobs though; I completely swapped stacks. Learning a dozen technologies “overnight” has taken up a lot of the time that I previously dedicated to […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=2059&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2017/06/10/go-away-it-will-all-be-waiting-for-you-when-you-return/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
</item>
<item>
<title>Pretend Your Users Sat Next to You Everyday</title>
<link>https://christopherjmcclellan.wordpress.com/2017/05/13/pretend-your-users-sat-next-to-you-everyday/</link>
<comments>https://christopherjmcclellan.wordpress.com/2017/05/13/pretend-your-users-sat-next-to-you-everyday/#respond</comments>
<pubDate>Sat, 13 May 2017 00:01:40 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[Programming]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/2017/05/13/pretend-your-users-sat-next-to-you-everyday/</guid>
<description><![CDATA[I’m very much a “The tests pass. Ship it.” kind of guy. I like to fail fast and have long believed that the best way to find places where we missed a requirement or made a mistake is to get it into the hands of real users as quickly as possible. Recently however, the users […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=2058&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2017/05/13/pretend-your-users-sat-next-to-you-everyday/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
</item>
<item>
<title>Two Quick Tips for a Better Code Review Experience</title>
<link>https://christopherjmcclellan.wordpress.com/2017/04/30/two-quick-tips-for-a-better-code-review-experience/</link>
<comments>https://christopherjmcclellan.wordpress.com/2017/04/30/two-quick-tips-for-a-better-code-review-experience/#respond</comments>
<pubDate>Sun, 30 Apr 2017 11:18:46 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[Programming]]></category>
<category><![CDATA[code review]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/?p=2056</guid>
<description><![CDATA[Let’s talk about Code Reviews for a minute. They’re important; they spread knowledge around and catch bugs [citation needed], but they can be frustrating some times. They don’t need to be though. There are a few things we can do to keep the code review a pleasant experience. Review the code, not the coder. Keep […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=2056&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2017/04/30/two-quick-tips-for-a-better-code-review-experience/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
</item>
<item>
<title>Tests tell stories, listen to what they say</title>
<link>https://christopherjmcclellan.wordpress.com/2017/03/20/tests-tell-stories-listen-to-what-they-say/</link>
<comments>https://christopherjmcclellan.wordpress.com/2017/03/20/tests-tell-stories-listen-to-what-they-say/#respond</comments>
<pubDate>Mon, 20 Mar 2017 09:13:34 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[Programming]]></category>
<category><![CDATA[clean architecture]]></category>
<category><![CDATA[integration tests]]></category>
<category><![CDATA[testing]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/?p=2052</guid>
<description><![CDATA[I’m not a big fan of integration tests. They’re often unreliable and “flaky” due to their very nature of being integration tests that rely on file systems, networks, and databases. These kinds of tests are hard to get right. At least, it’s hard to get them stable enough to be valuable and I often wonder if […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=2052&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2017/03/20/tests-tell-stories-listen-to-what-they-say/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
</item>
<item>
<title>Teaching an Old Dog New Tricks</title>
<link>https://christopherjmcclellan.wordpress.com/2017/03/04/teaching-an-old-dog-new-tricks/</link>
<comments>https://christopherjmcclellan.wordpress.com/2017/03/04/teaching-an-old-dog-new-tricks/#respond</comments>
<pubDate>Sat, 04 Mar 2017 13:12:41 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[agile]]></category>
<category><![CDATA[Programming]]></category>
<category><![CDATA[tdd]]></category>
<category><![CDATA[pair programming]]></category>
<category><![CDATA[productivity]]></category>
<category><![CDATA[software development]]></category>
<category><![CDATA[test driven development]]></category>
<category><![CDATA[unit testing]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/?p=1948</guid>
<description><![CDATA[I had a really amazing experience this week. I had an opportunity to pair with a gentleman who has been programming since I was in diapers. He had only ever test driven code once before, but is really excited about learning. I think that in and of itself is amazing, but I learned a few […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=1948&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2017/03/04/teaching-an-old-dog-new-tricks/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
</item>
<item>
<title>The Bottleneck</title>
<link>https://christopherjmcclellan.wordpress.com/2017/01/22/the-bottleneck/</link>
<comments>https://christopherjmcclellan.wordpress.com/2017/01/22/the-bottleneck/#respond</comments>
<pubDate>Sun, 22 Jan 2017 14:39:09 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[Programming]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/?p=1891</guid>
<description><![CDATA[The monk Ahiru was pairing with the bright young apprentice, Taipisuto. The apprentice was quite impressed with his customized editor and the speed at which he could type. Ahiru was not nearly as impressed. The screen was flickering in a way that made him more than just a bit nauseous. “And what shall you do when […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=1891&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2017/01/22/the-bottleneck/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
</item>
<item>
<title>Doing what’s best, even when it sucks</title>
<link>https://christopherjmcclellan.wordpress.com/2017/01/09/doing-whats-best-even-when-it-sucks/</link>
<comments>https://christopherjmcclellan.wordpress.com/2017/01/09/doing-whats-best-even-when-it-sucks/#comments</comments>
<pubDate>Mon, 09 Jan 2017 14:01:55 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[agile]]></category>
<category><![CDATA[Programming]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/?p=1795</guid>
<description><![CDATA[About 8 months ago, I promised you that I’d follow up and let you know how our transition to Agile software development was going. This is that long overdue follow up and I’m sad to say that six weeks ago I submitted my resignation. Tomorrow I start with my new company. I’m sitting in an airport […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=1795&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2017/01/09/doing-whats-best-even-when-it-sucks/feed/</wfw:commentRss>
<slash:comments>4</slash:comments>
<media:thumbnail url="https://christopherjmcclellan.files.wordpress.com/2017/01/humanity.jpeg" />
<media:content url="http://christopherjmcclellan.files.wordpress.com/2017/01/humanity.jpeg" medium="image">
<media:title type="html">humanity</media:title>
</media:content>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
<media:content url="http://christopherjmcclellan.files.wordpress.com/2017/01/humanity.jpeg?w=1536" medium="image">
<media:title type="html">humanity</media:title>
</media:content>
</item>
<item>
<title>In Depth on my first NodeJs / Express Stack</title>
<link>https://christopherjmcclellan.wordpress.com/2016/12/04/in-depth-on-my-first-nodejs-express-stack/</link>
<comments>https://christopherjmcclellan.wordpress.com/2016/12/04/in-depth-on-my-first-nodejs-express-stack/#respond</comments>
<pubDate>Sun, 04 Dec 2016 15:39:54 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[NodeJs]]></category>
<category><![CDATA[Programming]]></category>
<category><![CDATA[chai]]></category>
<category><![CDATA[express]]></category>
<category><![CDATA[handlebars]]></category>
<category><![CDATA[javascript]]></category>
<category><![CDATA[mocha]]></category>
<category><![CDATA[node]]></category>
<category><![CDATA[unit testing]]></category>
<category><![CDATA[unittesting]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/?p=1127</guid>
<description><![CDATA[The whole goal of my hobby site is to iteratively create the simplest website that could possibly work using all “new to me” stacks. Getting a static site up and running on my own Linux CentOS with Lighttpd was definitely simple. Getting a NodeJs web service up and running with Express was equally simple, but […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=1127&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2016/12/04/in-depth-on-my-first-nodejs-express-stack/feed/</wfw:commentRss>
<slash:comments>0</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
<media:content url="http://christopherjmcclellan.files.wordpress.com/2016/11/capture.png" medium="image">
<media:title type="html">capture</media:title>
</media:content>
<media:content url="http://i.imgur.com/SAx29qc.jpg" medium="image">
<media:title type="html">Buzz LightYear and Woody. Callbacks Everywhere</media:title>
</media:content>
</item>
<item>
<title>Initial Thoughts on Node.js</title>
<link>https://christopherjmcclellan.wordpress.com/2016/11/14/initial-thoughts-on-node-js/</link>
<comments>https://christopherjmcclellan.wordpress.com/2016/11/14/initial-thoughts-on-node-js/#comments</comments>
<pubDate>Mon, 14 Nov 2016 11:44:52 +0000</pubDate>
<dc:creator><![CDATA[Christopher J. McClellan]]></dc:creator>
<category><![CDATA[NodeJs]]></category>
<category><![CDATA[Programming]]></category>
<category><![CDATA[node]]></category>
<guid isPermaLink="false">http://christopherjmcclellan.wordpress.com/?p=1124</guid>
<description><![CDATA[I’ve been building a hobby site so I can learn about non-Microsoft stacks and I spent the weekend learning Node.js. At first I was completely amazed at how awesome it was. It took about 5 minutes to spin up a webserver and start returning HTML from an endpoint! It was easy and fun! That 5 […]<img alt="" border="0" src="https://pixel.wp.com/b.gif?host=christopherjmcclellan.wordpress.com&blog=59673389&post=1124&subd=christopherjmcclellan&ref=&feed=1" width="1" height="1" />]]></description>
<wfw:commentRss>https://christopherjmcclellan.wordpress.com/2016/11/14/initial-thoughts-on-node-js/feed/</wfw:commentRss>
<slash:comments>2</slash:comments>
<media:content url="http://0.gravatar.com/avatar/0b43c27212304872e59ec6c73e1e30e7?s=96&d=identicon&r=G" medium="image">
<media:title type="html">ckuhn203</media:title>
</media:content>
</item>
</channel>
</rss>以及解析代码。Rss模块包含所有记录类型和返回RssFeed记录的单个Parse方法。
module Rss =
open System
type Item = {
Title: string
Link: Uri
Comments: Uri
PublishDate: DateTimeOffset
Description: string
}
type Channel = {
Title: string
Link: Uri
Description: string
LastBuildDate: DateTimeOffset
Items: seq<Item>
}
type RssFeed = {
Version: double
Channel: Channel
}
open System
open System.Xml
let Parse input =
let document = XmlDocument()
document.LoadXml input
let rss = document.DocumentElement
let version = rss.Attributes.ItemOf "version"
let channelNode = rss.FirstChild
let innerText (node: XmlNode) (name: string) =
let item = node.Item name
item.InnerText
let channelElementValue name =
innerText channelNode name
let itemNodes = seq {
for element in channelNode.ChildNodes do
if element.Name.Equals "item" then
yield element
}
let itemNodeToItem node = {
Title = innerText node "title"
Link = Uri(innerText node "link")
Comments = Uri(innerText node "comments")
PublishDate = DateTimeOffset.Parse(innerText node "pubDate")
Description = innerText node "description"
}
let channel = {
Title = channelElementValue "title"
Link = Uri(channelElementValue "link")
Description = channelElementValue "description"
LastBuildDate = DateTimeOffset.Parse(channelElementValue "lastBuildDate")
Items = itemNodes |> Seq.map(itemNodeToItem)
}
{Version = Double.Parse version.Value; Channel = channel}发布于 2017-08-13 13:00:27
大部分情况下,我喜欢您的代码的外观,不过我想谈谈几件主要是次要的事情。
在F#中,我们大部分尝试把东西写成作文,包括泛型。F# (在我看来)更好的地方之一是它允许非常有表现力的代码和输入。例如:
键入Channel ={ Title: string : Uri描述: string LastBuildDate: DateTimeOffset Item: seq }
您的Items应该是一个Item seq,因为Item成为seq的一个组合。净效果是一样的:它是一个项目序列,但是表达式略有不同,我们表达的是组合而不是泛型。
我知道chat中提到,与循环相比,我们更喜欢递归或映射:
让itemNodes = seq { channelNode.ChildNodes中的元素做如果element.Name.Equals "item“然后产生元素}
所以我不想详细讨论这个问题,只是提到我们这样做是为了让我们能够用一系列的步骤而不是迭代来表达正在发生的事情。
我将在以下函数中重新排序这些参数:
设innerText (节点: XmlNode) (名称: string) = let item = node.Item name item.InnerText
为什么?因为它给我们留下了以后的管道,但更多的是:它允许我们建立一个有意义的构图。您知道如何使用|> (管道-右)运算符,但是您知道它总是将左参数输送到右边函数的最后一个参数吗?这意味着,如果我们想要将node输送到innerText,则需要将node作为最后一个参数。让我们更有表现力,尤其是在这里:
让itemNodeToItem节点={ Title = innerText节点"title“Link = Uri(innerText节点"link")注释= Uri(innerText节点”注释“) PublishDate = DateTimeOffset.Parse(innerText节点"pubDate") Description = innerText节点"description”}
现在我们可以编写Title = node |> innerText "title"了,它通常在F#中读得更清晰一些。我们甚至可以声明一个nodeTitle node = node |> innerText "title",它是由允许我们将channelNode或node输送到其中的。(想想:Title = node |> nodeTitle.)
我还将从编译器中删除:string类型提示,因为它知道您正在查看XmlNode.Item,因此它应该推断name必须是string。(我面前没有编译器来验证,但情况应该是这样的。如果没有,请告诉我,我将删除这一点。)
关于您的代码,我唯一不喜欢的地方是这个函数:
让channelElementValue名称= innerText channelNode名称
name参数并不是不言自明的,我个人称之为elementName、element或elName。(缩写在F#中是可以接受的)而且,一旦我们重写了我们的innerText,我认为它可以读得更有表现力:channelNode |> innerText name。
最后,我看到:
Item= itemNodes |> Seq.map(itemNodeToItem)
我们真的应该删除这些括号:Seq.map是一个F#函数,我们通常通过括号区分调用F#函数和.NET方法,它们在这里是不必要的:itemNodes |> Seq.map itemNodeToItem,我想您可能有它们,因为您以前使用过fun ...,这需要括号,但是一旦提取到它自己的函数中,括号就过时了。
最后,这是非常好的F#代码。你做了一件很棒的工作,简明扼要地表达了你想要达到的目标:这些步骤是合乎逻辑的,流程的,而且是有意义的。干得好。:)
https://codereview.stackexchange.com/questions/172821
复制相似问题