我使用XML-conduit构建了一个 GPX 解析器,并且遇到了用于识别元素和跳过不需要的标签的代码过于冗长和脆弱的问题。
识别元素(一个小烦恼)
我通过仅比较nameLocalName
s 来明确忽略名称空间。我想正确的方法是将正确的命名空间硬编码到程序中,并让一个助手构造我的元素名称以便在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*
变体可以为我做到这一点(在没有消耗所有孩子的情况下成功)但是没有表明我缺少一个简单的组合器或应该发送一个补丁的事实 - 是它吗?