我正在尝试解析XML,但我想过滤并从特定节点中仅提取确定数量的子节点。例如:
<root>
<node id="a" />
<node id="b" />
<node id="c" />
<node id="d" />
</root>
然后,如果我执行箭头getChildren >>> myFilter 2
,我只会返回ID为“a”和“b”的节点。
Intuition表示我应该使用State Arrow跟踪,但我不知道该怎么做。
我试着自己做,但这不是我想要的,看起来不是很优雅,也不行。我尝试使用runSLA
和整数参数作为初始状态运行我的箭头链,然后定义:
takeOnly :: IOSLA Int XmlTree XmlTree
takeOnly = changeState (\s b -> s-1)
>>> accessState (\s b -> if s >= 0 then b else Nothing)
但当然我无法返回Nothing
,我需要返回一个XmlTree。但我根本不想退货!
可能有更好的方法。你能救我吗?
感谢您的时间和帮助!
答案 0 :(得分:4)
在Control.Arrow.ArrowList中使用组合器来处理这类事情可能更为惯用。
该软件包专门提供(>>.) :: a b c -> ([c] -> [d]) -> a b d
,这是一个“用于将列表箭头的结果转换为另一个列表的组合器”。这允许我们在此上下文中使用我们已有的take
函数用于列表。
以下是您可以使用它的快速版本:
module Main where
import Text.XML.HXT.Arrow
takeOnly :: (ArrowXml a) => Int -> a XmlTree XmlTree
takeOnly n = getChildren >>. take n
main = do
let xml = "<root><node id='a' /><node id='b' />\
\<node id='c' /><node id='d' /></root>"
print =<< runX (readString [] xml >>> getChildren >>> takeOnly 2)
我认为这与您所寻找的大致相符:
travis@sidmouth% ./ArrowTake
[NTree (XTag (LP node) [NTree (XAttr (LP id)) [NTree (XText "a") []]]) [],
NTree (XTag (LP node) [NTree (XAttr (LP id)) [NTree (XText "b") []]]) []]
不需要IOSLA
。请注意,我也稍微更改了函数类型 - 这个版本对我来说似乎更好,但您可以轻松地将其转换为更类似于您的版本中的类型。