A wrapper for json
in the Erlang stdlib for 27+ and for jsx
in Erlang 26 and below
ljson provides a very thin wrapper around the encode/1
, encode/2
functions of the jsx library when running in OTP versions 26 and below; it provides a similar wrapper for encode/1
, encode/3
when running in OTP 27 and above.
In both cases, binary is returned. Since Erlang 27's json
returns an iolist, this does add a step for Erlang 27+ and breaks a bit of that compatibility in the interest of preserving more backwards compatibility for projects that have used jsx.
How long will this library be around? Until there's a better library easily usable from LFE projects, or until all supported Erlang versions have json
and provide a backwards-compatible feature set, this library will be around.
The following usage examples are from LFE, but the same applies to Erlang (though hyphens in the LFE function name can be replaced with underscores in the same Erlang function).
Encode simple LFE data to JSON:
lfe> (ljson:encode 'a)
#"\"a\""
lfe> (ljson:encode "a")
#"[97]"
lfe> (ljson:encode 1)
#"1"
lfe> (ljson:encode 3.14)
#"3.14"
lfe> (ljson:encode '(a b c 42))
#"[\"a\",\"b\",\"c\",42]"
lfe> (ljson:encode #m(a b))
#"{\"a\":\"b\"}"
lfe> (ljson:encode #m(a b c d))
#"{\"c\":\"d\",\"a\":\"b\"}"
Decode simple JSON:
lfe> (ljson:decode #"\"a\""))
#"a"
lfe> (ljson:decode #b("[97]"))
"a"
lfe> (ljson:decode #b("1"))
1
lfe> (ljson:decode #b("3.14"))
3.14
lfe> (ljson:decode #b("[\"a\",\"b\",\"c\",42]"))
(#"a" #"b" #"c" 42)
lfe> (ljson:decode #"{\"a\": \"b\"}")
#M(#"a" #"b")
lfe> (ljson:decode #"{\"a\":\"b\",\"c\":\"d\"}")
#M(#"a" #"b" #"c" #"d")
lfe> (ljson:decode
lfe> #B(123 34 97 34 58 34 98 34 44 34 99 34 58 34 100 34 125))
#M(#"a" #"b" #"c" #"d")
Decode a JSON data structure (note that, for formatting purposes, the data below has been presented separated with newlines; this won't work in the LFE REPL -- you'll need to put it all on one line):
lfe> (set json-data #"{
\"First Name\": \"Jón\",
\"Last Name\": \"Þórson\",
\"Is Alive?\": true,
\"Age\": 25,
\"Height_cm\": 167.6,
\"Address\": {
\"Street Address\": \"í Gongini 5 Postsmoga 108\",
\"City\": \"Tórshavn\",
\"Country\": \"Faroe Islands\",
\"Postal Code\": \"100\"
},
\"Phone Numbers\": [
{
\"Type\": \"home\",
\"Number\": \"20 60 30\"
},
{
\"Type\": \"office\",
\"Number\": \"+298 20 60 20\"
}
],
\"Children\": [],
\"Spouse\": null}")
lfe> (set data (ljson:decode json-data))
#M(#"Address"
#M(#"City" #"Tórshavn" #"Country" #"Faroe Islands"
#"Postal Code" #"100"
#"Street Address" #"í Gongini 5 Postsmoga 108")
#"Age" 25 #"Children" () #"First Name" #"Jón" #"Height_cm" 167.6
#"Is Alive?" true #"Last Name" #"Þórson"
#"Phone Numbers"
(#M(#"Number" #"20 60 30" #"Type" #"home")
#M(#"Number" #"+298 20 60 20" #"Type" #"office"))
#"Spouse" null)
Now let's take it full circle by encoding it again:
lfe> (ljson:encode data)
#"{\"Address\":{\"City\":\"Tórshavn\",\"Country\":\"Faroe Islands\",\"Postal Code\":\"100\",\"Street Address\":\"í Gongini 5 Postsmoga 108\"},\"Age\":25,\"Children\":[],\"First Name\":\"Jón\",\"Height_cm\":167.6,\"Is Alive?\":true,\"Last Name\":\"Þórson\",\"Phone Numbers\":[{\"Number\":\"20 60 30\",\"Type\":\"home\"},{\"Number\":\"+298 20 60 20\",\"Type\":\"office\"}],\"Spouse\":null}"
Let's do the same, but this time from LFE data:
lfe> (set lfe-data
'#m(#"First Name" #"Jón"
#"Last Name" #"Þórson"
#"Is Alive?" true
#"Age" 25
#"Height_cm" 167.6
#"Address" #m(#"Street Address" #"í Gongini 5 Postsmoga 108"
#"City" #"Tórshavn"
#"Country" #"Faroe Islands"
#"Postal Code" #"100")
#"Phone Numbers" (#m(#"Type" #"home" #"Number" #"20 60 30")
#m(#"Type" #"office" #"Number" #"+298 20 60 20"))
#"Children" ()
#"Spouse" null))
(#(#B(...)))
lfe> (ljson:encode lfe-data)
#"{\"Address\":{\"City\":\"Tórshavn\",\"Country\":\"Faroe Islands\",\"Postal Code\":\"100\",\"Street Address\":\"í Gongini 5 Postsmoga 108\"},\"Age\":25,\"Children\":[],\"First Name\":\"Jón\",\"Height_cm\":167.6,\"Is Alive?\":true,\"Last Name\":\"Þórson\",\"Phone Numbers\":[{\"Number\":\"20 60 30\",\"Type\":\"home\"},{\"Number\":\"+298 20 60 20\",\"Type\":\"office\"}],\"Spouse\":null}"
Note that the additional function arguments (encode/2
, decode/2
, and decode/3
) are specific to the underlying JSON library being used. The args will have the same meaning as the parent library used, with no attempt made by ljson to unify these for consistency.
Write Erlang terms as serialised JSON data to a file:
lfe> (ljson-file:write "/tmp/test-data.json" #m(a 1 b 2 c 3))
"/tmp/test-data.json"
Read a JSON file, deserialising the data as Erlang terms:
lfe> (ljson-file:read "/tmp/test-data.json")
#M(#"a" 1 #"b" 2 #"c" 3)
The Erlang/LFE project dirs (a port of the same Rust library)) defines standard/convential directories by in Linux, macos, and Windows operating systems. The ljson project utilises this library to support convenient reading and writing of application data files, etc.
Write a JSON file:
lfe> (ljson-file:write 'data "myapp/conponent/state.json" #m(a 1 b 2 c 3))
"/Users/oubiwann/Library/Application Support/myapp/conponent/state.json"
Read a JSON file:
lfe> (ljson-file:read 'data "myapp/conponent/state.json")
#M(#"a" 1 #"b" 2 #"c" 3)
Apache Version 2 License
Copyright © 2014-2015, Dreki Þórgísl
Copyright © 2015, arpunk
Copyright © 2015-2025, Duncan McGreggor [email protected]