packages feed

jsontsv 0.1.4.2 → 0.1.4.3

raw patch · 3 files changed

+62/−22 lines, 3 files

Files

Main.hs view
@@ -28,7 +28,13 @@ import qualified Text.CSV as CSV import Data.String.QQ  -data Options = Options { jsonExpr :: String, arrayDelim :: String, outputMode :: OutputMode, showHeader :: Bool } deriving Show+data Options = Options { +    jsonExpr :: String+  , arrayDelim :: String+  , outputMode :: OutputMode+  , showHeader :: Bool+  , debugKeyPaths :: Bool+  } deriving Show  data OutputMode = TSVOutput { delimiter :: String } | CSVOutput deriving (Show) @@ -38,6 +44,7 @@   <*> O.strOption (O.metavar "DELIM" <> O.value "," <> O.short 'a' <> O.help "Concatentated array elem delimiter. Defaults to comma.")   <*> (parseCSVMode <|> parseTSVMode)   <*> O.flag False True (O.short 'H' <> O.help "Include headers")+  <*> O.switch (O.long "debug" <> O.help "Debug keypaths")  parseCSVMode = O.flag' CSVOutput (O.short 'c' <> O.long "csv" <> O.help "Output CSV") @@ -49,25 +56,31 @@           (O.fullDesc              <> O.progDesc [s| Transform JSON objects to TSV.                       On STDIN provide an input stream of whitespace-separated JSON objects. |]-            <> O.header "jsontsv v0.1.4.1"+            <> O.header "jsontsv v0.1.4.3"             <> O.footer "See https://github.com/danchoi/jsontsv for more information.")  main = do-  Options expr arrayDelim mode showHeaders <- O.execParser opts+  Options expr arrayDelim mode showHeaders debugKeyPaths <- O.execParser opts   x <- BL.getContents    let xs :: [Value]       xs = decodeStream x       ks = parseKeyPath $ T.pack expr+      -- keypaths without alias info:+      ks' = [ks' | KeyPath ks' _ <- ks]       arrayDelim' = T.pack arrayDelim-  -- Prelude.putStrLn $ "key Paths " ++ show ks+  when debugKeyPaths $+     Prelude.putStrLn $ "key Paths " ++ show ks   when showHeaders $ do-    let hs = words expr+    let hs = [case alias of +                Just alias' -> T.unpack alias'+                Nothing -> expr  +              | (KeyPath _ alias, expr) <- Data.List.zip ks (words expr)]      case mode of        TSVOutput delim -> Prelude.putStrLn . Data.List.intercalate delim $ hs       CSVOutput -> Prelude.putStrLn . CSV.printCSV $ [hs]   case mode of -    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+    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@@ -84,6 +97,12 @@                       Success a -> (Just a, r)                       _ -> (Nothing, r)) $ fromJSON v' ++-- | KeyPath may have an alias for the header output+data KeyPath = KeyPath [Key] (Maybe Text) deriving Show++data Key = Key Text | Index Int deriving (Eq, Show)+ parseKeyPath :: Text -> [KeyPath] parseKeyPath s = case AT.parseOnly pKeyPaths s of     Left err -> error $ "Parse error " ++ err @@ -95,34 +114,40 @@ pKeyPaths = pKeyPath `AT.sepBy` spaces  pKeyPath :: AT.Parser KeyPath-pKeyPath = AT.sepBy1 pKeyOrIndex (AT.takeWhile1 $ AT.inClass ".[")+pKeyPath = KeyPath +    <$> (AT.sepBy1 pKeyOrIndex (AT.takeWhile1 $ AT.inClass ".["))+    <*> (pAlias <|> pure Nothing) +-- | A column header alias is designated by : followed by alphanum string after keypath+pAlias :: AT.Parser (Maybe Text)+pAlias = do+    AT.char ':'+    Just <$> AT.takeWhile1 (AT.inClass "a-zA-Z0-9")++pKeyOrIndex :: AT.Parser Key pKeyOrIndex = pIndex <|> pKey -pKey = Key <$> AT.takeWhile1 (AT.notInClass " .[")+pKey = Key <$> AT.takeWhile1 (AT.notInClass " .[:")  pIndex = Index <$> AT.decimal <* AT.char ']' -type KeyPath = [Key]-data Key = Key Text | Index Int deriving (Eq, Show)--evalToLineBuilder :: Text -> String -> [KeyPath] -> Value -> B.Builder +evalToLineBuilder :: Text -> String -> [[Key]] -> Value -> B.Builder  evalToLineBuilder arrayDelim delim ks v =      mconcat $ intersperse (B.fromText . T.pack $ delim) $  map (flip (evalToBuilder arrayDelim) v) ks  type ArrayDelimiter = Text -evalToList :: Text -> [KeyPath] -> Value -> [Text]+evalToList :: Text -> [[Key]] -> Value -> [Text] evalToList arrayDelim ks v = map (flip (evalToText arrayDelim) v) ks -evalToBuilder :: ArrayDelimiter -> KeyPath -> Value -> B.Builder+evalToBuilder :: ArrayDelimiter -> [Key] -> Value -> B.Builder evalToBuilder d k v = valToBuilder $ evalKeyPath d k v -evalToText :: ArrayDelimiter -> KeyPath -> Value -> Text+evalToText :: ArrayDelimiter -> [Key] -> 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 :: ArrayDelimiter -> KeyPath -> Value -> Value+evalKeyPath :: ArrayDelimiter -> [Key] -> Value -> Value evalKeyPath d [] x@(String _) = x evalKeyPath d [] x@Null = x evalKeyPath d [] x@(Number _) = x
README.md view
@@ -97,17 +97,22 @@ ## Usage  ```-jsontsv+jsontsv v0.1.4.3 -Usage: jsontsv FIELDS [-a DELIM] ([-c|--csv] | [-d DELIM]) [-H]-  Transform JSON objects to TSV+Usage: jsontsv FIELDS [-a DELIM] ([-c|--csv] | [-d DELIM]) [-H] [--debug]+  Transform JSON objects to TSV. On STDIN provide an input stream of+  whitespace-separated JSON objects.  Available options:   -h,--help                Show this help text-  -a DELIM                 Concatentated array elem delimiter. Defaults to comma.+  -a DELIM                 Concatentated array elem delimiter. Defaults to+                           comma.   -c,--csv                 Output CSV   -d DELIM                 Output field delimiter. Defaults to tab.   -H                       Include headers+  --debug                  Debug keypaths++See https://github.com/danchoi/jsontsv for more information. ```  Input should be a stream of JSON objects of the same or mostly similar shape,@@ -164,6 +169,16 @@ * null is printed as `null` * If the leaf value is an array, it is concatenated into a single   comma-separated string. This delimiter can be changed with the `-a` option.+++## Column header aliases++If the default column headers using `-H` are too long, you can designate+aliases with the pattern `[keypath]:[alias]`. E.g., ++    curl -s "https://api.github.com/repos/rails/rails/issues" | +    jq -M '.[]' | +    jsontsv -H 'number title user.login:login state repository.name:repo labels.name:lables'   ## Known alternatives  
jsontsv.cabal view
@@ -2,7 +2,7 @@ --  see http://haskell.org/cabal/users-guide/  name:                jsontsv-version:             0.1.4.2+version:             0.1.4.3 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.