Euphoria JSON parser

new topic     » topic index » view thread      » older message » newer message

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

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu