[Haskell-cafe] HaXml question

Albert Lai trebla at vex.net
Thu Aug 31 22:22:09 EDT 2006

Tim Newsham <newsham at lava.net> writes:

> I thought this one would be easy but I'm starting to think its not.
> I am playing with HaXml and I want to transform an XML tree into
> another tree.  The transforms are simple enough, but the kicker
> is that I want them to be "stateful."  In this example, the state
> is a random number generator.  So the transformation depends on
> the current node and the random number generator state.  I want
> to transform every node in the tree.

Indeed, the HaXml functions are pure, and in particular foldXml does
not thread a state through.

To introduce state, you provide your own state monad (fortunately
there is always Control.Monad.State).  To traverse the whole tree in
this monad, you write your own recursion and deconstruct the nodes
yourself (because foldXml is too specific to be re-usable).

Here is my example.  It replaces attribute values by random integers
between 0 and 99, so it is a similar task but slightly different from
yours.  Some names are inspired by yours, but I have simplified their
nature: The state I thread through is not a stream of generators, but
rather a stream of numbers; as long as this stream comes from
Random.randomRs, I'm good.

import Text.XML.HaXml
import Control.Monad.State
import Random

newtweak :: [Int] -> CFilter
newtweak xs c = [evalState (reco c) xs]

reco :: Content -> State [Int] Content
reco (CElem (Elem nm ats cs)) =
    do { ats' <- mapM newtweakAttr ats
       ; cs' <- mapM reco cs
       ; return (CElem (Elem nm ats' cs'))
reco c = return c

newtweakAttr (k,_) =
    do { n <- gets head
       ; modify tail
       ; return (k, AttValue[Left (show n)])

main = do
    gen <- getStdGen
    processXmlWith (newtweak (randomRs (0,99) gen))

More information about the Haskell-Cafe mailing list