HXT: How to stop processing after the first successful transformation?
Question
I'm trying to use Control.Arrow.ArrowTree to build a HTML processing arrow that stops after the first successful transformation (depth-first) in the given tree. I.e. a function with the type
processFirst :: (ArrowTree a, Tree t) => a (t b) (t b) -> a (t b) (t b)
For example, to add the class "first" to the very first list item in a HTML document, one could build the arrow
processFirst (hasName "li" `guards` addAttr "class" "first")
I'm rather new to HXT and I've been reading the API docs for a couple of hours now and trying to figure out how to implement processFirst
, but I haven't been able to fit all the pieces together. processTopDownUntil
sounded promising at first, but that function only stops the processing for a particular sub-tree, so it will still transform all elements excluding nested ones.
Solution
I'm not sure I completely understood the question, but I'll try to answer :)
Lets try the next:
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)
The definition of processFirst
is the same as definition of processTopDownUntil
. This function will output something like:
["<xml><x class=\"first\">X1</x><x class=\"first\">X2</x></xml>"]
The problem should be clear -- if f
fails for the top node, then processFirst
will be called for every child. We need a way to abort processing of the other children if f
succeeded on some child.
Possible solution could be to use state arrow:
processFirst f = fromSLA False process
where
process = (getState >>> isA not)
`guards`
(f >>> changeState (const $ const True))
`orElse`
processChildren process
The idea is to set state when f
succeeded and check it before processing.
Note: now f
should be SLA
arrow. If it is not what you want, the you can try to collect all children (using e.g. listA
) and process them purely.
So, the solution is not ideal, but I hope it will help you as a starting point.