在Haskell中,如何从XML文档中提取字符串?

时间:2009-03-17 13:59:43

标签: xml haskell

如果我有这样的XML文档:

<root>
  <elem name="Greeting">
    Hello
  </elem>
  <elem name="Name">
    Name
  </elem>
</root>

和一些像这样的Haskell类型/数据定义:

 type Name = String
 type Value = String
 data LocalizedString = LS Name Value

我想写一个带有以下签名的Haskell函数:

 getLocalizedStrings :: String -> [LocalizedString]

其中第一个参数是XML文本,返回值是:

 [LS "Greeting" "Hello", LS "Name" "Name"]

我该怎么做?

如果HaXml是最好的工具,我如何使用HaXml来实现上述目标?

感谢!

4 个答案:

答案 0 :(得分:6)

我从来没有真正想过要弄清楚如何使用HaXML从XML文档中提取比特; HXT满足了我的所有需求。

{-# LANGUAGE Arrows #-}
import Data.Maybe
import Text.XML.HXT.Arrow

type Name = String
type Value = String
data LocalizedString = LS Name Value

getLocalizedStrings :: String -> Maybe [LocalizedString]
getLocalizedStrings = (.) listToMaybe . runLA $ xread >>> getRoot

atTag :: ArrowXml a => String -> a XmlTree XmlTree
atTag tag = deep $ isElem >>> hasName tag

getRoot :: ArrowXml a => a XmlTree [LocalizedString]
getRoot = atTag "root" >>> listA getElem

getElem :: ArrowXml a => a XmlTree LocalizedString
getElem = atTag "elem" >>> proc x -> do
    name <- getAttrValue "name" -< x
    value <- getChildren >>> getText -< x
    returnA -< LS name value

你可能想要更多的错误检查(即不要像我一样懒惰地使用atTag;实际上验证<root>是root,<elem>是直接后代,等等,但这对你的例子很好。


现在,如果你需要Arrow的介绍,不幸的是我不知道有什么好的。我自己也学会了“扔进海里学习如何游泳”的方式。

可能有助于记住的一点是proc / -<语法只是基本箭头操作的糖(arr>>>等。 ),就像do / <-只是基本monad操作的糖(return>>=等)。以下是等效的:

getAttrValue "name" &&& (getChildren >>> getText) >>^ uncurry LS

proc x -> do
    name <- getAttrValue "name" -< x
    value <- getChildren >>> getText -< x
    returnA -< LS name value

答案 1 :(得分:3)

使用其中一个XML包。

最受欢迎的是,

  1. 的HaXml
  2. HXT
  3. XML的光
  4. hexpat

答案 2 :(得分:2)

FWIW,HXT似乎有点过分,只需要一个简单的TagSoup:)

答案 3 :(得分:1)

这是我使用TagSoup的第二次尝试(在收到其他人的一些好的输入后):

module Xml where

import Data.Char
import Text.HTML.TagSoup

type SName = String
type SValue = String

data LocalizedString = LS SName SValue
     deriving Show

getLocalizedStrings :: String -> [LocalizedString]
getLocalizedStrings = create . filterTags . parseTags
  where 
    filterTags :: [Tag] -> [Tag]
    filterTags = filter (\x -> isTagOpenName "elem" x || isTagText x)

    create :: [Tag] -> [LocalizedString]
    create (TagOpen "elem" [("name", name)] : TagText text : rest) = 
      LS name (trimWhiteSpace text) : create rest
    create (_:rest) = create rest
    create [] = []               

trimWhiteSpace :: String -> String
trimWhiteSpace = dropWhile isSpace . reverse . dropWhile isSpace . reverse

main = do
  xml <- readFile "xml.xml"  -- xml.xml contains the xml in the original question.
  putStrLn . show . getLocalizedStrings $ xml

第一次尝试展示了一种从字符串中修剪空格的天真(和错误)方法。