27

到目前为止,我看到的所有使用 Haskell XML 工具包 HXT 的示例都runX用于执行解析器。runX在 IO monad 内部运行。有没有办法在 IO 之外使用这个 XML 解析器?对我来说似乎是一个纯粹的操作,不明白为什么我被迫在 IO 里面。

4

2 回答 2

27

您可以使用 HXTxreadrunLA解析IO.

xread具有以下类型:

xread :: ArrowXml a => a String XmlTree

这意味着您可以使用任何类型的箭头组合它(ArrowXml a) => a XmlTree Whatever以获得a String Whatever.

runLA就像runX,但对于类型的东西LA

runLA :: LA a b -> a -> [b]

LA是 的一个实例ArrowXml

综上所述,我对您上一个问题的回答的以下版本使用 HXT 来解析包含格式良好的 XML 的字符串,而无需IO涉及任何内容:

{-# LANGUAGE Arrows #-}
module Main where

import qualified Data.Map as M
import Text.XML.HXT.Arrow

classes :: (ArrowXml a) => a XmlTree (M.Map String String)
classes = listA (divs >>> pairs) >>> arr M.fromList
  where
    divs = getChildren >>> hasName "div"
    pairs = proc div -> do
      cls <- getAttrValue "class" -< div
      val <- deep getText         -< div
      returnA -< (cls, val)

getValues :: (ArrowXml a) => [String] -> a XmlTree (String, Maybe String)
getValues cs = classes >>> arr (zip cs . lookupValues cs) >>> unlistA
  where lookupValues cs m = map (flip M.lookup m) cs

xml = "<div><div class='c1'>a</div><div class='c2'>b</div>\
      \<div class='c3'>123</div><div class='c4'>234</div></div>"

values :: [(String, Maybe String)]
values = runLA (xread >>> getValues ["c1", "c2", "c3", "c4"]) xml

main = print values

classes并且getValues与之前的版本相似,只是做了一些小的改动以适应预期的输入和输出。主要区别在于这里我们使用xreadandrunLA而不是readStringand runX

能够以ByteString类似的方式阅读像懒惰的东西会很好,但据我所知,目前 HXT 无法做到这一点。


其他几件事:您可以在没有 的情况下以这种方式解析字符串IO,但尽可能使用它可能会更好runX:它使您可以更好地控制解析器的配置、错误消息等。

另外:我试图使示例中的代码简单明了且易于扩展,但是如果您愿意,可以使用组合Control.ArrowControl.Arrow.ArrowList更简洁地使用箭头。以下是 的等价定义classes,例如:

classes = (getChildren >>> hasName "div" >>> pairs) >. M.fromList
  where pairs = getAttrValue "class" &&& deep getText
于 2010-10-10T19:11:53.197 回答
1

Travis Brown 的回答非常有帮助。我只想在这里添加我自己的解决方案,我认为它更通用(使用相同的功能,只是忽略特定问题的问题)。

我以前不喜欢:

upIO      :: XmlPickler a => String -> IO [a]
upIO str   = runX $ readString [] str >>> arrL (maybeToList . unpickleDoc xpickle)

我可以改成这样:

upPure    :: XmlPickler a => String -> [a]
upPure str = runLA (xreadDoc >>> arrL (maybeToList . unpickleDoc xpickle)) str

我完全同意他的观点,这样做可以减少对解析器等配置的控制,这是不幸的。

于 2014-10-21T09:22:55.520 回答