Reputation: 225
I have the following xml :
<list>
<recipient>
<name></name>
<lastname></lastname>
<email></email>
<phone></phone>
<home></home>
</recipient>
<recipient>
</recipient>
</list>
and the following data type :
data Recipient = Recipient { name :: String
, lastname :: String
, email :: String
, phone :: Maybe String
, home :: Maybe String }
What I want to do is read the xml and get back a list of recipients : [Recipient]
To do that I have written the following :
import Text.XML.HXT.Core
readMyXml :: FilePath -> IO [Recipient]
readMyXml path = do
-- lets read the doc
fe <- readFile path
let
-- parse it
doc = readString [withValidate no] fe
-- get all recipient nodes
reps <- getAllRep
-- the part I don't have
-- the only thing wrong in the following is the map function
-- I need an equivalent that runs on hxt trees
return $ map frmRep2Dat reps
-- ^
-- |
-- here
-- end of part I don't have
where
getAllRep = runX $ doc
>>> deep (hasName "list")
>>> multi (hasName "recipient")
frmRep2Dat branch = do
let
-- gets the recipient of a recipient node child
getV name = runX $
branch
>>> deep (hasName name)
>>> removeAllWhiteSpace
>>> deep getText
-- normaly there is no need to check because not maybe fields are
-- mandatory and should not be empty
getVal name = do
val <- getV name
case val of
[] -> ""
[""] -> ""
_ -> head val
-- some maybe wrapping
getMayVal name = do
val <- getV name
case val of
[] -> Nothing
[""] -> Nothing
_ -> Just (head val)
name <- getVal "name"
lastname <- getVal "lastname"
email <- getVal "email"
phone <- getMayVal "phone"
home <- getMayVal "home"
return $ Recipient name lastname email phone home
Any lead as to how to map the tree?
Upvotes: 2
Views: 184
Reputation: 225
Found out that there is no need to iterate throught the tree. HXT already does it.
There is a simpler way of constructing data from xml than the naive one I wrote up.
I replaced the entire readMyXml function by :
readMyXml path = do
fi <- readFile path
let
doc = readString [withValidate no] fi
return =<< runX $ getRecipients doc
wrapStr a = if null a
then Nothing
else Just a
getD a = deep (hasName a)
>>> removeAllWhiteSpace
>>> deep getText
getMD a = getD a
>>^ wrapStr
getRecipients doc = doc
>>> deep (hasName "list")
>>> multi (hasName "recipient")
>>> proc y -> do
nime <- getD "name" -< y
lstn <- getD "lastname" -< y
mail <- getD "email" -< y
phon <- getMD "phone" -< y
homi <- getMD "home" -< y
returnA -< Recipient nime lstn mail phon homi
Now the return of getRecipients applied to the doc defined in the question is [Recipient]
Cheers
Upvotes: 1