Euphoria JSON parser
- Posted by ghaberek (admin) Mar 13, 2015
- 3103 views
Good news, everyone!
I have implemented an experimental JSON parser powered by JSMN (pronounced like 'jasmine'). I created a new branch for this in SCM named jsmn. I think I did a pretty good job of "Euphoriaizing" the functionality. I've done a lot of testing so far with JSON data from many sources and I have verified the JSON output with several online validators.
Basically, JSMN parses a JSON string into a series of tokens that simply describe the contents of string. The tokens contain the following values:
- J_TYPE (a JSON type constant, see below)
- J_START (start of the JSON value in the string)
- J_END (end of the JSON value in the string)
- J_SIZE (number of sub-tokens following this token)
- J_PARENT (index of this token's parent token)
We then take those tokens and assemble Euphoria objects such as maps, sequences, strings, and atoms.
These values are always stored in a sequence with their respective type:
- JSON_OBJECT (a key/value map)
- JSON_ARRAY (an sequence of values)
- JSON_STRING (a basic string)
- JSON_PRIMITIVE (a number or true/false/null)
Documentation is complete but may need to be touched up. I have not tested building on all platforms.
Example 1
-- -- Parse a raw JSON string into a sequence of tokens. -- include std/console.e include std/json.e sequence js = `{"key": "hello", "value": "world"}` object tokens = json:parse( js ) if atom( tokens ) then -- token is an error number end if for i = 1 to length( tokens ) do sequence t = tokens[i] integer j_type = t[J_TYPE] integer j_start = t[J_START] integer j_end = t[J_END] integer j_size = t[J_SIZE] integer j_parent = t[J_PARENT] sequence j_value = js[j_start..j_end] display( "token [1]", {i} ) display( " j_type = [1]", {j_type} ) display( " j_start = [1]", {j_start} ) display( " j_end = [1]", {j_end} ) display( " j_size = [1]", {j_size} ) display( " j_parent = [1]", {j_parent} ) display( " j_value = [1]", {j_value} ) end for
Output
token 1 j_type = 1 j_start = 1 j_end = 34 j_size = 2 j_parent = 0 j_value = {"key": "hello", "value": "world"} token 2 j_type = 3 j_start = 3 j_end = 5 j_size = 1 j_parent = 1 j_value = key ...
Example 2
-- -- Parse a sequence of JSON tokens into a Euphoria object. -- include std/console.e include std/json.e include std/map.e object result = json:value( `{"key": "hello", "value": "world"}` ) if atom( result ) then -- result is an error number end if map m = result[J_VALUE] object key = map:get( m, "key" ) object value = map:get( m, "value" ) display( `key = "[1]", value = "[2]"`, {key[J_VALUE],value[J_VALUE]} )
Output
key = "hello", value = "world"
Example 3
-- -- Create a simple JSON object. -- include std/json.e -- a JSON_OBJECT is a map of key/value pairs object test = json:new(JSON_OBJECT, { -- a JSON_OBJECT is a map of key/value pairs -- values get converted to JSON_STRING automatically {"key", "hello"}, {"value", "world"} }) json:write(1, test)
Output
{ "key": "hello", "value": "world" }
Example 4
-- -- Create a complex JSON object. -- include std/json.e object test = json:new(JSON_OBJECT, { -- a JSON_OBJECT is a map of key/value pairs {"array", json:new(JSON_ARRAY, { -- JSON_ARRAY is a sequence of values, which can be nested JSON_OBJECTs json:new( JSON_OBJECT, { {"name","one"}, {"value",1} } ), json:new( JSON_OBJECT, { {"name","two"}, {"value",2} } ), json:new( JSON_OBJECT, { {"name","three"}, {"value",3} } ), json:new( JSON_OBJECT, { {"name","four"}, {"value",4} } ), json:new( JSON_OBJECT, { {"name","five"}, {"value",5} } ) })} }) json:write(1, test)
Output
{ "array": [ { "value": 1, "name": "one" }, { "value": 2, "name": "two" }, { "value": 3, "name": "three" }, { "value": 4, "name": "four" }, { "value": 5, "name": "five" } ] }
-Greg