Problemas al leer RSS con C#y.net 3.5
syndication (4)
Interesante. Parece que el formateo de fecha y hora no es uno de los esperados naturalmente por el analizador de fecha y hora. Después de mirar las clases de fuentes, no parece que pueda insertarlas en su propia convención de formato para el analizador y es probable que usen un esquema específico para validar la sensación.
Puede modificar cómo se comporta el analizador de fecha y hora modificando la cultura . Nunca lo había hecho antes, así que no puedo decir con certeza que funcionaría.
Otra solución nocturna es transformar primero el feed que estás tratando de leer. Probablemente no sea el mejor, pero podría ayudarlo a resolver el problema.
Buena suerte.
He estado intentando escribir algunas rutinas para leer feeds RSS y ATOM usando las nuevas rutinas disponibles en System.ServiceModel.Syndication, pero desafortunadamente el Rss20FeedFormatter explota en aproximadamente la mitad de los feeds que intento con la siguiente excepción:
An error was encountered when parsing a DateTime value in the XML.
Esto parece ocurrir cada vez que la fuente RSS expresa la fecha de publicación en el siguiente formato:
Jue, 16 Oct 08 14:23:26 -0700
Si el feed expresa la fecha de publicación como GMT, las cosas van bien:
Jue, 16 de oct. 08 21:23:26 GMT
Si hay alguna forma de evitar esto con XMLReaderSettings, no lo he encontrado. ¿Alguien puede ayudar?
Los feeds de sindicación RSS 2.0 utilizan la especificación de fecha y hora RFC 822 al serializar elementos como pubDate y lastBuildDate . La especificación de fecha y hora de RFC 822 es lamentablemente una sintaxis muy flexible para expresar el componente de zona horaria de DateTime.
La zona horaria puede estar indicada de varias maneras. "UT" es Universal Time (anteriormente llamado "Greenwich Mean Time"); "GMT" está permitido como referencia al tiempo universal. El estándar militar usa un solo carácter para cada zona. "Z" es el tiempo universal. "A" indica una hora antes, y "M" indica 12 horas antes; "N" es una hora más tarde, e "Y" es 12 horas después. La letra "J" no se usa. Los otros dos formularios restantes están tomados del estándar ANSI X3.51-1975. Uno permite una indicación explícita de la cantidad de compensación de UT; el otro usa cadenas comunes de 3 caracteres para indicar zonas horarias en América del Norte.
Creo que el problema implica cómo se procesa el componente de zona del valor RFC 822 de fecha y hora. Parece que el formateador de alimentación no maneja los tiempos de fecha que utilizan un diferencial local para indicar el huso horario.
Como RFC 1123 amplía la especificación RFC 822, puede intentar usar DateTimeFormatInfo.RFC1123Pattern ("r") para manejar la conversión de tiempos de fecha problamatic o escribir su propio código de análisis para las fechas formateadas RFC 822. Otra opción sería utilizar un marco de terceros en lugar de las clases de espacio de nombres System.ServiceModel.Syndication.
Parece que hay algunos problemas conocidos con el análisis de fecha y hora y el Rss20FeedFormatter que está siendo procesado por Microsoft.
Un problema similar aún persiste en .NET 4.0 y decidí trabajar con XDocument en lugar de invocar directamente SyndicationFeed . Describí el método aplicado (específico para mi proyecto aquí ). No puedo decir que sea la mejor solución, pero ciertamente puede considerarse un "plan de respaldo" en caso de que SyndicationFeed falle.
Basado en la solución temporal publicada en el informe de fallas a Microsoft sobre esto , hice un XmlReader específicamente para leer SyndicationFeeds que tienen fechas no estándar.
El código siguiente es ligeramente diferente del código en la solución en el sitio de Microsoft. También toma el consejo de Oppositional sobre el uso del patrón RFC 1123.
En lugar de simplemente llamar a XmlReader.Create (), necesita crear XmlReader desde un Stream. Uso la clase WebClient para obtener esa transmisión:
WebClient client = new WebClient();
using (XmlReader reader = new SyndicationFeedXmlReader(client.OpenRead(feedUrl)))
{
SyndicationFeed feed = SyndicationFeed.Load(reader);
....
//do things with the feed
....
}
A continuación se muestra el código para 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;
}
}
Nuevamente, esto se copia casi exactamente de la solución provisional publicada en el sitio de Microsoft en el enlace anterior. ... excepto que este funciona para mí, y el publicado en Microsoft no.
NOTA : Un poco de personalización que puede necesitar hacer es en las dos matrices al comienzo de la clase. Dependiendo de cualquier campo extraño que pueda agregar su feed no estándar, es posible que necesite agregar más elementos a esas matrices.