Skip to content
Jacob Williams edited this page Jul 11, 2019 · 10 revisions

On this page, the basic functionality of the JSON-Fortran library is illustrated. The full API documentation can be found here. In addition, there are various unit tests in the src/tests directory that may be helpful.

Reading JSON from a file

Reading a JSON file and getting data from it is fairly straightforward using the json_file class. Here is an example. See unit tests 1 and 3-6 for more examples.

    program example1

        use json_module

        implicit none

        type(json_file) :: json
        logical :: found
        integer :: i,j,k

        ! initialize the class
        call json%initialize()

        ! read the file
        call json%load(filename = '../files/inputs/test1.json')

        ! print the file to the console
        call json%print()

        ! extract data from the file
        ! [found can be used to check if the data was really there]
        call json%get('version.major', i, found)
        if ( .not. found ) stop 1
        call json%get('version.minor', j, found)
        if ( .not. found ) stop 1
        call json%get('data(1).number', k, found)
        if ( .not. found ) stop 1

        ! clean up
        call json%destroy()
        if (json%failed()) stop 1

    end program example1

Reading JSON from a string

JSON can also be read directly from a character string like so:

    call json%deserialize('{"name": "Leonidas"}')

Modifying variables in a JSON file

After reading a JSON file, if you want to change the values of some of the variables, you can use the update method. For the example above:

    ! [found can be used to check if the data was really there]
    call json%update('version.major',9,found)  !change major version to 9
    call json%update('version.minor',0,found)  !change minor version to 0
    call json%update('version.patch',0,found)  !change patch to 0

Specifying paths

There are three ways to specify the path to a JSON variable. This is done using the path_mode argument of the various initialize methods. The value values are:

  1. Default
  2. RFC 6901
  3. JSONPath "Bracket Notation"

For the default way, the following special characters are used to denote paths:

  $         - root
  @         - this
  .         - child object member
  [] or ()  - child array element

Thus, if any of these characters are present in the name key, the get_by_path methods cannot be used to get the value. In that case, the get_child methods would need to be used. Note that array indices in the default mode are 1-based (Fortran style). The default mode is a subset of the JSONPath "dot notation" specification.

Alternately, RFC 6901 paths can be used to retrieve any variable in a JSON structure. Note that array indices in RFC 6901 mode are 0-based.

The JSONPath "Bracket Notation" mode may also be used. This uses 1-based (Fortran-style) array indices like the default mode. In this mode, every key is enclosed in square brackets and string keys are enclosed on quotes. An example path is: $['store']['book'][0]['title'] (either single or double quotes may be used).

Writing a JSON file

To print the JSON file (either to a file or the console), the print method can be used. For the above example:

    call json%print()         !prints to the console
    call json%print(iunit)    !prints to the file connected to iunit
    call json%print(filename) !prints to the filename (internal unit is used)

Building a JSON file from scratch

Constructing a JSON file element by element is slightly more complicated and involves the use of json_value pointers. In order to manipulate these pointers a json_core class is provided. For more examples see unit tests 2, 4 and 7.

    program example2

        use,intrinsic :: iso_fortran_env, only: wp => real64
        use json_module

        implicit none

        type(json_core) :: json
        type(json_value),pointer :: p, inp

        ! initialize the class
        call json%initialize()

        ! initialize the structure:
        call json%create_object(p,'')

        ! add an "inputs" object to the structure:
        call json%create_object(inp,'inputs')
        call json%add(p, inp) !add it to the root

        ! add some data to inputs:
        call json%add(inp, 't0', 0.1_wp)
        call json%add(inp, 'tf', 1.1_wp)
        call json%add(inp, 'x0', 9999.0000d0)
        call json%add(inp, 'integer_scalar', 787)
        call json%add(inp, 'integer_array', [2,4,99])
        call json%add(inp, 'names', ['aaa','bbb','ccc'])
        call json%add(inp, 'logical_scalar', .true.)
        call json%add(inp, 'logical_vector', [.true., .false., .true.])
        nullify(inp)  !don't need this anymore

        ! write the file:
        call json%print(p,'../files/example2.json')

        !cleanup:
        call json%destroy(p)
        if (json%failed()) stop 1

    end program example2

The code above produces the file:

{
  "inputs": {
    "t0": 0.1E+0,
    "tf": 0.11E+1,
    "x0": 0.9999E+4,
    "integer_scalar": 787,
    "integer_array": [
      2,
      4,
      99
    ],
    "names": [
      "aaa",
      "bbb",
      "ccc"
    ],
    "logical_scalar": true,
    "logical_vector": [
      true,
      false,
      true
    ]
  }
}