9.2.1 JSON Parsing

Refer to the Jzon documentation. The FSet/Jzon parsing API exports many of the same names as Jzon, and is mostly used in the same way. The exception is when the input contains, potentially, more than one top-level JSON value. In this case, pass :allow-multiple-content t to make-parser or with-parser, as you would have with Jzon, but then call parse-top-level once for each top-level value you wish to parse. FSet/Jzon does not export parse-next.

As mentioned, JSON arrays parse into FSet seqs. For JSON objects, you have a choice:

The object representation is controlled by the object-type keyword argument to with-parser or make-parser. In the map case, the keys will be strings by default; to have them interned, pass an appropriate key-package, or use key-fn to transform them into whatever type you like.

Tuples are FSet’s most space-efficient and featureful representation of JSON objects, but require a bit more work to set up. You will need a tuple key for each key in the JSON you’re parsing. The name of each tuple key should contain the corresponding JSON key string, normally upcased and with a prefix and/or suffix added; the use of a prefix and/or suffix is optional, but highly recommended. For example, if your JSON contains keys "size" and "color", the corresponding tuple key names could be +JSON-SIZE+ and +JSON-COLOR+ (written here in uppercase because that’s how they’ll print, but of course you can normally write them in lowercase in source code). Thus the prefix is "+JSON-" and the suffix is "+". With that in mind, the steps are:

On printing, the keys will be in the order in which they were declared, or if some keys were found in the input that had not been declared, the order in which they were first encountered. (You can still call fset2:define-tuple-key on them after parsing, if you hadn’t done it beforehand.)

As mentioned above, parsing into tuples (but not maps) converts null into nil. Also, since printing from tuples prints [] for nil when the key is of list type, parsing converts [] back to nil in this case. So even though I recommend using seqs instead of lists for sequence-valued data, it’s still safe to use lists (but only with tuples, not maps).

Data type: json-atom

Re-exported from Jzon.

Data type: json-element

(or json-atom seq map tuple)

Macro: with-parser (var in &rest kwd-args) &body body

Binds var around body to an FSet/Jzon parser that will read from in, which can be a vector, a stream, or a pathname. The keyword arguments are passed unchanged to make-parser. Calls close-parser on the parser before returning.

Function: make-parser in &key allow-comments allow-trailing-comma allow-multiple-content (max-string-length 1048576) (max-depth 128) (key-fn (make-fset-string-pool)) (object-type ’replay-map) key-package (key-case-mode ’:upcase) (key-prefix "") (key-suffix "")

If allow-comments is true, comments as in C (// for single-line or /* ... */ for block) will be accepted. If allow-trailing-comma, a comma will be permitted after the last element of an array or object. max-string-length limits the length of strings, and max-depth the maximum nesting depth; these help protect against DoS attacks. key-fn controls whether and how string pooling is done; the default uses an FSet set.

The returned parser should be closed after use; see close-parser, and macro with-parser which closes it automatically.

If allow-multiple-content is true, the input may contain multiple top-level JSON values, which you can read by calling parse-top-level multiple times.

JSON arrays are returned as FSet seqs; JSON objects are returned according to object-type, which can be replay-map, map, or tuple (symbols in package fset2). If key-package is supplied, keys will be interned in this package; this option overrides key-fn. If object-type is tuple, key-package is required, and may not be the CL keyword package. If key-package is supplied: (a) key-case-mode can be any of :upcase, :downcase, or :preserve (the default is :upcase); (b) if supplied, key-prefix is prepended and key-suffix is appended to the case-converted key before interning.

Function: close-parser parser

Closes the parser. If the input was specified as a pathname, closes the input stream.

Other parsing-related symbols re-exported from Jzon are: json-atom, json-error, json-limit-error, json-parse-error, json-parse-limit-error, and json-eof-error.