2

我有以下 xml:

<list>
    <recipient>
        <name></name>
        <lastname></lastname>
        <email></email>
        <phone></phone>
        <home></home>
    </recipient>
    <recipient>
    </recipient>
</list>

和以下数据类型:

data Recipient = Recipient { name     :: String
                           , lastname :: String
                           , email    :: String
                           , phone    :: Maybe String
                           , home     :: Maybe String }

我想要做的是读取 xml 并取回收件人列表:[收件人]
为此,我编写了以下内容:

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

关于如何映射树的任何线索?

4

1 回答 1

1

发现不需要遍历树。HXT 已经做到了。有一种从 xml 构造数据的方法比我写的幼稚方法更简单。
我将整个 readMyXml 函数替换为:

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

现在应用于问题中定义的文档的 getRecipients 的返回是 [Recipient]
Cheers

于 2013-09-28T21:13:49.227 回答