For Development HEAD DRAFTSearch (procedure/syntax/module):

12.49 rfc.json - JSON parsing and construction

Module: rfc.json

Procedures to parse JSON (RFC7159) data to S-expressions, and convert S-expressions to JSON representation, are provided.

Parsing JSON

Condition type: <json-parse-error>

{rfc.json} The parser parse-json and parse-json-string raise this condition when they encounter invalid JSON syntax. It inherits <error>, and adds the following slot.

Instance Variable of <json-parse-error>: position

The input position, counted in characters, where the error occurred.

Parameter: json-nesting-depth-limit

[SRFI-180]{rfc.json} Its value must be a real number, specifying the maximum nesting depth of JSON text that can be parsed by parse-json. If the input exceeds the value, an <json-parse-error> is thrown. The default value is +inf.0.

Function: parse-json :optional input-port

{rfc.json} Reads and parses the JSON representation from input-port (default is the current input port), and returns the result in an S-expression. May raise a <json-parse-error> condition when parse error occurs, or the nesting level exceeds the value of json-nesting-depth-limit.

The following table shows how JSON datatypes are mapped to Scheme objects.

true, false, null

Symbols true, false and null. (Customizable by json-special-handler)

Arrays

Scheme vectors. (Customizable by json-array-handler)

Objects

Scheme assoc-lists, in which keys are strings, and values are Scheme objects. (Customizable by json-object-handler)

Numbers

Scheme inexact real numbers.

Strings

Scheme strings.

Since the parser used internally in parse-json prefetches characters, some characters after the parsed JSON expression may already been read from port when parse-json returns. That is, you cannot call parse-json repeatedly on port to read subsequent JSON expressions. Use parse-json* if you need to read multiple JSON expressions.

Function: parse-json* :optional input-port

{rfc.json} Read JSON repeatedly from input-port until it reaches EOF, and returns parsed results as a list.

Function: parse-json-string str

{rfc.json} Parses the JSON string and returns the result in an S-expression. May raise a <json-parse-error> condition when parse error occurs.

See parse-json above for the mappings from JSON datatypes to Scheme types.

Parameter: json-array-handler
Parameter: json-object-handler
Parameter: json-special-handler

{rfc.json} The value of these parameters must be a procedure that takes one argument: for json-array-handler, it is a list of elements of a JSON array, for json-object-handler, it is a list of conses of key and value of a JSON object, and for json-special-handler, it is one of the symbols false, true or null.

Whenever parse-json reads a JSON array, a JSON object, or one of those special values, it calls corresponding parameter to get a Scheme object.

The default value of these parameters are list->vector, identity, and identity, respectively.

The following example maps JSON objects to hash tables.

(parameterize ([json-object-handler (cut alist->hash-table <> 'string=?)])
  (parse-json-string "{\"a\":1, \"b\":2}"))
 ⇒ #<hash-table ...>

Constructing JSON

Condition type: <json-construct-error>

{rfc.json} The converters construct-json and construct-json-string raise this condition when they cannot convert given Scheme object to JSON. It inherits <error>, and adds the following slot.

Instance Variable of <json-construct-error>: object

The Scheme object that cannot convert to JSON representation.

Class: <json-mixin>

{rfc.json} A Gauche object of a class inheriting this mixin class is automatically serialized to JSON object with the following rule:

  • Each slot of the object is examined. Only the slots with its slot definition has a true value in :json-name option are the subject to be serialized.
  • If :json-name option is #t, the slot name is used as the key; otherwise, string representation (x->string) of the option’s value is used as the key.
  • Then the slot value is serialized recursively.
(define-class <foo> (<json-mixin>)
  ((slot-1 :init-keyword :slot-1 :json-name "Slot1")
   (slot-2 :init-keyword :slot-2 :json-name #t)
   (slot-3 :init-keyword :slot-3)))

(construct-json
  (make <foo> :slot-1 "xyz" :slot-2 123 :slot-3 'abc))
 ⇒ prints
 {"Slot1":"xyz","slot-2":123}
Function: construct-json obj :optional output-port
Function: construct-json-string obj

{rfc.json} Creates JSON representation of Scheme object obj. construct-json writes out the result to output-port, whose default is the current output port. construct-json-string returns the result in a string.

If obj contains a Scheme object that cannot be mapped to JSON representation, a <json-construct-error> condition is raised.

Scheme objects are mapped to JSON as follows:

symbol false, #f

false

symbol true, #t

true

symbol null

null

list, instance of <dictionary>

JSON object (list must be an assoc list of key and value).

string

string

real number

number

instance of <sequence> (except strings and lists)

JSON array



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT