Skip to content

Instantly share code, notes, and snippets.

@jbpotonnier
Last active December 18, 2015 02:08
Show Gist options
  • Save jbpotonnier/5708349 to your computer and use it in GitHub Desktop.
Save jbpotonnier/5708349 to your computer and use it in GitHub Desktop.
Access json data using path. Functional programming to the rescue :P
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text as Text
import Data.Text (Text)
import Data.Aeson (encode, decode, Value, Value(..))
import qualified Data.HashMap.Strict as HashMap
import Data.Vector ((!))
path :: Text -> Value -> Value
path pathString = foldl1 (.) getters
where
getters :: [Value -> Value]
getters = (map jsonGetter . reverse . Text.splitOn ".") pathString
jsonGetter :: Text -> Value -> Value
jsonGetter name = go
where go (Object jsonValue) = case HashMap.lookup name jsonValue of
Just val -> val
Nothing -> error $ "Error accessing " ++ show name
go (Array jsonArray) = jsonArray ! (read . Text.unpack) name
go _ = error $ "Error accessing " ++ show name
jsonPath :: Text -> LBS.ByteString -> LBS.ByteString
jsonPath pathString content =
let jsonValue = case decode content :: Maybe Value of
Just v -> v
Nothing -> error $ "Error parsing json " in
encode . path pathString $ jsonValue
main :: IO ()
main = do
content <- LBS.readFile "persons.json"
LBS.putStrLn $ jsonPath "address.city" content
LBS.putStrLn $ jsonPath "phoneNumbers.0.type" content
import json
from operator import itemgetter
compose = lambda f, g: lambda x: f(g(x))
jsongetter = lambda s: itemgetter(int(s)) if s.isdigit() else itemgetter(s)
def path(path):
getters = map(jsongetter, reversed(path.split('.')))
return reduce(compose, getters)
if __name__ == '__main__':
with open('persons.json') as f:
data = json.loads(f.read())
print path('address.city')(data)
print path('phoneNumbers.0.type')(data)
{
"firstName": "John",
"lastName": "Smith",
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": 10021
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "fax",
"number": "646 555-4567"
}
]
}
@jbpotonnier
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment