Home

Awesome

json-streams

json-streams is a Common Lisp library for reading and writing JSON text.

Homepage: https://github.com/rotatef/json-streams

Features

High level interface

Streaming interface for output

Example

(with-json-output (nil :key-encoder #'string-downcase :indent t)
  (with-json-object
    (json-output-member :first-name "John")
    (json-output-member :last-name "Smith")
    (with-json-member :is-alive (json-output-boolean t))
    (json-output-member :age 25)
    (with-json-member :address
      (json-output-alist '((:street-address . "21 2nd Street")
                           (:city . "New York")
                           (:state . "NY")
                           (:postal-code . "10021-3100"))))
    (with-json-member :phone-numbers
      (with-json-array
        (json-output-plist '(:type "home"
                             :number "212 555-1234"))
        (json-output-plist '(:type "office"
                             :number "646 555-4567"))
        (json-output-plist '(:type "mobile"
                             :number "123 456-7890"))))
    (json-output-member :children #())
    (with-json-member :spouse (json-output-null))))
Macro
JSON-STREAMS:WITH-JSON-OUTPUT (&optional target &rest options) &body body

The options are explained under MAKE-JSON-OUTPUT-STREAM. Target must be a character stream or NIL. If target is NIL output is written to a string that is returned, otherwise the values of body is returned.

The following functions and macros can only be used inside the body of WITH-JSON-OUTPUT:

Parsing and writing using an unambigious s-expression notation

The high level interface uses the following datatype mapping:

JSONCommon Lisp
trueT
falseNIL
null:NULL
stringstring
numberinteger, float or ratio
array(:ARRAY ... )
object(:OBJECT (key . value) ... )

The options are explained under MAKE-JSON-INPUT-STREAM and MAKE-JSON-OUTPUT-STREAM.

Function
JSON-STREAMS:JSON-PARSE source &rest options
=> json, position

Parses a single JSON text from source. The second value is the position where parsing stopped.

Function
JSON-STREAMS:JSON-PARSE-MULTIPLE source &rest options
=> jsons

Parses zero or more JSON texts from source. Returns a list of JSON values.

Function
JSON-STREAMS:JSON-STRINGIFY value &optional target &rest options

Stringifies value into JSON text. If target is not provided or NIL, returns a string with the JSON text. Otherwise target must be a character stream.

Function
JSON-STREAMS:JSON-STRINGIFY-MULTIPLE values &optional target &rest options

Stringifies multiple json values.

The streaming interface

See parse.lisp and stringify.lisp for examples of how to use the streaming interface.

Function
JSON-STREAMS:MAKE-JSON-INPUT-STREAM source &key start end close-stream multiple duplicate-key-check use-ratios max-exponent raw-strings
=> json-input-stream
Function
JSON-STREAMS:MAKE-JSON-OUTPUT-STREAM stream &key close-stream multiple duplicate-key-check indent escape-non-ascii
=> json-input-stream

Common options

Function
JSON-STREAMS:JSON-READ json-input-stream
=> token

Parses JSON text from the underlying stream and returns the next token.

Function
JSON-STREAMS:JSON-WRITE token json-output-stream
=> token

Outputs JSON text to underlying stream based on the given token.

Function
JSON-STREAMS:JSON-CLOSE json-stream &key abort

Closes the json-stream. Applications should always call JSON-CLOSE when finished with a JSON stream. This ensures that all syntax errors are detected. The value of abort is forwarded to CL:CLOSE of the underlying stream (if close-stream was true) and JSON syntax checking is suppressed.

Macro
JSON-STREAMS:WITH-OPEN-JSON-STREAM (var json-stream) &body

Binds var to json-stream, executes body, and ensures that JSON-CLOSE is called on json-stream.

Tokens

The possible tokens for input and output are

After a :BEGIN-OBJECT is returned, JSON-READ will alternate between returning keys and values of the object, until :END-OBJECT is returned instead of a key. Keys are always returned as strings. Values can be anything, except :END-OBJECT, :END-ARRAY and :EOF. Thus some kind of recursive or stack based algorithm is neccearry.

Handling of numbers

While JSON standard doesn't define any limits on the size of numbers, many progamming languages does. This library assumes the limits of JavaScript. In JavaScript there is only one number type, a 64-bit IEEE 754 double precision float. This has the following implications:

The syntax doesn't matter: 20, 20.0 or 2e1 are all the same number, the integer 20.

The integer range is +/- (expt 10 53). Numbers outside this range can't be represented accurately. This library will refuse to write an integer outside this range. If you need to output such large numbers, convert them to double-float or string.

At input the handling of numbers outside the integer range depends on syntax. If the number contains a decimal point or an exponent it will be returned as a double-float. Otherwise an error will be signalled. The option :USE-RATIOS disables this check.