如何使用lens折叠XML元素的节点?

时间:2019-06-26 19:04:32

标签: xml haskell lens

我正在使用xml-lens包来处理XML。

鉴于Element,我想对其concatMap字段执行类似elementNode :: [Node]的计算。具体来说,满足某些条件的NodeElement应该产生更多的NodeElement,而所有其他情况(其余NodeElement和其他Node构造函数应该产生一个单例列表。然后应将其串联到[Node]中,并用作覆盖给定elementNode的当前Element的值。

我正在努力写出合适的镜头咒语来做到这一点。到目前为止,这是我设法提出的:

over nodes $ concatMapOf someLensMagic (myFun :: Element -> [Node])

它进行类型检查,但是我无法实现someLensMagic。非常感谢您的帮助。

4 个答案:

答案 0 :(得分:1)

如果$(document).ready(function () { AjaxInit(); $(document).ajaxComplete(function () { AjaxInit() }); }); function AjaxInit() { alert("test"); }解释了如何使用myFun构造函数,并且您想为其他NodeElement构造函数提供一个空列表,则可以使用Node

要为其他构造函数提供单例列表,应修改concatMapOf _Element以处理myFun的所有构造函数。然后,您可以使用Node,而不是concatMap myFun。 (在这种情况下,您可以使用concatMapOf,但很难理解。)

由于无法从concatMapOf traverse myFun中提取someLensMagic,因此无法编写将生成单例列表的Element

答案 1 :(得分:1)

最直接的解决方案是much like bergey suggests,在myFun周围编写包装器,以便它可以处理Node而不是Element s:

myFun' :: Node -> [Node]
myFun' n = case n of
    NodeElement el -> myFun el
    _ -> [n]
然后,可以将

myFun'与普通concatMap(而不是concatMapOf)一起使用,以修改nodes字段:

over nodes (concatMap myFun')

碰巧,有一部分 lens 魔术可以用作编写包装器的替代方法。 outside组合器将棱镜变成瞄准功能的透镜,实际上,我们可以编辑功能在特定情况下的功能。实际上,它看起来像这样:

over nodes (concatMap $ set (outside _Element) myFun (:[]))

concatMap的参数的功能类似于(:[]),除非该参数与_Element匹配,在这种情况下,它变为基础元素上的myFun。也就是说,实质上是抽象的模式匹配。为了说明这一点,我们可以尝试使用myFun'模仿上面outside的定义样式:

myFun' :: Node -> [Node]
myFun'
    = outside _Element .~ myFun
    $ \n -> [n]

答案 2 :(得分:0)

一种在Fold中对某些子节点进行不同处理的方法是,根据情况使用to将其置于Either的不同分支中,然后使用{{3 }},该函数可让您将不同的Traversal应用于Either的每个分支。

例如,此函数应返回Node的子Element,其特殊之处在于,对于满足条件的节点,将返回其子节点:

foldDifferently :: (Node -> Bool) -> Fold Element Node
foldDifferently p =
      nodes 
    . folded 
    . to (\n -> if p n then Right n else Left n) 
    . beside id (_Element . nodes . folded)

答案 3 :(得分:0)

我结束了两个连续的concatMap

over nodes (concatMap $ concatMapOf _Element myFun) element

这是次优的解决方案,因此我不会将其标记为答案,也欢迎其他任何建议。