我想要使用xml-conduit
,特别是Text.XML.Stream.Parse
,以便从大型XML文件中懒惰地提取对象列表。Streaming xml-conduit解析结果
作为测试用例,我使用了the recently re-released StackOverflow data dumps。为了简单起见,我打算从stackoverflow.com-Users.7z
中提取所有用户名。即使该文件是一个.7z
,file
说,这是刚刚的bzip2压缩数据(有可能是在文件的结尾部分7zip的东西,但现在我不关心)。
的XML的简化版本将
<users>
<row id="1" DisplayName="StackOverflow"/>
...
<row id="2597135" DisplayName="Uli Köhler"/>
...
</users>
基于this previous Q&A和示例on Hackage流读取示例XML在BZ2-ED的形式完美的作品对我来说
然而,在使用runghc
时运行下面的程序,它运行时不打印任何输出:
{-# LANGUAGE OverloadedStrings #-}
import Data.Conduit (runResourceT, ($$), ($=))
import qualified Data.Conduit.Binary as CB
import Data.Conduit.BZlib
import Data.Conduit
import Data.Text (Text)
import System.IO
import Text.XML.Stream.Parse
import Control.Applicative ((<*))
data User = User {name :: Text} deriving (Show)
parseUserRow = tagName "row" (requireAttr "DisplayName" <* ignoreAttrs) $ \displayName -> do
return $ User displayName
parseUsers = tagNoAttr "users" $ many parseUserRow
main = do
users <- runResourceT $ CB.sourceFile "stackoverflow.com-Users.7z" $= bunzip2 $= parseBytes def $$ force "users required" parseUsers
putStrLn $ unlines $ map show users
我假设这个问题因为Haskell试图在开始打印之前深入评估users
列表。该理论得到了该程序的内存使用量的支持,该程序的持续增长速度约为每秒2%(来源:htop)。
我如何“活流”结果到stdout?我认为这是可能的最后添加另一个像$$ CB.sinkFile "output.txt"
管道声明。然而,这个特定的版本需要Conduit
输出ByteString
。你能否指出我正确的方向从哪里出发?
任何帮助将不胜感激!
非常感谢您抽出时间来写这个!即使我仍然不理解你使用的任何概念(由于缺乏Haskell知识),你真的理解我的问题并提供了一个很好的解决方案。我设法创建了一个解析文件而不是无限流的示例(它花费了一些时间,我会将其作为下面的答案张贴以供进一步参考! –
在库的当前版本中,yieldWhileJust已放置在Text中。带有manyYield名称的XML.Stream.Parse。 –