Вопрос

Я пытался написать несколько процедур для чтения каналов RSS и ATOM, используя новые процедуры, доступные в System.ServiceModel.Syndicate, но, к сожалению, Rss20FeedFormatter не работает примерно на половине каналов, которые я пытаюсь использовать, за следующим исключением:

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

Похоже, это происходит всякий раз, когда RSS-канал выражает дату публикации в следующем формате:

Чт, 16 окт. 08 14:23:26 -0700

Если в ленте дата публикации указана как GMT, все идет хорошо:

Чт, 16 октября 2008 г., 21:23:26 GMT

Если и есть способ обойти это с помощью XMLReaderSettings, то я его не нашел.Может ли кто-нибудь помочь?

Это было полезно?

Решение

В каналах синдикации в формате RSS 2.0 используется Спецификация даты и времени RFC 822 при сериализации таких элементов, как pubDate и последняя дата сборки.Спецификация даты и времени RFC 822, к сожалению, является очень «гибким» синтаксисом для выражения компонента часового пояса DateTime.

Часовой пояс может быть указан несколькими способами.«UT» — всемирное время (ранее называвшееся «средним временем по Гринвичу»);«GMT» разрешено использовать в качестве обозначения всемирного времени.Военный стандарт использует один символ для каждой зоны.«Z» — всемирное время.«А» означает на час раньше, а «М» — на 12 часов раньше;«N» — на час позже, «Y» — на 12 часов позже.Буква «J» не используется.Остальные две формы взяты из стандарта ANSI X3.51-1975.Один позволяет явно указать величину смещения от UT;другой использует обычные трехсимвольные строки для обозначения часовых поясов в Северной Америке.

Я считаю, что проблема заключается в том, как зона Компонент значения даты и времени RFC 822 обрабатывается.Средство форматирования каналов, похоже, не обрабатывает дату и время, которые используют местный дифференциал для указания часового пояса.

Поскольку RFC 1123 расширяет спецификацию RFC 822, вы можете попробовать использовать DateTimeFormatInfo.RFC1123Pattern («r») для обработки проблемного преобразования даты и времени или напишите собственный код синтаксического анализа дат в формате RFC 822.Другой вариант — использовать стороннюю платформу вместо классов пространства имен System.ServiceModel.Syndicate.

Кажется, есть некоторые Известные вопросы с анализом даты и времени и Rss20FeedFormatter, которые находятся в процессе рассмотрения Microsoft.

Другие советы

На основе обходного пути, опубликованного в отчет об ошибке в Microsoft об этом Я создал XmlReader специально для чтения SyndictionFeeds с нестандартными датами.

Код ниже немного отличается от кода обходного пути на сайте Microsoft.Это также требует Совет оппозиционера об использовании шаблона RFC 1123.

Вместо простого вызова XmlReader.Create() вам нужно создать XmlReader из потока.Я использую класс WebClient для получения этого потока:

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

Ниже приведен код SyndictionFeedXmlReader:

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 по ссылке выше.... за исключением того, что этот работает у меня, а тот, что опубликован в Microsoft, - нет.

ПРИМЕЧАНИЕ:Возможно, вам придется внести небольшую настройку в два массива в начале класса.В зависимости от посторонних полей, которые может добавить ваш нестандартный фид, вам может потребоваться добавить в эти массивы дополнительные элементы.

Интересный.Похоже, что форматирование даты и времени не является одним из тех, которые естественным образом ожидаются парсером даты и времени.После просмотра классов каналов кажется, что вы не можете внедрить собственное соглашение о форматировании для синтаксического анализатора, и они, вероятно, используют определенную схему для проверки ощущения.

Вы можете изменить поведение парсера datetime, изменив культура.Я никогда раньше этого не делал, поэтому не могу сказать наверняка, что это сработает.

Еще одно решение — сначала преобразовать канал, который вы пытаетесь прочитать.Вероятно, не самое лучшее, но это может помочь вам решить проблему.

Удачи.

Подобная проблема все еще сохраняется в .NET 4.0, и я решил поработать с XДокумент вместо прямого вызова Лента синдикации.Я описал примененный метод (специфичный для моего проекта здесь).Не могу сказать, что это лучшее решение, но его определенно можно рассматривать как «запасной план» на случай, если Лента синдикации терпит неудачу.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top