jsontsv 0.1.2.0 → 0.1.3.0
raw patch · 3 files changed
+42/−56 lines, 3 files
Files
- Main.hs +34/−29
- README.md +7/−26
- jsontsv.cabal +1/−1
Main.hs view
@@ -25,13 +25,14 @@ import qualified Options.Applicative as O import qualified Text.CSV as CSV -data Options = Options { jsonExpr :: String, outputMode :: OutputMode } deriving Show+data Options = Options { jsonExpr :: String, arrayDelim :: String, outputMode :: OutputMode } deriving Show data OutputMode = TSVOutput { delimiter :: String } | CSVOutput deriving (Show) parseOpts :: O.Parser Options parseOpts = Options <$> O.argument O.str (O.metavar "FIELDS")+ <*> O.strOption (O.metavar "ARRAY-DELIM" <> O.value "," <> O.short 'a' <> O.help "concatentated array elem delimiter. Default to comma") <*> ((O.flag' CSVOutput (O.short 'c' <> O.long "csv" <> O.help "output CSV")) <|> (TSVOutput <$> (O.strOption (O.metavar "DELIM" <> O.value "\t" <> O.short 'd' <> O.help "output field delimiter. Defaults to tab")))) @@ -39,15 +40,16 @@ (O.fullDesc <> O.progDesc "Transform JSON objects to TSV" <> O.header "jsontsv") main = do- Options expr mode <- O.execParser opts+ Options expr arrayDelim mode <- O.execParser opts x <- BL.getContents let xs :: [Value] xs = decodeStream x- let ks' = parseKeyPath $ T.pack expr+ ks' = parseKeyPath $ T.pack expr+ arrayDelim' = T.pack arrayDelim -- Prelude.putStrLn $ "key Paths " ++ show ks' case mode of - TSVOutput delim -> mapM_ (TL.putStrLn . B.toLazyText . evalToLineBuilder delim ks') xs- CSVOutput -> Prelude.putStrLn . CSV.printCSV $ map (map T.unpack . evalToList ks') $ xs+ TSVOutput delim -> mapM_ (TL.putStrLn . B.toLazyText . evalToLineBuilder arrayDelim' delim ks') xs+ CSVOutput -> Prelude.putStrLn . CSV.printCSV $ map (map T.unpack . evalToList arrayDelim' ks') $ xs decodeStream :: (FromJSON a) => BL.ByteString -> [a] decodeStream bs = case decodeWith json bs of@@ -86,44 +88,47 @@ type KeyPath = [Key] data Key = Key Text | Index Int deriving (Eq, Show) -evalToLineBuilder :: String -> [KeyPath] -> Value -> B.Builder -evalToLineBuilder delim ks v = mconcat $ intersperse (B.fromText . T.pack $ delim) $ map (flip evalToBuilder v) ks+evalToLineBuilder :: Text -> String -> [KeyPath] -> Value -> B.Builder +evalToLineBuilder arrayDelim delim ks v = + mconcat $ intersperse (B.fromText . T.pack $ delim) $ map (flip (evalToBuilder arrayDelim) v) ks -evalToList :: [KeyPath] -> Value -> [Text]-evalToList ks v = map (flip evalToText v) ks+type ArrayDelimiter = Text -evalToBuilder :: KeyPath -> Value -> B.Builder-evalToBuilder k v = valToBuilder $ evalKeyPath k v+evalToList :: Text -> [KeyPath] -> Value -> [Text]+evalToList arrayDelim ks v = map (flip (evalToText arrayDelim) v) ks -evalToText :: KeyPath -> Value -> Text-evalToText k v = valToText $ evalKeyPath k v+evalToBuilder :: ArrayDelimiter -> KeyPath -> Value -> B.Builder+evalToBuilder d k v = valToBuilder $ evalKeyPath d k v +evalToText :: ArrayDelimiter -> KeyPath -> Value -> Text+evalToText d k v = valToText $ evalKeyPath d k v+ -- evaluates the a JS key path against a Value context to a leaf Value-evalKeyPath :: KeyPath -> Value -> Value-evalKeyPath [] x@(String _) = x-evalKeyPath [] x@Null = x-evalKeyPath [] x@(Number _) = x-evalKeyPath [] x@(Bool _) = x-evalKeyPath [] x@(Object _) = x-evalKeyPath [] x@(Array v) = +evalKeyPath :: ArrayDelimiter -> KeyPath -> Value -> Value+evalKeyPath d [] x@(String _) = x+evalKeyPath d [] x@Null = x+evalKeyPath d [] x@(Number _) = x+evalKeyPath d [] x@(Bool _) = x+evalKeyPath d [] x@(Object _) = x+evalKeyPath d [] x@(Array v) = let vs = V.toList v- xs = intersperse "," $ map (evalToText []) vs+ xs = intersperse d $ map (evalToText d []) vs in String . mconcat $ xs-evalKeyPath (Key key:ks) (Object s) = +evalKeyPath d (Key key:ks) (Object s) = case (HM.lookup key s) of- Just x -> evalKeyPath ks x+ Just x -> evalKeyPath d ks x Nothing -> Null-evalKeyPath (Index idx:ks) (Array v) = +evalKeyPath d (Index idx:ks) (Array v) = let e = (V.!?) v idx in case e of - Just e' -> evalKeyPath ks e'+ Just e' -> evalKeyPath d ks e' Nothing -> Null -- traverse array elements with additional keys-evalKeyPath ks@(Key key:_) (Array v) = +evalKeyPath d ks@(Key key:_) (Array v) = let vs = V.toList v- in String . mconcat . intersperse "," $ map (evalToText ks) vs-evalKeyPath ((Index _):_) _ = Null-evalKeyPath _ _ = Null+ in String . mconcat . intersperse d $ map (evalToText d ks) vs+evalKeyPath _ ((Index _):_) _ = Null+evalKeyPath _ _ _ = Null valToBuilder :: Value -> B.Builder valToBuilder (String x) = B.fromText x
README.md view
@@ -14,28 +14,6 @@ "title": "Terminator 2: Judgement Day", "year": 1991, "stars": [- "Arnold Schwarzenegger",- "Linda Hamilton"- ],- "ratings": {- "imdb": 8.5- }-}-{- "title": "Interstellar",- "year": 2014,- "stars": [- "Matthew McConaughey",- "Anne Hathaway"- ],- "ratings": {- "imdb": 8.9- }-}-{- "title": "Terminator 2: Judgement Day",- "year": 1991,- "stars": [ { "name": "Arnold Schwarzenegger" },@@ -102,11 +80,12 @@ ``` jsontsv -Usage: jsontsv FIELDS ([-c|--csv] | [-d DELIM])+Usage: jsontsv FIELDS [-a ARRAY-DELIM] ([-c|--csv] | [-d DELIM]) Transform JSON objects to TSV Available options: -h,--help Show this help text+ -a ARRAY-DELIM concatentated array element delimiter. Defaults to comma -c,--csv output CSV -d DELIM output field delimiter. Defaults to tab ```@@ -139,7 +118,8 @@ * Strings and numbers are copied to output. * Boolean values are output as `t` or `f`. * null is printed as `null`-* If the leaf value is an array, it is concatenated into a single comma-separated string+* If the leaf value is an array, it is concatenated into a single+ comma-separated string. The delimiter can be changed with the `-a` option. ## Performing post-processing on field values @@ -147,6 +127,7 @@ ## Known alternatives -* [jsawk](https://github.com/micha/jsawk) +* [jsawk](https://github.com/micha/jsawk) Jsawk is like awk, but for JSON. (nodejs) * [jq][jq]-* [jsoncsv](https://github.com/gradus/jsoncsv)+* [jsoncsv](https://github.com/gradus/jsoncsv) a json to csv library in javascript/coffeescript+* [json](https://github.com/konklone/json) A free, in-browser JSON to CSV converter.
jsontsv.cabal view
@@ -2,7 +2,7 @@ -- see http://haskell.org/cabal/users-guide/ name: jsontsv-version: 0.1.2.0+version: 0.1.3.0 synopsis: JSON to TSV transformer homepage: https://github.com/danchoi/jsontsv description: Transforms JSON into tab-separated line-oriented output, for easier processing in Unix-style pipelines.