142 lines
5.9 KiB
Racket
142 lines
5.9 KiB
Racket
#lang scribble/manual
|
|
|
|
@(require (for-label racket/base json))
|
|
|
|
@(define website @link["http://json.org"]{JSON web site})
|
|
@(define rfc @link["http://www.ietf.org/rfc/rfc4627.txt"]{JSON RFC})
|
|
|
|
@; @(begin (require scribble/eval)
|
|
@; (define ev (make-base-eval))
|
|
@; (ev '(require json)))
|
|
|
|
@title{JSON}
|
|
|
|
@author["Eli Barzilay" "Dave Herman"]
|
|
|
|
@defmodule[json]
|
|
|
|
This library provides utilities for parsing and producing data in the
|
|
JSON data exchange format to/from Racket values. See the @website and
|
|
the @rfc for more information about JSON.
|
|
|
|
@section{JS-Expressions}
|
|
|
|
@defproc[(jsexpr? [x any] [#:null jsnull any? (json-null)])
|
|
boolean?]{
|
|
Performs a deep check to determine whether @racket[x] is a @tech{jsexpr}.
|
|
|
|
This library defines a subset of Racket values that can be represented
|
|
as JSON strings, and this predicates checks for such values. A
|
|
@deftech{JS-Expression}, or @deftech{jsexpr}, is one of:
|
|
|
|
@itemize[
|
|
@item{the value of @racket[jsnull], @racket['null] by default}
|
|
@item{@racket[boolean?]}
|
|
@item{@racket[string?]}
|
|
@item{@racket[(or exact-integer? inexact-real?)]}
|
|
@item{@racket[(listof jsexpr?)]}
|
|
@item{@racket[(hasheqof symbol? jsexpr?)]}]}
|
|
|
|
@defparam[json-null jsnull any?]{
|
|
This parameter determines the default Racket value that corresponds to
|
|
a JSON ``@tt{null}''. By default, it is the @racket['null] symbol.
|
|
In some cases a different value may better fit your needs, therefore
|
|
all functions in this library accept a @racket[#:null] keyword
|
|
argument for the value that is used to represent a JSON ``@tt{null}'',
|
|
and this argument defaults to @racket[(json-null)].}
|
|
|
|
@section{Generating JSON Text from JS-Expressions}
|
|
|
|
@defproc[(write-json [x jsexpr?] [out output-port? (current-output-port)]
|
|
[#:null jsnull any? (json-null)]
|
|
[#:encode encode (or/c 'control 'all) 'control])
|
|
any]{
|
|
Writes the @racket[x] @tech{jsexpr}, encoded as JSON, to the
|
|
@racket[outp] output port.
|
|
|
|
By default, only ASCII control characters are encoded as
|
|
``@tt{\uHHHH}''. If @racket[encode] is given as @racket['all], then
|
|
in addition to ASCII control characters, non-ASCII characters are
|
|
encoded as well. This can be useful if you need to transport the text
|
|
via channels that might not support UTF-8. Note that characters in
|
|
the range of @tt{U+10000} and above are encoded as two @tt{\uHHHH}
|
|
escapes, see Section 2.5 of the @|rfc|.}
|
|
|
|
@defproc[(jsexpr->string [x jsexpr?]
|
|
[#:null jsnull any? (json-null)]
|
|
[#:encode encode (or/c 'control 'all) 'control])
|
|
string?]{
|
|
Generates a JSON source string for the @tech{jsexpr} @racket[x].}
|
|
|
|
@defproc[(jsexpr->bytes [x jsexpr?]
|
|
[#:null jsnull any? (json-null)]
|
|
[#:encode encode (or/c 'control 'all) 'control])
|
|
bytes?]{
|
|
Generates a JSON source byte string for the @tech{jsexpr} @racket[x].
|
|
(The byte string is encoded in UTF-8.)}
|
|
|
|
@section{Parsing JSON Text into JS-Expressions}
|
|
|
|
@defproc[(read-json [in input-port? (current-input-port)]
|
|
[#:null jsnull any? (json-null)])
|
|
(or/c jsexpr? eof-object?)]{
|
|
Reads a @tech{jsexpr} from a JSON-encoded input port @racket[in] as a
|
|
Racket (immutable) value, or produces @racket[eof] if only whitespace
|
|
remains.}
|
|
|
|
@defproc[(string->jsexpr [str string?] [#:null jsnull any? (json-null)])
|
|
jsexpr?]{
|
|
Parses the JSON string @racket[str] as an immutable @tech{jsexpr}.}
|
|
|
|
@defproc[(bytes->jsexpr [str bytes?] [#:null jsnull any? (json-null)])
|
|
jsexpr?]{
|
|
Parses the JSON bytes string @racket[str] as an immutable @tech{jsexpr}.}
|
|
|
|
@section{A Word About Design}
|
|
|
|
@subsection{The JS-Expression Data Type}
|
|
|
|
JSON syntactically distinguishes ``@tt{null}'', array literals, and
|
|
object literals, and therefore there is a question of what Racket value
|
|
should represent a JSON ``@tt{null}''. This library uses the Racket
|
|
@racket['null] symbol by default. Note that this is unambiguous, since
|
|
Racket symbols are used only as object keys, which are required to be
|
|
strings in JSON.
|
|
|
|
Several other options have been used by various libaries. For example,
|
|
Dave Herman's PLaneT library (which has been the basis for this library)
|
|
uses the @racket[#\nul] character, other libraries for Racket and other
|
|
Lisps use @racket[(void)], @tt{NIL} (some use it also for JSON
|
|
``@tt{false}''), and more. The approach taken by this library is to use
|
|
a keyword argument for all functions, with a parameter that determines
|
|
its default, making it easy to use any value that fits your needs.
|
|
|
|
The @rfc only states that object literal expressions ``SHOULD'' contain
|
|
unique keys, but does not proscribe them entirely. Looking at existing
|
|
practice, it appears that popular JSON libraries parse object literals
|
|
with duplicate keys by simply picking one of the key-value pairs and
|
|
discarding the others with the same key. This behavior is naturally
|
|
paralleled by Racket hash tables, making them a natural analog.
|
|
|
|
Finally, the @rfc is almost completely silent about the order of
|
|
key-value pairs. While the RFC only specifies the syntax of JSON, which
|
|
of course always must represent object literals as an ordered
|
|
collection, the introduction states:
|
|
|
|
@nested[#:style 'inset]{
|
|
An object is an unordered collection of zero or more name/value pairs,
|
|
where a name is a string and a value is a string, number, boolean,
|
|
null, object, or array.}
|
|
|
|
In practice, JSON libraries discard the order of object literals in
|
|
parsed JSON text and make no guarantees about the order of generated
|
|
object literals, usually using a hash table of some flavor as a natural
|
|
choice. We therefore use do so as well.
|
|
|
|
@subsection{Naming Conventions}
|
|
|
|
Some names in this library use ``jsexpr'' and some use ``json''. The
|
|
rationale that the first is used for our representation, and the second
|
|
is used as information that is received from or sent to the outside
|
|
world.
|