16

System.ServiceModel.Syndication で利用可能な新しいルーチンを使用して、RSS および ATOM フィードを読み取るルーチンをいくつか作成しようとしましたが、残念ながら、次の例外を除いて、Rss20FeedFormatter は私が試したフィードの約半分を爆破します。

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

これは、RSS フィードが公開日を次の形式で表現している場合に発生するようです。

木、16 10 月 08 14:23:26 -0700

フィードが発行日を GMT として表している場合、問題はありません。

2008 年 10 月 16 日(木)21:23:26 GMT

XMLReaderSettings でこれを回避する方法がある場合、私はそれを見つけていません。誰でも手伝ってもらえますか?

4

4 に答える 4

26

これに関するMicrosoft へのバグ レポートに投稿された回避策に基づいて、非標準の日付を持つ SyndicationFeeds を読み取るための XmlReader を作成しました。

以下のコードは、Microsoft のサイトにある回避策のコードとは少し異なります。また、RFC 1123 パターンの使用に関するOppositional のアドバイスも取り入れています。

単純に 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 サイトに掲載されている回避策からほぼ正確にコピーされています。...ただし、これは私には機能しますが、Microsoft に投稿されたものは機能しませんでした。

: カスタマイズが必要になる可能性があるのは、クラスの最初にある 2 つの配列です。非標準フィードが追加する可能性のある不要なフィールドによっては、それらの配列にさらに項目を追加する必要がある場合があります。

于 2010-04-27T20:16:18.177 に答える
9

RSS 2.0 形式のシンジケーション フィードは、pubDatelastBuildDateなどの要素をシリアル化するときに、 RFC 822 の日時仕様を利用します。残念ながら、RFC 822 の日付と時刻の仕様は、DateTime のタイムゾーン コンポーネントを表現するための非常に「柔軟な」構文です。

タイムゾーンは、いくつかの方法で示すことができます。「UT」は世界時 (以前は「グリニッジ標準時」と呼ばれていました) です。「GMT」は世界時への参照として許可されています。軍事規格では、ゾーンごとに 1 文字を使用します。「Z」は世界時です。「A」は1時間早く、「M」は12時間早く、「N」は1時間後、「Y」は12時間後です。文字「J」は使用されません。残りの 2 つの形式は、ANSI 標準 X3.51-1975 から取られています。UT からのオフセット量を明示的に示すことができます。もう 1 つは、北米のタイム ゾーンを示すために一般的な 3 文字の文字列を使用します。

この問題は、RFC 822 の日時値のゾーンコンポーネントがどのように処理されるかに関係していると思います。フィード フォーマッタは、ローカル差分を使用してタイム ゾーンを示す日時を処理していないようです。

RFC 1123 は RFC 822 仕様を拡張するため、DateTimeFormatInfo.RFC1123Pattern ("r") を使用して問題のある日付時刻の変換を処理したり、RFC 822 形式の日付用に独自の解析コードを記述したりできます。もう 1 つのオプションは、System.ServiceModel.Syndication 名前空間クラスの代わりにサード パーティのフレームワークを使用することです。

日時の解析と Rss20FeedFormatterに関するいくつかの既知の問題があり、Microsoft によって対処されているようです。

于 2008-11-04T19:37:59.237 に答える
2

面白い。日時の書式設定は、日時パーサーによって自然に期待されるものの 1 つではないようです。フィード クラスを調べたところ、パーサーに独自の書式設定規則を挿入できるようには見えず、フィールを検証するために特定のスキームを使用している可能性があります。

カルチャを変更することで、日時パーサーの動作を変更できる場合があります。今までやったことがないので、確実にうまくいくとは言えません。

別の解決策の夜は、最初に読み込もうとしているフィードを変換することです。おそらく最大ではありませんが、問題を回避できる可能性があります。

幸運を。

于 2008-10-19T03:06:12.437 に答える
1

同様の問題が .NET 4.0 にも残っているため、SyndicationFeedを直接呼び出すのではなく、XDocumentを使用することにしました。適用された方法について説明しました(ここで私のプロジェクトに固有です)。これが最善の解決策とは言えませんが、SyndicationFeedが失敗した場合の「バックアップ プラン」と見なすことはできます。

于 2010-09-13T04:23:31.107 に答える