The JSONStreamParser structure

The JSONStreamParser structure provides an event-based (or stream) parsing model for JSON files. It is suitable for scanning large files for particular items without having to first build an in-memory data structure. It can also be useful to directly translate from JSON to a specific SML datatype without having to go through the intermediate JSON.value representation.

Synopsis

structure JSONStreamParser

Interface

type source

type 'ctx callbacks = {
    null : 'ctx -> 'ctx,
    boolean : 'ctx * bool -> 'ctx,
    integer : 'ctx * IntInf.int -> 'ctx,
    float : 'ctx * real -> 'ctx,
    string : 'ctx * string -> 'ctx,
    startObject : 'ctx -> 'ctx,
    objectKey : 'ctx * string -> 'ctx,
    endObject : 'ctx -> 'ctx,
    startArray : 'ctx -> 'ctx,
    endArray : 'ctx -> 'ctx,
    error : 'ctx * string -> unit
  }

val openStream : TextIO.instream -> source
val openFile : string -> source
val openString : string -> source

val close : source -> unit

val parse : 'ctx callbacks -> (source * 'ctx) -> 'ctx

val parseFile : 'ctx callbacks -> (string * 'ctx) -> 'ctx

Description

type source

The abstract type of JSON input sources. Note that this type is the same as JSONParser.source.

type 'ctx callbacks = { …​ }

This type is a record of the parsing-event call-back functions, where the type parameter 'cxt is instantiated to the context (or state) needed to preserve information between events. The call-back functions in this record type are invoked as follows:

null : 'ctx -> 'ctx

called when the JSON null value is encountered.

boolean : 'ctx * bool -> 'ctx

called when the JSON true or false values are encountered.

integer : 'ctx * IntInf.int -> 'ctx

called when a JSON integral-number value encountered.

float : 'ctx * real -> 'ctx

called when a JSON floating-point-number value encountered.

string : 'ctx * string -> 'ctx

called when a JSON string value encountered.

startObject : 'ctx -> 'ctx

called at the beginning of a JSON object definition (i.e., when a “{” is encountered).

objectKey : 'ctx * string -> 'ctx

called when a JSON object key is encountered (including the "`:"). The next call-back will specify the value associated with the key.

endObject : 'ctx -> 'ctx

called at the end of a JSON object definition (i.e., when a “}” is encountered).

startArray : 'ctx -> 'ctx

called at the beginning of a JSON array definition (i.e., when a “[” is encountered).

endArray : 'ctx -> 'ctx

called at the end of a JSON array definition (i.e., when a “]” is encountered).

error : 'ctx * string -> unit

called when a syntax error is encountered in the input. The second argument is an error message describing the error. It is expected that this call-back does not return (i.e., it either raises an exception or terminates the program). If it does return, then the parser will raise the Fail exception.

val openStream : TextIO.instream → source

openStream inS returns a input source for the given input stream.

val openFile : string → source

openStream file returns a input source for the given file. This function opens an input stream for reading from the file, so one should make sure to call close on the source once all of the JSON values have been read from the file.

val openString : string → source

openStream s returns a input source for the given string.

val close : source → unit

close src closes the input source, which has the effect of marking the source as closed. Furthermore, if src was created by a call to openFile, then the underlying input stream that was created for the file is closed. This function does not close the input stream for sources created by openStream

val parse : 'ctx callbacks -> (source * 'ctx) -> 'ctx

parse cbs (src, cxt) will parse the JSON input from the input source src, using the record of call-back functions cbs and the initial context cxt.

val parseFile : 'ctx callbacks -> (string * 'ctx) -> 'ctx

parse cbs (f, cxt) will parse the JSON input from the file f, using the record of call-back functions cbs and the initial context cxt. Note that this function will only parse a single JSON value from the file; to parse multiple values, one should used the parse function with a source created by openFile.

Exampless

Consider the following JSON input:

{ "a" : 23,
  "b" : [ false, true ],
  "c" : "hello world"
}

Parsing this value has the same result as evaluating the following function:

fun f cxt = let
      val cxt = startObject cxt
      val cxt = objectKey (cxt, "a")
      val cxt = integer (cxt, 23)
      val cxt = objectKey (cxt, "b")
      val cxt = startArray cxt
      val cxt = boolean (cxt, false)
      val cxt = boolean (cxt, true)
      val cxt = endArray cxt
      val cxt = objectKey (cxt, "c")
      val cxt = objectString (cxt, "hello world")
      val cxt = endObject cxt
      in
        cxt
      end

The following function returns a list of all of the string-valued fields labeled as "name" in the input file.

fun getNames file = let
      fun objectKey ({names, ...}, "name") = {names = names, isName = true}
        | objectKey (cxt, _) = cxt
      fun string (cxt as {names, isName}, s) = if isName
            then {names = s :: names, isName = false}
            else cxt
      fun default ({names, isName}, _) = {names = names, isName = false}
      val cbs = {
              null = Fn.id,
              boolean = default,
              integer = default,
              float = default,
              string = string,
              startObject = Fn.id,
              objectKey = objectKey,
              endObject = Fn.id,
              startArray = Fn.id,
              endArray = Fn.id,
              error = fn (_, msg) => raise Fail msg
            }
      val {names, ...} =
            JSONStreamParser.parseFile cbs (file, {names = [], isName = false})
      in
        List.rev names
      end