xml - 使用 xml-conduit 的脆弱和冗长的代码

标签 xml haskell conduit

我使用 XML-conduit 构建了一个 GPX 解析器并且在识别元素和跳过不需要的标签时遇到了过于冗长和脆弱的代码问题。

识别元素(一个小麻烦)

我通过仅比较 nameLocalName 来明确忽略 namespace 。我想正确的方法是将正确的命名空间硬编码到程序中,并让助手构造我的元素名称以便在 tag* 函数中进行比较?这有点烦人,因为我必须支持至少两个不同的 namespace (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* 变体可以为我做这件事(在没有所有 child 被消耗的情况下成功)但是没有这个事实表明我缺少一个简单的组合器或者应该发送补丁 - 这是什么?

最佳答案

如果您根本不使用命名空间,使用 Data.Conduit.List.map stripNamespace 之类的东西将它们完全剥离可能是最简单的。

坦率地说,我并没有真正使用自己经常使用的流媒体界面;我几乎所有的工作都涉及 DOM (Text.XML) 或游标界面。所以完全有可能缺少组合器。但在这种情况下,我相信您可以大大简化实现,因为 tagPredicate 不应允许内部 Sink 读取元素末尾之后的内容。所以你可以重写 skipTagAndContents 为:

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

你应该在把它放进去之前测试一下,我可能会错误地记住流接口(interface)的一些细节。

关于xml - 使用 xml-conduit 的脆弱和冗长的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10875179/

相关文章:

c# - 如何反序列化 XML 数组项?

android - 错误 : Error parsing xml: Unbound Prefix when using StaggeredGridView

haskell - 2 级类型和函数组合的类型错误

list - 管道,替换列表?

xml - Intellisense 无法使用 XML 引号 - 键入双引号会打开两个引号,再次键入双引号不会移动光标

html - XPath根据标签选择表格单元格?

haskell - 在 Haskell 中编写汇编程序 - 带状态的 mapM?

list - 在 Haskell 中将分层数据结构转换为平面数据结构

haskell - 将导管合二为一

networking - Http-Conduit 频繁连接失败