- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我想使用 xml-conduit
, 具体来说 Text.XML.Stream.Parse
为了从大型 XML 文件中延迟提取对象列表。
作为测试用例,我使用 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流式读取 bz2-ed 形式的示例 XML 非常适合我
但是,当使用 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)支持这一理论。
如何将结果“直播”到标准输出?我认为这可以通过在末尾添加另一个管道语句(如 $$ CB.sinkFile "output.txt"
)来实现。但是,此特定版本需要 ByteString
的 Conduit
输出。你能为我指出正确的方向吗?
任何帮助将不胜感激!
最佳答案
首先让我说 xml-conduit 中的流式助手 API 已经多年未开发,并且可能会受益于在此期间管道发生的给定变化的重新构想。我认为可能有更好的方法来完成任务。
也就是说,让我解释一下您遇到的问题。 many
函数创建一个结果列表,并且在完成处理之前不会产生任何值。在你的情况下,有太多的值,这似乎永远不会发生。最终,当整个文件被读取后,整个用户列表将立即显示。但这显然不是您要寻找的行为。
相反,您要做的是创建 User
值的流,这些值会在准备就绪后立即生成。您要做的基本上是用一个新函数替换 many
函数调用,该函数每次解析时都会 yield
一个结果。一个简单的实现可以是:
yieldWhileJust :: Monad m
=> ConduitM a b m (Maybe b)
-> Conduit a m b
yieldWhileJust consumer =
loop
where
loop = do
mx <- consumer
case mx of
Nothing -> return ()
Just x -> yield x >> loop
此外,您不想使用 putStrLn $ unlines $ map show
,而是希望将整个管道附加到一个消费者,消费者将打印每个单独产生的 User
值。这可以通过 Data.Conduit.List.mapM_
轻松实现,例如:CL.mapM_ (liftIO . print)
。
我整理了a full example根据你的代码。输入是一个人工生成的无限 XML 文件,只是为了证明它确实是立即产生输出这一点。
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
import Control.Applicative ((<*))
import Control.Concurrent (threadDelay)
import Control.Monad (forever, void)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Data.ByteString (ByteString)
import Data.Conduit
import qualified Data.Conduit.List as CL
import Data.Text (Text)
import Data.Text.Encoding (encodeUtf8)
import Data.XML.Types (Event)
import Text.XML.Stream.Parse
-- instead of actually including a large input data file, just for testing purposes
infiniteInput :: MonadIO m => Source m ByteString
infiniteInput = do
yield "<users>"
forever $ do
yield $ encodeUtf8
"<row id=\"1\" DisplayName=\"StackOverflow\"/><row id=\"2597135\" DisplayName=\"Uli Köhler\"/>"
liftIO $ threadDelay 1000000
--yield "</users>" -- will never be reached
data User = User {name :: Text} deriving (Show)
parseUserRow :: MonadThrow m => Consumer Event m (Maybe User)
parseUserRow = tagName "row" (requireAttr "DisplayName" <* ignoreAttrs) $ \displayName -> do
return $ User displayName
parseUsers :: MonadThrow m => Conduit Event m User
parseUsers = void $ tagNoAttr "users" $ yieldWhileJust parseUserRow
yieldWhileJust :: Monad m
=> ConduitM a b m (Maybe b)
-> Conduit a m b
yieldWhileJust consumer =
loop
where
loop = do
mx <- consumer
case mx of
Nothing -> return ()
Just x -> yield x >> loop
main :: IO ()
main = infiniteInput
$$ parseBytes def
=$ parseUsers
=$ CL.mapM_ print
关于xml - 流式传输 xml-conduit 解析结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21367423/
正如标题中所问,我有两个如下结构的 XML 文件 A.xml //here I want to include B.xml
我有一个 xml 文件。根据我的要求,我需要更新空标签,例如我需要更改 to .是否可以像那样更改标签.. 谢谢... 最佳答案 var xmlString=" "; var properStri
我有这样简单的 XML: Song Playing 09:41:18 Frederic Delius Violin Son
在我的工作中,我们有自己的 XML 类来构建 DOM,但我不确定应该如何处理连续的空格? 例如 Hello World 当它被读入 DOM 时,文本节点应该包含 Hello 和 World
我有以下 2 个 xml 文件,我必须通过比较 wd:Task_Name_ID 和 TaskID 的 XML 文件 2。 例如,Main XML File-1 wd:Task_Name_ID 具有以下
我在 Rails 应用程序中有一个 XML View ,需要从另一个文件插入 XML 以进行测试。 我想说“构建器,只需盲目地填充这个字符串,因为它已经是 xml”,但我在文档中看不到这样做的任何内容
我正在重建一些 XML 提要,因此我正在研究何时使用元素以及何时使用带有 XML 的属性。 一些网站说“数据在元素中,元数据在属性中。” 那么,两者有什么区别呢? 让我们以 W3Schools 为例:
在同一个文档中有两个 XML 声明是否是格式正确的 XML? hello 我相信不是,但是我找不到支持我的消息来源。 来自 Extensible Markup Language
我需要在包装器 XML 文档中嵌入任意(语法上有效的)XML 文档。嵌入式文档被视为纯文本,在解析包装文档时不需要可解析。 我知道“CDATA trick”,但如果内部 XML 文档本身包含 CDAT
XML 解析器和 XML 处理器是两个不同的东西吗?他们是两个不同的工作吗? 最佳答案 XML 解析器和 XML 处理器是一样的。它不适用于其他语言。 XML 是通用数据标记语言。解析 XML 文件已
我使用这个 perl 代码从一个文件中读取 XML,然后写入另一个文件(我的完整脚本有添加属性的代码): #!usr/bin/perl -w use strict; use XML::DOM; use
我正在编写一个我了解有限的历史脚本。 对象 A 的类型为 system.xml.xmlelement,我需要将其转换为类型 system.xml.xmldocument 以与对象 B 进行比较(类型
我有以下两个 XML 文件: 文件1 101 102 103 501 502 503
我有以下两个 XML 文件: 文件1 101 102 103 501 502 503
我有一个案例,其中一个 xml 作为输入,另一个 xml 作为输出:我可以选择使用 XSL 和通过 JAXB 进行 Unmarshalling 编码。性能方面,有什么真正的区别吗? 最佳答案 首先,程
我有包含 XML 的 XML,我想使用 JAXB 解析它 qwqweqwezxcasdasd eee 解析器 public static NotificationRequest parse(Strin
xml: mario de2f15d014d40b93578d255e6221fd60 Mario F 23 maria maria
尝试更新 xml 文件数组时出现以下错误。 代码片段: File dir = new File("c:\\XML"); File[] files = dir.listFiles(new Filenam
我怎样才能完成这样的事情: PS /home/nicholas/powershell> PS /home/nicholas/powershell> $date=(Get-Date | ConvertT
我在从 xml 文件中删除节点时遇到一些困难。我发现很多其他人通过各种方式在 powershell 中执行此操作的示例,下面的代码似乎与我见过的许多其他示例相同,但我没有得到所需的行为。 我的目标是将
我是一名优秀的程序员,十分优秀!