Navigating JSON Objects in General in Haskell

My goal is to write a program in Haskell that takes the name of the json file and interprets the rest of the arguments as a way to move that json file and prints the value to which the transition is made. The problem is that JSON can contain several types of values, I don’t know how to make a system like Haskell understand what I want. Here is the Haskell code with a “navigation” function that I cannot implement correctly:

import qualified Data.Aeson as A import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as BSL import Data.List import Data.Maybe import System.Environment parse :: String -> A.Value parse = fromJust . A.decode . BSL.pack isInteger xs = case reads xs :: [(Integer, String)] of [(_, "")] -> True _ -> False navigate :: A.Value -> String -> String navigate value [] = value navigate value [x:xs] | isInteger x = ??? -- value is an array, get the xth element of it. | otherwise = ??? -- value is an map, x is a key in it. main :: IO () main = do [filename:path] <- getArgs contents <- readFile filename let d = parse contents putStrLn (show (navigate d path)) 

For reference, here is how the program was written in Python:

 from json import load from sys import argv def navigate(obj, path): if not path: return obj head, tail = path[0], path[1:] return navigate(obj[int(head) if head.isdigit() else head], tail) if __name__ == '__main__': fname, path = argv[1], argv[2:] obj = load(open(fname)) print navigate(obj, path) 

The program will start as follows:

 $ cat data.json {"foo" : [[1, 2, 3, {"bar" : "barf"}]]} $ python showjson.py data.json foo 0 3 bar barf 
+4
source share
1 answer

You can simply map the pattern to the A.Value constructors to find out which JSON objects you are dealing with:

 import qualified Data.HashMap.Strict as M import qualified Data.Vector as V import qualified Data.Text as T -- ... rest of the code more or less as before ... navigate :: A.Value -> [String] -> BSL.ByteString navigate value [] = A.encode value navigate (A.Array vs) (x : xs) = navigate (vs V.! read x) xs navigate (A.Object o) (x : xs) = navigate (o M.! T.pack x) xs 

Note that the definition of A.Value as follows:

 data Value = Object !(HashMap Text Value) | Array !(Vector Value) | ... -- other constructors 

Thus, the code for navigate uses a search function (called ! In both cases) on vectors and hash maps. The read function is used to interpret the command line argument as a number, if necessary (and will fail if it is not), while T.pack interprets the string as a value of type Text .

+3
source

Source: https://habr.com/ru/post/1444290/


All Articles