代码之家  ›  专栏  ›  技术社区  ›  Tim Stewart

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

  •  7
  • Tim Stewart  · 技术社区  · 17 年前

    <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 回复  |  直到 17 年前
        1
  •  6
  •   ephemient    17 年前

    实际上,我从来没有想过如何使用 HaXML ; 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> <elem> 是直系后裔,等等),但这在您的示例中效果很好。


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

    需要记住的是 proc / -< arr >>> 等等),就像 do <- 对于基本的单子运算来说,糖就是简单的糖( return , >>= 等)。以下是等效的:

    getAttrValue "name" &&& (getChildren >>> getText) >>^ uncurry LS
    
    proc x -> do
        name <- getAttrValue "name" -< x
        value <- getChildren >>> getText -< x
        returnA -< LS name value
    
        2
  •  3
  •   Don Stewart    17 年前

    使用其中一个XML包。

    最受欢迎的是,

    1. haxml
    2. hxt
    3. xml灯
    4. 赫克斯巴特
        3
  •  2
  •   ADEpt    17 年前

        4
  •  1
  •   Tim Stewart    17 年前

    第二 尝试使用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
    

    第一次尝试展示了一种简单(且有缺陷)的方法,用于修剪字符串中的空白。

    推荐文章