tests | ||
.dir-locals.el | ||
.envrc | ||
LICENSE | ||
README.org | ||
srfi-180.egg | ||
srfi-180.impl.scm | ||
srfi-180.org | ||
srfi-180.release-info | ||
srfi-180.scm |
SRFI-180
Dependencies
Main dependencies:
Egg | Description |
---|---|
srfi-34 | Exception Handling |
srfi-35 | Exception Types |
srfi-158 | Generators |
Test dependencies:
Egg | Description |
---|---|
test | The de-facto standard test egg |
API
Exceptions
This library defines an SRFI-35 exception type &json-error
that gets raised when invalid tokens are encountered. The exception type has a field json-invalid-token
that contains the offending token.
(define-condition-type &json-error &error
json-error?
(json-error-reason json-error-reason)
(json-invalid-token json-invalid-token))
Parameters
This library offers the following configuration parameters:
Parameter | Default | Description |
---|---|---|
json-nesting-depth-limit | +inf.0 | the maximum nesting depth of JSON that can be read. |
json-number-of-character-limit | +inf.0 | the maximum length of JSON input that can be read. |
Predicates
For some reason, this SRFI includes a predicate to check for JSON null values:
(define (json-null? obj) (eq? obj 'null))
Reading JSON
json-generator
(json-generator [port-or-generator]) → generator
Streaming event-based JSON reader. PORT-OR-GENERATOR
default value is the value returned by current-input-port
. It must be a textual input port or a generator of characters. json-generator
returns a generator of Scheme objects, each of which must be one of:
'array-start
symbol denoting that an array should be constructed.'array-end
symbol denoting that the construction of the array for which the last'array-start
was generated and not closed is finished.'object-start
symbol denoting that an object should be constructed. The object's key-value pairs are emitted in sequence like those in a property list (plist) where keys are strings. That is, the generation of a key is always followed by the generation of a value. Otherwise, the JSON would be invalid andjson-generator
would raise an error.'object-end
symbol denoting that the construction of the object for which the last'object-start
was generated and not closed is finished.- the symbol
'null
- boolean
- number
- string
In the case where nesting of arrays or objects reaches the value returned by the parameter json-nesting-depth-limit
, the generator must raise an object that satisfies the predicate json-error?
.
In cases where the JSON is invalid, the generator returned by json-generator
should raise an object that satisfies the predicate json-error?
.
Otherwise, if PORT-OR-GENERATOR
contains valid JSON text, the generator returned by json-generator
must yield an end-of-file object in two situations:
- The first time the generator returned by
json-generator
is called, it returns an object that is a boolean, a number, a string or the symbol'null
. - The first time the generator returned by
json-generator
is called, it returns a symbol that is not the symbol'null
. When the underlying JSON text is valid, it should be the symbol starting a structure:'object-start
or'array-start
. The end-of-file object is generated when that structure is finished.
In other words, the generator returned by json-generator
will parse at most one JSON value or one top-level structure. If PORT
is not finished, as in the case of JSON lines, the user should call json-generator
again with the same PORT-OR-GENERATOR
.
Examples
(call-with-input-string "42 101 1337" (lambda (port) (generator->list (json-generator port))))
(42)
(call-with-input-string "[42] 101 1337" (lambda (port) (generator->list (json-generator port))))
(array-start 42 array-end)
json-fold
(json-fold proc array-start array-end object-start object-end seed [port-or-generator])
Fundamental JSON iterator.
json-fold
will read the JSON text from PORT-OR-GENERATOR
, which has (current-input-port)
as its default value. json-fold
will call the procedures passed as argument:
(PROC obj seed)
is called when a JSON value is generated or a complete JSON structure is read.PROC
should return the new seed that will be used to iterate over the rest of the generator. Termination is described below.(OBJECT-START seed)
is called with a seed and should return a seed that will be used as the seed of the iteration over the key and values of that object.(OBJECT-END seed)
is called with a seed and should return a new seed that is the result of the iteration over a JSON object.
ARRAY-START
and ARRAY-END
take the same arguments, and have similar behavior, but are called for iterating on JSON arrays.
json-fold
must return the seed when:
PORT-OR-GENERATOR
yields an object that satisfies the predicateeof-object?
- All structures, array or object, that were started have ended. The returned object is
(PROC obj SEED)
where obj is the object returned byARRAY-END
orOBJECT-END
json-read
(json-read [port-or-generator]) → object
JSON reader procedure. PORT-OR-GENERATOR
must be a textual input port or a generator of characters. The default value of PORT-OR-GENERATOR
is the value returned by the procedure current-input-port
. The returned value is a Scheme object. json-read
must return only the first toplevel JSON value or structure. When there are multiple toplevel values or structures in PORT-OR-GENERATOR
, the user should call json-read
several times to read all of it.
The mapping between JSON types and Scheme objects is the following:
null
→ the symbol'null
true
→#t
false
→#f
number
→ numberstring
→ stringarray
→ vectorobject
→ association list with keys that are symbols
In the case where nesting of arrays or objects reaches the value returned by the parameter json-nesting-depth-limit
, json-read
must raise an object that satisfies the predicate json-error?
json-lines-read
(json-lines-read [port-or-generator]) → generator
JSON reader of jsonlines or ndjson. As its first and only argument, it takes a generator of characters or a textual input port whose default value is the value returned by current-input-port
. It will return a generator of Scheme objects as specified in json-read
.
json-sequence-read
(json-sequence-read [port-or-generator]) → generator
JSON reader of JSON Text Sequences (RFC 7464). As its first and only argument, it takes a generator of characters or a textual input port whose default value is the value returned by current-input-port
. It will return a generator of Scheme objects as specified in json-read
.
json-accumulator
(json-accumulator port-or-accumulator) → procedure
Streaming event-based JSON writer. PORT-OR-ACCUMULATOR
must be a textual output port or an accumulator that accepts characters and strings. It returns an accumulator procedure that accepts Scheme objects as its first and only argument and that follows the same protocol as described in json-generator
. Any deviation from the protocol must raise an error that satisfies json-error?
. In particular, objects and arrays must be properly nested.
Mind the fact that most JSON parsers have a nesting limit that is not documented by the standard. Even if you can produce arbitrarily nested JSON with this library, you might not be able to read it with another library.
json-write
(json-write obj [port-or-accumulator]) → unspecified
JSON writer procedure. PORT-OR-ACCUMULATOR
must be a textual output port, or an accumulator that accepts characters and strings. The default value of PORT-OR-ACCUMULATOR
is the value returned by the procedure current-output-port
. The value returned by json-write
is unspecified.
json-write
will validate that OBJ
can be serialized into JSON before writing to PORT
. An error that satisfies json-error?
is raised in the case where OBJ
is not an object or a composition of the following types:
- symbol
'null
- boolean
- number. Must be integers or inexact rationals. (That is, they must not be complex, infinite, NaN, or exact rationals that are not integers.)
- string
- vector
- association list with keys as symbols
About this egg
Source
The source is available at https://forgejo.lyrion.ch/Chicken/srfi-180.
Author
Daniel Ziltener
Version History
1.5.1 | Escape sequences |
1.5.0 | Reimplementation |
1.0.0 | Reference Implementation |
License
Copyright (C) 2022 Daniel Ziltener
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
,* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
,* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
,* Neither the name of the <organization> nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.