質問

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

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

これは、RSSフィードが次の形式で公開日を表すたびに発生するようです:

  

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

フィードで公開日がGMTとして表現されている場合、問題はありません:

  

木、08 Oct 10 21:23:26 GMT

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

役に立ちましたか?

解決

RSS 2.0形式のシンジケーションフィードは、シリアル化するときに RFC 822日時指定を利用します pubDate lastBuildDate などの要素。残念ながら、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日時値の zone コンポーネントの処理方法が関係していると思います。フィードフォーマッタは、ローカル差分を使用してタイムゾーンを示す日時を処理していないようです。

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

日付に関する既知の問題があるようです。マイクロソフトによる対応の過程にある時間解析とRss20FeedFormatter。

他のヒント

バグレポートに投稿された回避策に基づくこれについてマイクロソフトに、標準外の日付を持つSyndicationFeedsを読み取るためのXmlReaderを作成しました。

以下のコードは、Microsoftのサイトでの回避策のコードとわずかに異なります。また、異議申し立てのアドバイスも必要です。 RFC 1123パターンを使用します。

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つの配列をカスタマイズする必要がある場合があります。非標準フィードが追加する可能性のある無関係なフィールドによっては、それらの配列にさらにアイテムを追加する必要があります。

興味深い。日付時刻の書式設定は、日付時刻パーサーが当然期待するものの1つではないようです。フィードクラスを確認した後、パーサーの独自の書式設定規則を挿入できるようには見えず、フィールを検証するために特定のスキームを使用する可能性があります。

カルチャを変更することにより、日付時刻パーサーの動作を変更できる場合があります。 。私は前にそれをやったことがないので、それがうまくいくと確信することはできません。

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

がんばって。

.NET 4.0でも同様の問題が解決しないため、 SyndicationFeed を直接呼び出す代わりに、 XDocument を使用することにしました。適用した方法を説明しました(私のプロジェクトこちらに固有)。それが最善の解決策であるとは言えませんが、確かに「バックアップ計画」と考えることができます。 SyndicationFeed が失敗した場合。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top