我正在尝试使用Control.Arrow.ArrowTree来构建一个HTML处理箭头,该箭头在给定树中第一次成功转换(深度优先)后停止。即类型为
的函数processFirst :: (ArrowTree a, Tree t) => a (t b) (t b) -> a (t b) (t b)
例如,要将类“first”添加到HTML文档中的第一个列表项,可以构建箭头
processFirst (hasName "li" `guards` addAttr "class" "first")
我对HXT很陌生,我现在已经阅读了API文档几个小时,并试图弄清楚如何实现processFirst
,但我无法适应所有拼凑在一起。 processTopDownUntil
一开始听起来很有希望,但该函数只停止对特定子树的处理,因此它仍然会转换除嵌套子元素之外的所有元素。
答案 0 :(得分:1)
我不确定我是否完全理解这个问题,但我会尽力回答:)
让我们尝试下一个:
test = flip runLA undefined $ xshow $
constA "<xml><x>X1</x><x>X2</x></xml>" >>> xread
>>> processFirst (hasName "x" `guards` addAttr "class" "first")
processFirst f = f `orElse` processChildren (processFirst f)
processFirst
的定义与processTopDownUntil
的定义相同。此函数将输出如下内容:
["<xml><x class=\"first\">X1</x><x class=\"first\">X2</x></xml>"]
问题应该很清楚 - 如果顶级节点f
失败,那么将为每个孩子调用processFirst
。如果某个孩子f
成功,我们需要一种方法来中止其他孩子的处理。
可能的解决方案是使用状态箭头:
processFirst f = fromSLA False process
where
process = (getState >>> isA not)
`guards`
(f >>> changeState (const $ const True))
`orElse`
processChildren process
想法是在f
成功时设置状态并在处理之前检查它。
注意:现在f
应为SLA
箭头。如果它不是您想要的,您可以尝试收集所有孩子(使用例如listA
)并纯粹处理它们。
所以,解决方案并不理想,但我希望它能帮助你作为一个起点。