1. Euphoria JSON parser

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 message » categorize

2. Re: Euphoria JSON parser

What does it do?

Kat

new topic     » goto parent     » topic index » view message » categorize

3. Re: Euphoria JSON parser

katsmeow said...

What does it do?

Kat

It's a JSON parser. It parses JSON. It also allows you to create JSON objects in memory and output them as JSON text.

With this, you can make use of REST APIs that send and receive JSON data by combining this with http_get() and http_post() calls. Or you could just store some data in a portable human-readable format. Or support importing and exporting data that is compatible with other applications and services.

There have been several unsuccessfuly attempts at adding JSON to Euphoria. I've also run into my own roadblocks trying to get a good JSON parser written in Euphoria. Sometimes it's better to avoid reinventing the wheel and just seek out something that Just Works.

There is also cjson in The Archive, which was added by "ras" in May 2012. That library probably works well but it has a few short-comings:

  • It requires an external library. If the libraries provided are not compatible with the user's system, they will have to be recompiled accordingly (not a trivial task). I have compiled JSMN into the backend of Euphoria.
  • It has a lot of functions to manipulate JSON objects in memory. I have implemented JSMN such that all of the JSON object manipulation is as "close to the bone" as possible in native Euphoria.
  • It has not been updated since 2012 and most likely will not be. With JSMN built into the backend, we will pull updates from upstream when updating Euphoria.

I original started along the same vein as cjson: I compiled JSMN into a shared library and wrapped its two functions, then wrote all of the additional code to format Euphoria objects from the tokens it provides. However, given how small the library is, it was only a few hours work to get the code compiled into the backend so that there are no external dependancies.

This, I believe, is key to adding a lot of good features to Euphoria: zero external dependancies.

-Greg

new topic     » goto parent     » topic index » view message » categorize

4. Re: Euphoria JSON parser

So it's been like six months since I did this. Any thoughts on merging this into the trunk for 4.1 release? Is this a sufficiently "Euphoria" approach to handling JSON? I would like to start work on building Mini-XML into Euphoria as well. I think it is sufficiently small enouch (like JSMN) to be embedded into the interpreter directly and exposed through machine_func(). Mini-XML has about 70 functions whereas JSMN had only two, but when compiled into a shared library, Mini-XML is only about 70 KB. I guess I'm just looking for input on moving forward with this effort.

-Greg

new topic     » goto parent     » topic index » view message » categorize

5. Re: Euphoria JSON parser

ghaberek said...

So it's been like six months since I did this. Any thoughts on merging this into the trunk for 4.1 release? Is this a sufficiently "Euphoria" approach to handling JSON? I would like to start work on building Mini-XML into Euphoria as well. I think it is sufficiently small enouch (like JSMN) to be embedded into the interpreter directly and exposed through machine_func(). Mini-XML has about 70 functions whereas JSMN had only two, but when compiled into a shared library, Mini-XML is only about 70 KB. I guess I'm just looking for input on moving forward with this effort.

-Greg

I'm in favor.

new topic     » goto parent     » topic index » view message » categorize

6. Re: Euphoria JSON parser

You know, it is funny, but I have been able to use c_func/c_proc interface without external dlls.

include std/unittest.e 
include std/dll.e 
include std/machine.e 
 
constant no_dll = -1 
constant malloc_function = define_c_func(no_dll, "malloc", {C_INT}, C_POINTER) 
constant Emalloc = define_c_func(no_dll, "Emalloc", {C_UINT}, C_POINTER) 
 
test_true("Malloc function returns non-zero", malloc_function) 
test_true("EMalloc function returns non-zero", Emalloc) 
test_report() 

You can link the C code with the rest into the "library" section, and then you use a Euphoria wrapper that you first can debug as an external dll while the team resists.

In the case of Regex, we didn't do this. Because of the way as Open Euphoria has integrated PCRE. Extra glue code in C via be_regex.c had to handle whether we pass a number implemented as an encoded pointer to a struct d or as a C integer. The code had to be written with great care to ensure people were not passing sequences where integers were expected. Initially, it did not do this.

