2012-06-04 38 views
4

我使用XML-conduit構建了一個GPX分析器,並且存在用於標識元素和跳過不需要的標記的過於冗長和易碎代碼的問題。使用xml導管的易碎和冗長的代碼

識別元素(一個小麻煩)

我明確地只比較nameLocalName其實忽略了命名空間。我猜正確的方法是將正確的命名空間硬編碼到程序中,並且有一個幫助器構造我的元素名稱以便在tag*函數中進行比較?這有點煩人,因爲我必須支持至少兩個不同的名稱空間(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*變體會爲我做到這一點(成功沒有所有的孩子被消費),但事實是,沒有暗示我錯過了一個簡單的combinator或應該發送補丁 - 這是什麼?

回答

2

如果根本沒有使用名稱空間,那麼使用Data.Conduit.List.map stripNamespace之類的東西就可以完全去除它們。

坦率地說,我並沒有真正使用我自己的流媒體界面;幾乎我所有的工作都涉及DOM(Text.XML)或光標界面。所以完全有可能缺少組合器。但在這種情況下,我相信你可以簡化實現很多,因爲tagPredicate不應該允許內部Sink讀過元素的末尾。所以,你可以重寫skipTagAndContents爲:

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

您應該測試只是刪除它,我就可以記住一些流媒體接口的細節之前不正確。

+0

我有類似的代碼,它會導致錯誤,如'XmlException {xmlErrorMessage ='期望的結束標記爲:名稱{nameLocalName = \「metadata \」,nameNamespace = Just \「http://www.topografix.com/ GPX/1/1 \「,namePrefix = Nothing}」,xmlBadInput = Nothing}'。所以現在我會堅持我的實現,明確表示結束標記。 stripNamespace會清理一些東西 - 謝謝! –