4

私はXML コンジットを使用して GPX パーサーを構築しましたが、要素を識別して不要なタグをスキップするための過度に冗長で脆弱なコードに問題がありました。

要素の識別 (マイナーな煩わしさ)

sのみを比較して、名前空間を明示的に無視していnameLocalNameます。tag*正しい名前空間をプログラムにハードコードし、関数で比較するためにヘルパーに要素名を作成させるのが正しい方法だと思いますか? これは、少なくとも 2 つの異なる名前空間 (GPX 1.1 と 1.0) をサポートする必要があるため、少し面倒です。これらの名前空間は十分に類似しているため、コードを変更する必要はありません。

スキップ要素

GPX は大きく、カスタム拡張機能のセットはより大きくなります。私が構築しているツールは限られた情報しか必要としないため、特定のタグとそのすべてのサブ要素を無視することにしました。例えば:

<trkpnt lat="45.19843" lon="-122.428">
    <ele>4</ele>
    <time>...</time>
    <extensions>
         ...
    </extensions>
</trkpnt>

多数のサブ要素を持つ類似のタグを無視するためextensionsに、最後の要素まで要素を消費するシンクを作成しましたEvent

skipTagAndContents :: (MonadThrow m) => Text -> Sink Event m (Maybe ())
skipTagAndContents n = tagPredicate ((== n) . nameLocalName)
                                    ignoreAttrs
                                    (const $ many (skipElements n) >> return ())

skipElements t = do
        x <- await
        case x of
                Just (EventEndElement n) | nameLocalName n == t -> Done x Nothing
                Nothing -> Done x Nothing
                _ -> return (Just ())

私のためにこれを行うバリアントがあるはずtag*です(すべての子が消費されることなく成功します)が、単純なコンビネーターが不足しているか、パッチを送信する必要があることを示唆していないという事実はありますか?

4

1 に答える 1

2

名前空間をまったく使用していない場合は、Data.Conduit.List.map stripNamespace.

率直に言って、ストリーミング インターフェイスはあまり使用していません。私の仕事のほとんどすべてに、DOM ( Text.XML) またはカーソル インターフェイスが関係しています。したがって、コンビネータが欠落している可能性は十分にあります。tagPredicateしかし、この場合、内部Sink要素が要素の末尾を超えて読み取れるようにするべきではないため、実装を大幅に簡素化できると思います。したがって、次のように書き換えることができますskipTagAndContents

tagPredicate ((== n) . nameLocalName) ignoreAttrs (const Data.Conduit.List.sinkNull)

ドロップする前にテストする必要があります。ストリーミング インターフェイスの詳細の一部を間違って記憶している可能性があります。

于 2012-06-04T03:44:12.087 に答える