1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
------------------------------------------------------------------------------ --- This library contains the definition of a data type to represent --- JSON values. --- --- @author Jonas Oberschweiber --- @version February 2025 ------------------------------------------------------------------------------ module JSON.Data ( JValue(..) , JObject, fromJObject, toJObject, lookupName, insertField ) where import Data.List ( nubBy, partition ) --- A JSON value. --- --- @cons JBool - a Boolean value (`true` or `false` in JSON) --- @cons JNull - null, i.e. a missing value --- @cons JString - a JSON string --- @cons JInt - a JSON number without decimal point and exponent --- @cons JNumber - a JSON number (numbers are always floats in JSON) --- @cons JArray - a JSON array, represented by a list of JValues --- @cons JObject - a JSON object, represented by a map from Strings to JValues data JValue = JBool Bool | JNull | JString String | JInt Int | JNumber Float | JArray [JValue] | JObject JObject deriving (Eq, Show) --- A JSON object is just some representation of a mapping from names (strings) --- to JSON values. --- It is an abstract type (rather than an explicit list) to ensure --- that there are no duplicate entries. newtype JObject = JSONObject [(String, JValue)] deriving Show -- JSON objects are equivalent if they contain the same name/value pairs -- possibly in a different order. instance Eq JObject where JSONObject jo1 == JSONObject jo2 = eqJObject jo1 jo2 where eqJObject [] [] = True eqJObject [] (_:_) = False eqJObject ((k,v):kvs) jo = let (eqk,neqk) = partition ((==k) . fst) jo in case eqk of [(_,v1)] -> v==v1 && eqJObject kvs neqk _ -> False --- Extracts the list of name / JSON value pairs from a JSON object. fromJObject :: JObject -> [(String, JValue)] fromJObject (JSONObject jo) = jo --- Transforms a list of name / JSON value pairs into a JSON object. --- Pairs with duplicated names are deleted to ensure that the JSON object --- is a map from names to values. toJObject :: [(String,JValue)] -> JObject toJObject = JSONObject . nubBy (\(k1, _) (k2, _) -> k1 == k2) --- Retrieves the JSON value with a given name from a JSON object, if it exists. lookupName :: String -> JObject -> Maybe JValue lookupName name (JSONObject jo) = lookup name jo --- Inserts a name / JSON value pair in a JSON object. --- If the name already exists, the existing value is overwritten. insertField :: String -> JValue -> JObject -> JObject insertField name val (JSONObject jo) = JSONObject (insert jo) where insert [] = [(name,val)] insert ((k,v):fs) | k == name = (name,val) : fs | otherwise = (k,v) : insert fs ------------------------------------------------------------------------------ |