tags:

views:

92

answers:

1

I'm having some problems with HXT, though I suspect it's just something I'm missing about arrows.

I have an XML structure like

<str name="field1">value</str>
<lst name="field2"><str>value2</str><str>value3</str></lst>

And internal structure like

data XmlData = XmlStr String | XmlList XmlData

Is there a way to collect elements at a step in an arrow?

getXmlData :: IOSArrow XmlTree (String, XmlData)
getXmlData = (getAttrl >>> getChildren >>> getText) &&& 
      ((filterByType "str" >>> getText >>> arr (\x -> XmlStr x))
      <+> (filterByType "lst" >>> getXmlData))
  where filterByType t = isElem >>> hasName t >>> getChildren

The recursive call to getXmlData needs to collect it's answer and wrap in an XmlList constructor, but I don't know how to collect terms. Currently I'm accomplishing this with some post processing on the output (collecting on the same name), but I would like a better solution.

+1  A: 

In general you can use listA from Control.Arrow.ArrowList to do this. It has type (ArrowList a) => a b c -> a b [c] and is a

combinator for converting an arrow into a determinstic version with all results collected in a single element list.

(See my answers here and here for a concrete example.)

In this specific case you can use the >. combinator with the XmlList constructor as its second argument to accomplish the same thing more concisely.

Travis Brown
>. worked when I moved the getChildren call out of the helper and added some parenthesis. I was curious about the usage for listA but couldn't find an example with it as part of a pipeline. Could you provide a solution with listA?
amccausl
@amccausl: In the first answer linked above we have an non-deterministic arrow with type `a XmlTree (String, String)` and we want to use it with `arr Data.Map.fromList` (of type `a [(String, String)] (M.Map String String)`) to fill a map. `listA` lets us make the types of the arrows match up so that they can be composed.
Travis Brown