我一直在尝试编写一些例程来使用System.ServiceModel.Syndication中提供的新例程来读取RSS和ATOM提要,但不幸的是,Rss20FeedFormatter对我尝试的大约一半的提示进行了炸弹,但有以下异常:
An error was encountered when parsing a DateTime value in the XML.
只要RSS提要以下列格式表达发布日期,就会出现这种情况:
2008年10月16日星期四14:23:26 -0700
如果Feed将发布日期表示为GMT,那么情况就好了:
周四,08年10月16日21:23:26 GMT
如果有一些方法可以使用XMLReaderSettings解决这个问题,我还没有找到它.有人可以帮忙吗?
根据微软提交给我的错误报告中的解决方法,我制作了一个专门用于阅读具有非标准日期的SyndicationFeeds的XmlReader.
下面的代码与Microsoft网站的变通方法中的代码略有不同.它还需要Oppositional关于使用RFC 1123模式的建议.
您不需要简单地调用XmlReader.Create(),而是需要从Stream创建XmlReader.我使用WebClient类来获取该流:
WebClient client = new WebClient(); using (XmlReader reader = new SyndicationFeedXmlReader(client.OpenRead(feedUrl))) { SyndicationFeed feed = SyndicationFeed.Load(reader); .... //do things with the feed .... }
以下是SyndicationFeedXmlReader的代码:
public class SyndicationFeedXmlReader : XmlTextReader { readonly string[] Rss20DateTimeHints = { "pubDate" }; readonly string[] Atom10DateTimeHints = { "updated", "published", "lastBuildDate" }; private bool isRss2DateTime = false; private bool isAtomDateTime = false; public SyndicationFeedXmlReader(Stream stream) : base(stream) { } public override bool IsStartElement(string localname, string ns) { isRss2DateTime = false; isAtomDateTime = false; if (Rss20DateTimeHints.Contains(localname)) isRss2DateTime = true; if (Atom10DateTimeHints.Contains(localname)) isAtomDateTime = true; return base.IsStartElement(localname, ns); } public override string ReadString() { string dateVal = base.ReadString(); try { if (isRss2DateTime) { MethodInfo objMethod = typeof(Rss20FeedFormatter).GetMethod("DateFromString", BindingFlags.NonPublic | BindingFlags.Static); Debug.Assert(objMethod != null); objMethod.Invoke(null, new object[] { dateVal, this }); } if (isAtomDateTime) { MethodInfo objMethod = typeof(Atom10FeedFormatter).GetMethod("DateFromString", BindingFlags.NonPublic | BindingFlags.Instance); Debug.Assert(objMethod != null); objMethod.Invoke(new Atom10FeedFormatter(), new object[] { dateVal, this }); } } catch (TargetInvocationException) { DateTimeFormatInfo dtfi = CultureInfo.CurrentCulture.DateTimeFormat; return DateTimeOffset.UtcNow.ToString(dtfi.RFC1123Pattern); } return dateVal; } }
同样,这几乎完全是从上面链接中Microsoft站点上发布的变通方法中复制的....除了这个适合我,而微软发布的那个没有.
注意:您可能需要做的一点定制是在类的开头的两个数组中.根据非标准Feed可能添加的任何无关字段,您可能需要向这些阵列添加更多项目.
RSS 2.0格式的联合供稿在序列化pubDate和lastBuildDate等元素时使用RFC 822日期时间规范.遗憾的是,RFC 822日期时间规范是一种非常"灵活"的语法,用于表示DateTime的时区组件.
时区可以以多种方式指示."UT"是世界时(以前称为"格林威治标准时间"); 允许"GMT"作为对世界时的参考.军事标准对每个区域使用单个字符."Z"是世界时."A"表示提前一小时,"M"表示提前12小时; "N"是一小时后,"Y"是12小时后.不使用字母"J".其余两种形式取自ANSI标准X3.51-1975.一个允许明确指示UT的偏移量; 另一个使用常见的3字符字符串来表示北美的时区.
我认为该问题涉及如何处理RFC 822日期时间值的区域组件.Feed格式化程序似乎不处理使用本地差异来指示时区的日期时间.
由于RFC 1123扩展了RFC 822规范,您可以尝试使用DateTimeFormatInfo.RFC1123Pattern("r")来处理转换problamatic日期时间,或者为RFC 822格式化日期编写自己的解析代码.另一种选择是使用第三方框架而不是System.ServiceModel.Syndication命名空间类.
似乎有一些已知的日期时间解析问题和正在由Microsoft解决的Rss20FeedFormatter.