Domanda

Ho tentato di scrivere alcune routine per leggere i feed RSS e ATOM utilizzando le nuove routine disponibili in System.ServiceModel.Syndication, ma sfortunatamente Rss20FeedFormatter lancia bombe su circa la metà dei feed che provo con la seguente eccezione:

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

Questo sembra accadere ogni volta che il feed RSS esprime la data di pubblicazione nel seguente formato:

  

Gio 16 Ott 08 14:23:26 -0700

Se il feed esprime la data di pubblicazione come GMT, le cose vanno bene:

  

Gio 16 Ott 08 21:23:26 GMT

Se c'è un modo per aggirare questo problema con XMLReaderSettings, non l'ho trovato. Qualcuno può aiutare?

È stato utile?

Soluzione

I feed di syndication formattati RSS 2.0 utilizzano le specifica data-ora RFC 822 durante la serializzazione elementi come pubDate e lastBuildDate . La specifica data-ora RFC 822 è purtroppo una sintassi molto 'flessibile' per esprimere il componente fuso orario di un DateTime.

Il fuso orario può essere indicato in diversi modi. & Quot; UT " è Universal Time (precedentemente chiamato "quotazione di Greenwich"); & Quot; GMT " è consentito come riferimento a Universal Time. Lo standard militare utilizza un singolo personaggio per ogni zona. & Quot; Z " è il tempo universale. & Quot; A " indica un'ora prima e "M" indica 12 ore prima; & Quot; N " un'ora dopo, e "Y" 12 ore dopo. La lettera "J" non viene utilizzato. Le altre due forme rimanenti sono prese dallo standard ANSI X3.51-1975. Uno consente l'indicazione esplicita della quantità di offset da UT; l'altro usa stringhe di 3 caratteri comuni per indicare i fusi orari in Nord America.

Credo che il problema riguardi il modo in cui viene elaborato il componente zona del valore data-ora RFC 822. Il formatter del feed sembra non gestire le date-ora che utilizzano un differenziale locale per indicare il fuso orario.

Poiché RFC 1123 estende la specifica RFC 822, è possibile provare a utilizzare DateTimeFormatInfo.RFC1123Pattern (" r ") per gestire la conversione di date-orari probatici o scrivere il proprio codice di analisi per le date formattate RFC 822. Un'altra opzione sarebbe quella di utilizzare un framework di terze parti anziché le classi dello spazio dei nomi System.ServiceModel.Syndication.

Sembra che ci siano alcuni problemi noti con data- analisi del tempo e Rss20FeedFormatter che stanno per essere risolti da Microsoft.

Altri suggerimenti

Basato sulla soluzione alternativa pubblicata nella segnalazione di bug a Microsoft su questo ho creato un XmlReader appositamente per la lettura di SyndicationFeeds con date non standard.

Il codice seguente è leggermente diverso dal codice nella soluzione alternativa sul sito di Microsoft. Ci vuole anche I consigli dell'opposizione su usando il modello RFC 1123.

Invece di chiamare semplicemente XmlReader.Create () è necessario creare XmlReader da uno stream. Uso la classe WebClient per ottenere quel flusso:

WebClient client = new WebClient();
using (XmlReader reader = new SyndicationFeedXmlReader(client.OpenRead(feedUrl)))
{
    SyndicationFeed feed = SyndicationFeed.Load(reader);
    ....
    //do things with the feed
    ....
}

Di seguito è riportato il codice per 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;

    }

}

Ancora una volta, questo viene copiato quasi esattamente dalla soluzione alternativa pubblicata sul sito Microsoft nel collegamento sopra. ... tranne che questo funziona per me, e quello pubblicato su Microsoft no.

NOTA : un po 'di personalizzazione che potresti dover fare è nei due array all'inizio della lezione. A seconda dei campi estranei che potrebbero essere aggiunti dal feed non standard, potrebbe essere necessario aggiungere più elementi a tali array.

Interessante. Sembra che la formattazione del datetime non sia una di quelle naturalmente previste dal parser del datetime. Dopo aver esaminato le classi di feed non sembra che tu possa iniettare la tua convenzione di formattazione per il parser e probabilmente usa uno schema specifico per convalidare il feeling.

Potresti essere in grado di cambiare il comportamento del parser datetime modificando la cultura . Non l'ho mai fatto prima, quindi non posso dire con certezza che funzionerebbe.

Un'altra notte di soluzione è quella di trasformare prima il feed che stai cercando di leggere. Probabilmente non il massimo, ma potrebbe aggirare il problema.

Buona fortuna.

Un problema simile persiste ancora in .NET 4.0 e ho deciso di lavorare con XDocument invece di invocare direttamente SyndicationFeed . Ho descritto il metodo applicato (specifico per il mio progetto qui ). Non posso dire che sia la soluzione migliore, ma sicuramente può essere considerato un "piano di backup" nel caso in cui SyndicationFeed fallisca.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top