The JSONStreamParser structure
Author: John Reppy
Keywords: Standard ML, SML, SML/NJ Library

The SML of NJ Library
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

## See Also

`JSONParser`, `JSONStreamPrinter`, The JSON Library

SML/NJ Version 110.99.1 (September 23, 2021)
Last updated 2020-07-10 19:59:16 UTC