2008-10-16 72 views
16

我一直在嘗試編寫一些例程來讀取使用System.ServiceModel.Syndication中可用的新例程的RSS和ATOM訂閱源,但不幸的是,Rss20FeedFormatter炸彈了大約一半的訂閱源I嘗試用以下異常:用C#和.NET讀取RSS的問題

An error was encountered when parsing a DateTime value in the XML. 

這似乎每當RSS提要表示在發佈日期的格式如下發生:

週四,08年10月16日14:2 3:26 -0700

如果進表達了發佈日期爲GMT,事情罰款:

週四,08年10月16日21時23分二十六秒GMT

如果有一些使用XMLReaderSettings解決這個問題的方法,我沒有找到它。任何人都可以協助

+0

內置的是可怕的。您可以輕鬆編寫您自己的RSS,RDF和ATOM解析器。我有一個教程和一個完整的視覺工作室項目,你可以下載,只是那個http://www.jarloo.com/rumormill-5/ – Kelly 2011-10-07 03:07:29

回答

9

RSS 2.0格式化聯合供稿利用像pubdate的lastBuildDateRFC 822 date-time specification串行化時的元件。不幸的是,RFC 822日期時間規範是表達DateTime時區組件的一種非常「靈活」的語法。

時區可能以幾種方式表示。 「UT」是世界時(以前稱爲「格林威治標準時間」); 「格林尼治標準時間」被允許作爲對世界時間的參考。軍事標準爲每個區域使用單個字符。 「Z」是世界時。 「A」表示提前一小時,「M」表示提前12小時; 「N」是一小時後,「Y」是12小時後。字母「J」未被使用。剩餘的兩種形式取自ANSI標準X3.51-1975。一個允許明確指示來自UT的偏移量;另一個使用常用的3個字符的字符串來表示北美的時區。

我相信問題涉及如何處理RFC 822日期時間值的區域組件。 Feed格式化程序似乎不處理使用本地差異來指示時區的日期時間。

由於RFC 1123擴展了RFC 822規範,因此可以嘗試使用DateTimeFormatInfo.RFC1123Pattern(「r」)來處理轉換標準日期時間,或者爲RFC 822格式日期編寫自己的分析代碼。另一種選擇是使用第三方框架而不是System.ServiceModel.Syndication命名空間類。

看來有一些known issues帶有日期時間解析和Microsoft正在解決的Rss20FeedFormatter。

+1

謝謝 - 看起來這是在二月份引起了微軟的注意,但它不是固定的然而。 :( – dan90266 2008-11-08 23:56:21

2

有趣。它看起來像日期時間格式不是日期時間分析器自然期望的格式之一。查看Feed類後,它看起來並不像可以在解析器的自己的格式約定中注入,而且它可能使用特定的方案來驗證感覺。

您可以通過修改culture來更改日期時間分析程序的行爲方式。我從來沒有這樣做過,所以我不能肯定它會奏效。

另一個解決方案是首先轉換您正嘗試閱讀的Feed。可能不是最偉大的,但它可以讓你解決這個問題。

祝你好運。

26

基於發佈在bug report to Microsoft about this中的解決方法,我製作了專門用於閱讀具有非標準日期的SyndicationFeeds的XmlReader。

下面的代碼與Microsoft網站的解決方法中的代碼略有不同。使用RFC 1123模式也需要Oppositional's advice

不是簡單地調用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; 

    } 

} 

再次,這是從連接微軟網站上公佈的解決辦法複製幾乎一模一樣以上。 ...除了這一個適合我,而在微軟發佈的那個沒有。

注意:您可能需要做的一點定製是在類的開始處的兩個數組中。根據您的非標準提要可能添加的任何無關字段,您可能需要向這些數組添加更多項目。

+0

看來,你放棄了能夠使用XmlReaderSettings這種方法,即DtdProcessing選項。這些飼料的問題仍然參考rss-0.91.dtd。 – Ant 2010-04-28 11:49:28

1

類似的問題仍然存在,在.NET 4.0中,我決定用的XDocument,而不是直接調用SyndicationFeed工作。我描述了應用方法(特定於我的項目here)。不能說這是最好的解決方案,但如果SyndicationFeed失敗,肯定可以被視爲「備份計劃」。