如果我有这样的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来实现上述目标?
感谢!
答案 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包。
最受欢迎的是,
答案 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
第一次尝试展示了一种从字符串中修剪空格的天真(和错误)方法。