Now, if you use the c_func/c_proc interface and compile the files into the library, you don't get external dependencies. And it is in the be_callc.c that makes sure your integers are converted into c integers when they need to and whether to error out. The EUPHORIA wrapper code has to be written correctly but it is less work in the end. This approach eliminates a need for a be_json.c which would be needed if you pass everything through machine_func/machine_proc.

Shawn

new topic     » goto parent     » topic index » view message » categorize

7. Re: Euphoria JSON parser

SDPringle said...

You can link the C code with the rest into the "library" section, and then you use a Euphoria wrapper that you first can debug as an external dll while the team resists.

In the case of Regex, we didn't do this. Because of the way as Open Euphoria has integrated PCRE. Extra glue code in C via be_regex.c had to handle whether we pass a number implemented as an encoded pointer to a struct d or as a C integer. The code had to be written with great care to ensure people were not passing sequences where integers were expected. Initially, it did not do this.

Now, if you use the c_func/c_proc interface and compile the files into the library, you don't get external dependencies. And it is in the be_callc.c that makes sure your integers are converted into c integers when they need to and whether to error out. The EUPHORIA wrapper code has to be written correctly but it is less work in the end.

Right, for wrapping Mini-XML, I was thinking I could put all of the function addresses into a table and just peek them all from memory, get the pointer to that table with one machine_func() call, and then wrap the functions with define_c_func()/proc() as if I were wrapping a shared library. That would save me from having to burn through ~70 machine_func() constants in the backend. But, if I can just use define_c_func()/proc() to access backend functions directly, then I can just skip the machine_func() nonsense entirely. (And if that's true, why do we still have machine_func()? Just for legacy purposes?)

SDPringle said...

This approach eliminates a need for a be_json.c which would be needed if you pass everything through machine_func/machine_proc.

True, but JSMN is only two functions and my wrapper is only one function. It was easier to just expose that via machine_func() and be done with it. Most of the magic happens directly within json.e anyway. In fact, all of the "build a new JSON object and write it to a file" parts are 100% Euphoria using well-structured map objects.

-Greg

new topic     » goto parent     » topic index » view message » categorize

8. Re: Euphoria JSON parser

Try it. Emalloc is something in the static EUPHORIA library. It is not in any shared-object file in /usr/lib or alike. So, try the code I gave on Windows. I noticed this sometime back but we never exploited it.

new topic     » goto parent     » topic index » view message » categorize

9. Re: Euphoria JSON parser

SDPringle said...

You can link the C code with the rest into the "library" section, and then you use a Euphoria wrapper that you first can debug as an external dll

Now, if you use the c_func/c_proc interface and compile the files into the library, you don't get external dependencies. And it is in the be_callc.c that makes sure your integers are converted into c integers when they need to and whether to error out. The EUPHORIA wrapper code has to be written correctly but it is less work in the end.

Does this work on Windoze though? Using -1 in place of open_dll("") works fine on nix because they all use the same dlsym() - which supports use of RTLD_DEFAULT and RTLD_NEXT in place of an dlopen handle. (See http://www.scs.stanford.edu/histar/src/pkg/uclibc/include/dlfcn.h and http://linux.die.net/man/3/dlsym for details on how this works.)

I can't find any documentation suggesting that GetProcAddress() on the stupid platform supports anything similar. I even looked through WINE sources ( http://source.winehq.org/source/dlls/ntdll/loader.c and http://source.winehq.org/source/dlls/kernel32/module.c ) but afaict WINE doesn't implement such behavior either.

Another reason this works is because on nix, both shared objects and executables are ELF objects, and you can dlopen() an executable with no problems. However, I've seen evidence that the stupid platform can't do this (e.g. http://stackoverflow.com/questions/19110747/loadlibrary-an-exe )

SDPringle said...

while the team resists.

Huh?

SDPringle said...

In the case of Regex, we didn't do this. Because of the way as Open Euphoria has integrated PCRE. Extra glue code in C via be_regex.c had to handle whether we pass a number implemented as an encoded pointer to a struct d or as a C integer.

The main reason we did it this way was for DOS support. Since DOS was dropped I've advocated for loading PCRE via a shared library instead of having it built in, but no one has put in the effort to actually separate it back out again.

ghaberek said...

Right, for wrapping Mini-XML, I was thinking I could put all of the function addresses into a table and just peek them all from memory, get the pointer to that table with one machine_func() call, and then wrap the functions with define_c_func()/proc() as if I were wrapping a shared library. That would save me from having to burn through ~70 machine_func() constants in the backend.

That's a really clever idea!

ghaberek said...

But, if I can just use define_c_func()/proc() to access backend functions directly, then I can just skip the machine_func() nonsense entirely. (And if that's true, why do we still have machine_func()? Just for legacy purposes?)

Probably. A big part of this was that the define_c() stuff didn't work on DOS. (At least not this way. You could use define_c_func() to call a machine code routine, but it'd be a heck of a lot harder to call a backend routine in DOS this way. At the very least, you'd need a way to look up the memory address of the routine yourself, as there's no linker (ala dlopen/LoadLibrary) that can do it for you in the DOS version of Euphoria.)

new topic     » goto parent     » topic index » view message » categorize

10. Re: Euphoria JSON parser

Seeking an update on this project - I could really use a JSON parser right now. I'm hard-coding some specific routines, which is slow, painstaking work.

If it's released, where can i find it?

Thanks

new topic     » goto parent     » topic index » view message » categorize

11. Re: Euphoria JSON parser

CraigWelch said...

Seeking an update on this project - I could really use a JSON parser right now. I'm hard-coding some specific routines, which is slow, painstaking work.

If it's released, where can i find it?

Thanks

I'm not exactly sure how to answer that. My hope was that by adding it to the repository as a branch would allow it to be pulled into the master branch as part of a future release.

Ultimately we need somebody to do a release soon. It look like Shawn fixed the two outstanding issues in May. (Further discussions about releasing should continue in that thread.)

-Greg

new topic     » goto parent     » topic index » view message » categorize

12. Re: Euphoria JSON parser

Don't know if this can fit your need but there is a JSON to Euphoria sequence converter in my Eu4 Standard library (v0.8.3 uploaded today).

It could be extracted with only needed dependancies. Here is the code:

 
include std/convert.e 
include std/search.e 
include std/text.e 
include _types_.e 
include _conv_.e 
include _sequence_.e 
include _debug_.e 
include _file_.e 
 
function find_matching(integer c, sequence s, integer from) 
  integer n, e 
 
  if c = '(' then 
    e = ')' 
  elsif c = '[' then 
    e = ']' 
  elsif c = '{' then 
    e = '}' 
  elsif c = '<' then 
    e = '>' 
  elsif c = '"' then 
    e = '"' 
  elsif c = 39 then 
    e = 39 
  end if 
 
  n = 0 
  for i = from to length(s) do 
    if s[i] = c then n += 1 end if 
    if s[i] = e then n -= 1 end if 
    if n = -1 then return i end if 
  end for 
  return 0 
end function 
 
function split_list(sequence json, integer sep) 
  sequence result 
  integer c, e, previous 
 
  c = 1 
  result = {} 
  previous = 1 
  while c < length(json) do 
    if (json[c] = '{') or (json[c] = '[') then 
      e = find_matching(json[c], json, c+1) 
      c = e 
    elsif json[c] = sep then 
      result = append(result, trim(json[previous..c-1])) 
      c += 1 
      previous = c 
    end if 
    c += 1 
  end while 
  result = append(result, trim(json[previous..$])) 
  return result 
end function 
 
global function json_to_sequence(sequence json) 
  sequence s, t 
  object result 
 
  result = {} 
  if length(json) = 0 then return result end if 
  if (json[1] = '{') and (json[$] = '}') then 
    s = split_list(json[2..$-1], ',') 
    for i = 1 to length(s) do 
      t = split_list(s[i], ':') 
      if length(t) != 2 then 
        error_message("missing colon!", 1) 
      end if 
      if not begins("\"", t[1]) or not ends("\"", t[1]) then 
        error_message("missing string!", 1) 
      end if 
      result = append(result, {dequote(t[1], {}), json_to_sequence(t[2])}) 
    end for 
  elsif (json[1] = '[') and (json[$] = ']') then 
    s = split_list(json[2..$-1], ',') 
    for i = 1 to length(s) do 
      if length(s[i]) then 
        result = append(result, json_to_sequence(s[i])) 
      end if 
    end for 
  elsif is_number(json) then 
    result = to_number(json) 
  elsif is_string(json) then 
    result = dequote(json, {}) 
  end if 
  return result 
end function 
 

Jean-Marc

new topic     » goto parent     » topic index » view message » categorize

13. Re: Euphoria JSON parser

These JSON sequences

constant JSON_DATA = { 
  "{\"key1\" : {\"key1.1\" : 2}, \"key2\" : 2}", 
  "[120,183,\"alpha\",\"beta\",\"gamma\"]", 
  "{\"age\" : 51.5, \"details\" : [120,183], \"embedded\" : { \"three\" : 3.0, \"arr\" : [1,2,3,\"alpha\",\"beta\",\"gamma\"]} }", 
  "{\"him\" : true, \"her\" : false, \"nothing\" : null }", 
  "{\"dog\" : {\"name\" : \"Rover\", \"gender\" : \"male\"}}", 
  "{\"configure\":[{\"access-control\":[{\"access-list\":[]}]},{\"slot\":[]},{\"system\":[{\"date-and-time\":[{\"sntp\":[{\"server\":[]}]}]},{\"syslog\":[]}]},{\"management\":[{\"login-user\":[]},{\"snmp\":[{\"community\":[]}]},{\"access\":[]},{\"tacacsplus\":[{\"group\":[]}]}]},{\"qos\":[{\"policer-profile\":[]},{\"shaper-profile\":[]},{\"wred-profile\":[]},{\"queue-block-profile\":[{\"queue\":[]}]},{\"queue-group-profile\":[{\"queue-block\":[]}]}]},{\"port\":[{\"l2cp-profile\":[]},{\"ethernet\":[]},{\"svi\":[]}]},{\"bridge\":[{\"port\":[]},{\"vlan\":[]}]},{\"flows\":[{\"classifier-profile\":[]},{\"flow\":[]}]},{\"router\":[{\"interface\":[{\"dhcp-client\":[]}]}]},{\"oam\":[{\"cfm\":[{\"maintenance-domain\":[{\"maintenance-association\":[{\"mep\":[]}]}]}]}]},{\"test\":[{\"rfc2544\":[{\"profile-name\":[]}]}]}]}" 
} 
 

are converted to this

result =  
.  [1] 
.  .  [1] "key1" 
.  .  [2] 
.  .  .  [1] 
.  .  .  .  [1] "key1.1" 
.  .  .  .  [2] 2 
.  [2] 
.  .  [1] "key2" 
.  .  [2] 2 
result =  
.  [1] 120 
.  [2] 183 
.  [3] "alpha" 
.  [4] "beta" 
.  [5] "gamma" 
result =  
.  [1] 
.  .  [1] "age" 
.  .  [2] 51.500000 
.  [2] 
.  .  [1] "details" 
.  .  [2] "x·" 
.  [3] 
.  .  [1] "embedded" 
.  .  [2] 
.  .  .  [1] 
.  .  .  .  [1] "three" 
.  .  .  .  [2] 3 
.  .  .  [2] 
.  .  .  .  [1] "arr" 
.  .  .  .  [2] 
.  .  .  .  .  [1] 1 
.  .  .  .  .  [2] 2 
.  .  .  .  .  [3] 3 
.  .  .  .  .  [4] "alpha" 
.  .  .  .  .  [5] "beta" 
.  .  .  .  .  [6] "gamma" 
result =  
.  [1] 
.  .  [1] "him" 
.  .  [2] "true" 
.  [2] 
.  .  [1] "her" 
.  .  [2] "false" 
.  [3] 
.  .  [1] "nothing" 
.  .  [2] "null" 
result =  
.  [1] 
.  .  [1] "dog" 
.  .  [2] 
.  .  .  [1] 
.  .  .  .  [1] "name" 
.  .  .  .  [2] "Rover" 
.  .  .  [2] 
.  .  .  .  [1] "gender" 
.  .  .  .  [2] "male" 
result =  
.  [1] 
.  .  [1] "configure" 
.  .  [2] 
.  .  .  [1] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "access-control" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "access-list" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  [2] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "slot" 
.  .  .  .  .  [2] "" 
.  .  .  [3] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "system" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "date-and-time" 
.  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  [1] "sntp" 
.  .  .  .  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  .  .  .  [1] "server" 
.  .  .  .  .  .  .  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "syslog" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  [4] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "management" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "login-user" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "snmp" 
.  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  [1] "community" 
.  .  .  .  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [3] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "access" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [4] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "tacacsplus" 
.  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  [1] "group" 
.  .  .  .  .  .  .  .  .  .  .  [2] "" 
.  .  .  [5] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "qos" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "policer-profile" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "shaper-profile" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [3] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "wred-profile" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [4] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "queue-block-profile" 
.  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  [1] "queue" 
.  .  .  .  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [5] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "queue-group-profile" 
.  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  [1] "queue-block" 
.  .  .  .  .  .  .  .  .  .  .  [2] "" 
.  .  .  [6] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "port" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "l2cp-profile" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "ethernet" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [3] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "svi" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  [7] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "bridge" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "port" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "vlan" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  [8] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "flows" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "classifier-profile" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "flow" 
.  .  .  .  .  .  .  .  [2] "" 
.  .  .  [9] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "router" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "interface" 
.  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  [1] "dhcp-client" 
.  .  .  .  .  .  .  .  .  .  .  [2] "" 
.  .  .  [10] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "oam" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "cfm" 
.  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  [1] "maintenance-domain" 
.  .  .  .  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  .  .  .  [1] "maintenance-association" 
.  .  .  .  .  .  .  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  [1] "mep" 
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  [2] "" 
.  .  .  [11] 
.  .  .  .  [1] 
.  .  .  .  .  [1] "test" 
.  .  .  .  .  [2] 
.  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  [1] "rfc2544" 
.  .  .  .  .  .  .  .  [2] 
.  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  [1] 
.  .  .  .  .  .  .  .  .  .  .  [1] "profile-name" 
.  .  .  .  .  .  .  .  .  .  .  [2] "" 

new topic     » goto parent     » topic index » view message » categorize

14. Re: Euphoria JSON parser

For anyone interested, I have just pushed a new builtins/json.e module to the Phix repository (see https://bitbucket.org/petelomax/phix/src ), which should be compatible with OpenEuphoria.

Example use:

include builtins/json.e 
 
puts(1,"roundtrip (10 examples):\n") 
sequence json_strings = {"{\"this\":\"that\",\"age\":{\"this\":\"that\",\"age\":29}}", 
                         "1", 
                         "\"hello\"", 
                         "null", 
                         "[12]", 
                         "[null,12]", 
                         "[]", 
                         "{\"this\":\"that\",\"age\":29}", 
                         "{}", 
                         "[null,[null,12]]"} 
 
for i=1 to length(json_strings) do 
    string s = json_strings[i] 
    puts(1,s&"\n") 
    object json_object = parse_json(s) 
    puts(1,print_json("",json_object,true)&"\n") 
    if not equal(print_json("",json_object,true),s) then ?9/0 end if 
end for 

I would be interested to hear any tales of success or failure with it.

Pete

new topic     » goto parent     » topic index » view message » categorize

15. Re: Euphoria JSON parser

Thanks to the various replies - plenty there for me to work with. Appreciated.

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu