使用aeson / attoparsec管道,一旦源没有更多数据,如何干净地退出

时间:2013-10-22 07:29:53

标签: exception haskell conduit aeson attoparsec

我正在使用由aeson连接的attoparsec / conduitconduit-http / conduit-attoparsec来解析文件/网络服务器中的JSON数据。我的问题是我的管道总是抛出这个异常......

ParseError {errorContexts = ["demandInput"], errorMessage = "not enough bytes", errorPosition = 1:1}

...一旦套接字关闭或我们点击EOF。通过管道等解析和传递结果数据结构的工作正常,但它总是以sinkParser抛出此异常结束。我像这样调用它......

j <- CA.sinkParser json

...在我的管道内部,将ByteStrings解析为我的消息结构。

如果没有更多数据(没有更多顶级表达式),我怎么能干净地退出管道呢?有没有合适的方法来检测/区分这个异常,而不必查看错误字符串?

谢谢!

编辑:示例:

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Control.Applicative
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
import qualified Data.Conduit.Attoparsec as CA
import Data.Aeson
import Data.Conduit
import Data.Conduit.Binary
import Control.Monad.IO.Class

data MyMessage = MyMessage String deriving (Show)

parseMessage :: (MonadIO m, MonadResource m) => Conduit B.ByteString m B.ByteString
parseMessage = do
    j <- CA.sinkParser json
    let msg = fromJSON j :: Result MyMessage
    yield $ case msg of
        Success r -> B8.pack $ show r
        Error   s -> error s
    parseMessage

main :: IO ()
main =
    runResourceT $ do
        sourceFile "./input.json" $$ parseMessage =$ sinkFile "./out.txt"

instance FromJSON MyMessage where
    parseJSON j =
        case j of
        (Object o) -> MyMessage <$> o .: "text"
        _          -> fail $ "Expected Object - " ++ show j

示例输入(input.json):

{"text":"abc"}
{"text":"123"}

输出:

out: ParseError {errorContexts = ["demandInput"], errorMessage = "not enough bytes", errorPosition = 3:1}

和out.txt:

MyMessage "abc"MyMessage "123"

1 个答案:

答案 0 :(得分:4)

这是conduitParserEither的完美用例:

parseMessage :: (MonadIO m, MonadResource m) => Conduit B.ByteString m B.ByteString
parseMessage =
    CA.conduitParserEither json =$= awaitForever go
  where
    go (Left s) = error $ show s
    go (Right (_, msg)) = yield $ B8.pack $ show msg ++ "\n"

如果你在FP Haskell中心,你可以clone my solution into the IDE