json_value_print Subroutine

private recursive subroutine json_value_print(json, p, iunit, str, indent, need_comma, colon, is_array_element, is_compressed_vector, iloc)

Print the JSON structure to a string or a file.

Notes

  • This is an internal routine called by the various wrapper routines.
  • The reason the str argument is non-optional is because of a bug in v4.9 of the gfortran compiler.

Type Bound

json_core

Arguments

Type IntentOptional Attributes Name
class(json_core), intent(inout) :: json
type(json_value), intent(in), pointer :: p
integer(kind=IK), intent(in) :: iunit

file unit to write to (the file is assumed to be open)

character(kind=CK, len=:), intent(inout), allocatable :: str

if iunit==unit2str (-1) then the structure is printed to this string rather than a file. This mode is used by json_value_to_string.

integer(kind=IK), intent(in), optional :: indent

indention level

logical(kind=LK), intent(in), optional :: need_comma

if it needs a comma after it

logical(kind=LK), intent(in), optional :: colon

if the colon was just written

logical(kind=LK), intent(in), optional :: is_array_element

if this is an array element

logical(kind=LK), intent(in), optional :: is_compressed_vector

if True, this is an element from an array being printed on one line [default is False]

integer(kind=IK), intent(inout) :: iloc

current index in str. should be set to 0 initially. [only used when str is used.]


Calls

proc~~json_value_print~~CallsGraph proc~json_value_print json_core%json_value_print proc~json_value_print->proc~json_value_print none~throw_exception json_core%throw_exception proc~json_value_print->none~throw_exception proc~escape_string escape_string proc~json_value_print->proc~escape_string proc~integer_to_string integer_to_string proc~json_value_print->proc~integer_to_string proc~json_failed json_core%json_failed proc~json_value_print->proc~json_failed proc~json_is_vector json_core%json_is_vector proc~json_value_print->proc~json_is_vector proc~real_to_string real_to_string proc~json_value_print->proc~real_to_string proc~json_throw_exception json_core%json_throw_exception none~throw_exception->proc~json_throw_exception proc~wrap_json_throw_exception json_core%wrap_json_throw_exception none~throw_exception->proc~wrap_json_throw_exception proc~valid_json_hex valid_json_hex proc~escape_string->proc~valid_json_hex proc~json_is_vector->none~throw_exception none~info~2 json_core%info proc~json_is_vector->none~info~2 proc~compact_real_string compact_real_string proc~real_to_string->proc~compact_real_string proc~json_info json_core%json_info none~info~2->proc~json_info proc~json_info_by_path json_core%json_info_by_path none~info~2->proc~json_info_by_path proc~wrap_json_info_by_path json_core%wrap_json_info_by_path none~info~2->proc~wrap_json_info_by_path proc~wrap_json_throw_exception->none~throw_exception interface~to_unicode to_unicode proc~wrap_json_throw_exception->interface~to_unicode proc~to_uni to_uni interface~to_unicode->proc~to_uni proc~to_uni_vec to_uni_vec interface~to_unicode->proc~to_uni_vec proc~json_info->none~throw_exception proc~json_info_by_path->none~info~2 none~get~2 json_core%get proc~json_info_by_path->none~get~2 proc~wrap_json_info_by_path->none~info~2 proc~wrap_json_info_by_path->interface~to_unicode proc~json_get_alloc_string_vec json_core%json_get_alloc_string_vec none~get~2->proc~json_get_alloc_string_vec proc~json_get_alloc_string_vec_by_path json_core%json_get_alloc_string_vec_by_path none~get~2->proc~json_get_alloc_string_vec_by_path proc~json_get_array json_core%json_get_array none~get~2->proc~json_get_array proc~json_get_array_by_path json_core%json_get_array_by_path none~get~2->proc~json_get_array_by_path proc~json_get_by_path json_core%json_get_by_path none~get~2->proc~json_get_by_path proc~json_get_integer json_core%json_get_integer none~get~2->proc~json_get_integer proc~json_get_integer_by_path json_core%json_get_integer_by_path none~get~2->proc~json_get_integer_by_path proc~json_get_integer_vec json_core%json_get_integer_vec none~get~2->proc~json_get_integer_vec proc~json_get_integer_vec_by_path json_core%json_get_integer_vec_by_path none~get~2->proc~json_get_integer_vec_by_path proc~json_get_logical json_core%json_get_logical none~get~2->proc~json_get_logical proc~json_get_logical_by_path json_core%json_get_logical_by_path none~get~2->proc~json_get_logical_by_path proc~json_get_logical_vec json_core%json_get_logical_vec none~get~2->proc~json_get_logical_vec proc~json_get_logical_vec_by_path json_core%json_get_logical_vec_by_path none~get~2->proc~json_get_logical_vec_by_path proc~json_get_real json_core%json_get_real none~get~2->proc~json_get_real proc~json_get_real32 json_core%json_get_real32 none~get~2->proc~json_get_real32 proc~json_get_real32_by_path json_core%json_get_real32_by_path none~get~2->proc~json_get_real32_by_path proc~json_get_real32_vec json_core%json_get_real32_vec none~get~2->proc~json_get_real32_vec proc~json_get_real32_vec_by_path json_core%json_get_real32_vec_by_path none~get~2->proc~json_get_real32_vec_by_path proc~json_get_real_by_path json_core%json_get_real_by_path none~get~2->proc~json_get_real_by_path proc~json_get_real_vec json_core%json_get_real_vec none~get~2->proc~json_get_real_vec proc~json_get_real_vec_by_path json_core%json_get_real_vec_by_path none~get~2->proc~json_get_real_vec_by_path proc~json_get_string json_core%json_get_string none~get~2->proc~json_get_string proc~json_get_string_by_path json_core%json_get_string_by_path none~get~2->proc~json_get_string_by_path proc~json_get_string_vec json_core%json_get_string_vec none~get~2->proc~json_get_string_vec proc~json_get_string_vec_by_path json_core%json_get_string_vec_by_path none~get~2->proc~json_get_string_vec_by_path proc~wrap_json_get_alloc_string_vec_by_path json_core%wrap_json_get_alloc_string_vec_by_path none~get~2->proc~wrap_json_get_alloc_string_vec_by_path proc~wrap_json_get_array_by_path json_core%wrap_json_get_array_by_path none~get~2->proc~wrap_json_get_array_by_path proc~wrap_json_get_by_path json_core%wrap_json_get_by_path none~get~2->proc~wrap_json_get_by_path proc~wrap_json_get_integer_by_path json_core%wrap_json_get_integer_by_path none~get~2->proc~wrap_json_get_integer_by_path proc~wrap_json_get_integer_vec_by_path json_core%wrap_json_get_integer_vec_by_path none~get~2->proc~wrap_json_get_integer_vec_by_path proc~wrap_json_get_logical_by_path json_core%wrap_json_get_logical_by_path none~get~2->proc~wrap_json_get_logical_by_path proc~wrap_json_get_logical_vec_by_path json_core%wrap_json_get_logical_vec_by_path none~get~2->proc~wrap_json_get_logical_vec_by_path proc~wrap_json_get_real32_by_path json_core%wrap_json_get_real32_by_path none~get~2->proc~wrap_json_get_real32_by_path proc~wrap_json_get_real32_vec_by_path json_core%wrap_json_get_real32_vec_by_path none~get~2->proc~wrap_json_get_real32_vec_by_path proc~wrap_json_get_real_by_path json_core%wrap_json_get_real_by_path none~get~2->proc~wrap_json_get_real_by_path proc~wrap_json_get_real_vec_by_path json_core%wrap_json_get_real_vec_by_path none~get~2->proc~wrap_json_get_real_vec_by_path proc~wrap_json_get_string_by_path json_core%wrap_json_get_string_by_path none~get~2->proc~wrap_json_get_string_by_path proc~wrap_json_get_string_vec_by_path json_core%wrap_json_get_string_vec_by_path none~get~2->proc~wrap_json_get_string_vec_by_path proc~json_get_alloc_string_vec->none~get~2 none~string_info json_core%string_info proc~json_get_alloc_string_vec->none~string_info proc~json_get_alloc_string_vec_by_path->none~throw_exception proc~json_get_alloc_string_vec_by_path->none~get~2 proc~flag_not_found flag_not_found proc~json_get_alloc_string_vec_by_path->proc~flag_not_found proc~json_clear_exceptions json_core%json_clear_exceptions proc~json_get_alloc_string_vec_by_path->proc~json_clear_exceptions proc~json_get_array->none~throw_exception proc~json_get_array_by_path->none~throw_exception proc~json_get_array_by_path->none~get~2 proc~json_get_array_by_path->proc~json_clear_exceptions proc~json_get_by_path->none~throw_exception proc~json_get_by_path->proc~integer_to_string proc~json_get_by_path->proc~json_clear_exceptions proc~json_get_by_path_default json_core%json_get_by_path_default proc~json_get_by_path->proc~json_get_by_path_default proc~json_get_by_path_jsonpath_bracket json_core%json_get_by_path_jsonpath_bracket proc~json_get_by_path->proc~json_get_by_path_jsonpath_bracket proc~json_get_by_path_rfc6901 json_core%json_get_by_path_rfc6901 proc~json_get_by_path->proc~json_get_by_path_rfc6901 proc~json_get_integer->none~throw_exception proc~string_to_integer string_to_integer proc~json_get_integer->proc~string_to_integer proc~json_get_integer_by_path->none~throw_exception proc~json_get_integer_by_path->none~get~2 proc~json_get_integer_by_path->proc~flag_not_found proc~json_get_integer_by_path->proc~json_clear_exceptions proc~json_get_integer_vec->none~get~2 proc~json_get_integer_vec_by_path->none~throw_exception proc~json_get_integer_vec_by_path->none~get~2 proc~json_get_integer_vec_by_path->proc~flag_not_found proc~json_get_integer_vec_by_path->proc~json_clear_exceptions proc~json_get_logical->none~throw_exception proc~json_get_logical_by_path->none~throw_exception proc~json_get_logical_by_path->none~get~2 proc~json_get_logical_by_path->proc~flag_not_found proc~json_get_logical_by_path->proc~json_clear_exceptions proc~json_get_logical_vec->none~get~2 proc~json_get_logical_vec_by_path->none~throw_exception proc~json_get_logical_vec_by_path->none~get~2 proc~json_get_logical_vec_by_path->proc~flag_not_found proc~json_get_logical_vec_by_path->proc~json_clear_exceptions proc~json_get_real->none~throw_exception proc~string_to_real string_to_real proc~json_get_real->proc~string_to_real proc~json_get_real32->none~get~2 proc~json_get_real32_by_path->none~get~2 proc~json_get_real32_vec->none~get~2 proc~json_get_real32_vec_by_path->none~get~2 proc~json_get_real_by_path->none~throw_exception proc~json_get_real_by_path->none~get~2 proc~json_get_real_by_path->proc~flag_not_found proc~json_get_real_by_path->proc~json_clear_exceptions proc~json_get_real_vec->none~get~2 proc~json_get_real_vec_by_path->none~throw_exception proc~json_get_real_vec_by_path->none~get~2 proc~json_get_real_vec_by_path->proc~flag_not_found proc~json_get_real_vec_by_path->proc~json_clear_exceptions proc~json_get_string->none~throw_exception proc~json_get_string->proc~escape_string proc~json_get_string->proc~integer_to_string proc~json_get_string->proc~real_to_string proc~json_get_string_by_path->none~throw_exception proc~json_get_string_by_path->none~get~2 proc~json_get_string_by_path->proc~flag_not_found proc~json_get_string_by_path->proc~json_clear_exceptions proc~json_get_string_vec->none~get~2 proc~json_get_string_vec_by_path->none~throw_exception proc~json_get_string_vec_by_path->none~get~2 proc~json_get_string_vec_by_path->proc~flag_not_found proc~json_get_string_vec_by_path->proc~json_clear_exceptions proc~wrap_json_get_alloc_string_vec_by_path->interface~to_unicode proc~wrap_json_get_alloc_string_vec_by_path->none~get~2 proc~wrap_json_get_array_by_path->interface~to_unicode proc~wrap_json_get_array_by_path->none~get~2 proc~wrap_json_get_by_path->interface~to_unicode proc~wrap_json_get_by_path->none~get~2 proc~wrap_json_get_integer_by_path->interface~to_unicode proc~wrap_json_get_integer_by_path->none~get~2 proc~wrap_json_get_integer_vec_by_path->interface~to_unicode proc~wrap_json_get_integer_vec_by_path->none~get~2 proc~wrap_json_get_logical_by_path->interface~to_unicode proc~wrap_json_get_logical_by_path->none~get~2 proc~wrap_json_get_logical_vec_by_path->interface~to_unicode proc~wrap_json_get_logical_vec_by_path->none~get~2 proc~wrap_json_get_real32_by_path->interface~to_unicode proc~wrap_json_get_real32_by_path->none~get~2 proc~wrap_json_get_real32_vec_by_path->interface~to_unicode proc~wrap_json_get_real32_vec_by_path->none~get~2 proc~wrap_json_get_real_by_path->interface~to_unicode proc~wrap_json_get_real_by_path->none~get~2 proc~wrap_json_get_real_vec_by_path->interface~to_unicode proc~wrap_json_get_real_vec_by_path->none~get~2 proc~wrap_json_get_string_by_path->interface~to_unicode proc~wrap_json_get_string_by_path->none~get~2 proc~wrap_json_get_string_vec_by_path->interface~to_unicode proc~wrap_json_get_string_vec_by_path->none~get~2 proc~json_string_info json_core%json_string_info none~string_info->proc~json_string_info proc~json_get_by_path_default->none~throw_exception proc~json_get_by_path_default->proc~json_clear_exceptions proc~json_get_by_path_default->proc~string_to_integer none~add~4 json_core%add proc~json_get_by_path_default->none~add~4 none~get_child json_core%get_child proc~json_get_by_path_default->none~get_child proc~json_value_create json_value_create proc~json_get_by_path_default->proc~json_value_create proc~to_array json_core%to_array proc~json_get_by_path_default->proc~to_array proc~to_null json_core%to_null proc~json_get_by_path_default->proc~to_null proc~to_object json_core%to_object proc~json_get_by_path_default->proc~to_object proc~json_get_by_path_jsonpath_bracket->none~throw_exception proc~json_get_by_path_jsonpath_bracket->proc~json_clear_exceptions proc~json_get_by_path_jsonpath_bracket->proc~string_to_integer proc~json_get_by_path_jsonpath_bracket->none~add~4 proc~json_get_by_path_jsonpath_bracket->none~get_child proc~convert json_core%convert proc~json_get_by_path_jsonpath_bracket->proc~convert proc~json_get_by_path_jsonpath_bracket->proc~json_value_create proc~json_get_by_path_jsonpath_bracket->proc~to_null proc~json_get_by_path_rfc6901->none~throw_exception proc~json_get_by_path_rfc6901->proc~json_clear_exceptions proc~json_get_by_path_rfc6901->proc~string_to_integer proc~json_get_by_path_rfc6901->none~get_child proc~decode_rfc6901 decode_rfc6901 proc~json_get_by_path_rfc6901->proc~decode_rfc6901 proc~json_value_add_string_name_ascii json_core%json_value_add_string_name_ascii none~add~4->proc~json_value_add_string_name_ascii proc~json_value_add_string_val_ascii json_core%json_value_add_string_val_ascii none~add~4->proc~json_value_add_string_val_ascii proc~json_value_add_string_vec_name_ascii json_core%json_value_add_string_vec_name_ascii none~add~4->proc~json_value_add_string_vec_name_ascii proc~json_value_add_string_vec_val_ascii json_core%json_value_add_string_vec_val_ascii none~add~4->proc~json_value_add_string_vec_val_ascii proc~json_value_get_child json_core%json_value_get_child none~get_child->proc~json_value_get_child proc~json_value_get_child_by_index json_core%json_value_get_child_by_index none~get_child->proc~json_value_get_child_by_index proc~json_value_get_child_by_name json_core%json_value_get_child_by_name none~get_child->proc~json_value_get_child_by_name proc~wrap_json_value_get_child_by_name json_core%wrap_json_value_get_child_by_name none~get_child->proc~wrap_json_value_get_child_by_name proc~convert->none~throw_exception proc~convert->none~info~2 none~create_array json_core%create_array proc~convert->none~create_array none~create_null json_core%create_null proc~convert->none~create_null none~create_object json_core%create_object proc~convert->none~create_object proc~json_value_replace json_core%json_value_replace proc~convert->proc~json_value_replace proc~replace_string replace_string proc~decode_rfc6901->proc~replace_string proc~json_string_info->none~throw_exception proc~json_string_info->none~info~2 proc~json_string_info->none~get~2 proc~json_string_info->proc~json_clear_exceptions proc~destroy_json_data destroy_json_data proc~to_array->proc~destroy_json_data proc~to_null->proc~destroy_json_data proc~to_object->proc~destroy_json_data proc~json_value_create_array json_core%json_value_create_array none~create_array->proc~json_value_create_array proc~wrap_json_value_create_array json_core%wrap_json_value_create_array none~create_array->proc~wrap_json_value_create_array proc~json_value_create_null json_core%json_value_create_null none~create_null->proc~json_value_create_null proc~wrap_json_value_create_null json_core%wrap_json_value_create_null none~create_null->proc~wrap_json_value_create_null proc~json_value_create_object json_core%json_value_create_object none~create_object->proc~json_value_create_object proc~wrap_json_value_create_object json_core%wrap_json_value_create_object none~create_object->proc~wrap_json_value_create_object proc~json_value_add_string_name_ascii->interface~to_unicode proc~json_value_add_string_name_ascii->none~add~4 proc~json_value_add_string_val_ascii->interface~to_unicode proc~json_value_add_string_val_ascii->none~add~4 proc~json_value_add_string_vec_name_ascii->interface~to_unicode proc~json_value_add_string_vec_name_ascii->none~add~4 proc~json_value_add_string_vec_val_ascii->interface~to_unicode proc~json_value_add_string_vec_val_ascii->none~add~4 proc~json_value_get_child->none~throw_exception proc~json_value_get_child_by_index->none~throw_exception proc~json_value_get_child_by_index->proc~json_clear_exceptions proc~json_value_get_child_by_name->none~throw_exception proc~json_value_get_child_by_name->proc~json_clear_exceptions proc~name_equal json_core%name_equal proc~json_value_get_child_by_name->proc~name_equal none~insert_after json_core%insert_after proc~json_value_replace->none~insert_after proc~json_value_remove json_core%json_value_remove proc~json_value_replace->proc~json_value_remove proc~wrap_json_value_get_child_by_name->interface~to_unicode proc~wrap_json_value_get_child_by_name->none~get~2 proc~json_value_insert_after json_core%json_value_insert_after none~insert_after->proc~json_value_insert_after proc~json_value_insert_after_child_by_index json_core%json_value_insert_after_child_by_index none~insert_after->proc~json_value_insert_after_child_by_index proc~json_value_create_array->proc~json_value_create proc~json_value_create_array->proc~to_array proc~json_value_create_null->proc~json_value_create proc~json_value_create_null->proc~to_null proc~json_value_create_object->proc~json_value_create proc~json_value_create_object->proc~to_object none~destroy~3 json_core%destroy proc~json_value_remove->none~destroy~3 proc~name_strings_equal json_core%name_strings_equal proc~name_equal->proc~name_strings_equal proc~wrap_json_value_create_array->interface~to_unicode proc~wrap_json_value_create_array->none~create_array proc~wrap_json_value_create_null->interface~to_unicode proc~wrap_json_value_create_null->none~create_null proc~wrap_json_value_create_object->interface~to_unicode proc~wrap_json_value_create_object->none~create_object proc~destroy_json_core json_core%destroy_json_core none~destroy~3->proc~destroy_json_core proc~json_value_destroy json_core%json_value_destroy none~destroy~3->proc~json_value_destroy proc~json_value_insert_after_child_by_index->none~get_child proc~json_value_insert_after_child_by_index->none~insert_after proc~lowercase_string lowercase_string proc~name_strings_equal->proc~lowercase_string proc~json_value_destroy->proc~destroy_json_data proc~json_value_destroy->none~destroy~3

Called by

proc~~json_value_print~~CalledByGraph proc~json_value_print json_core%json_value_print proc~json_value_print->proc~json_value_print proc~json_print_to_unit json_core%json_print_to_unit proc~json_print_to_unit->proc~json_value_print proc~json_value_to_string json_core%json_value_to_string proc~json_value_to_string->proc~json_value_print proc~assign_json_file_to_string json_file%assign_json_file_to_string proc~assign_json_file_to_string->proc~json_value_to_string proc~json_file_print_to_string json_file%json_file_print_to_string proc~json_file_print_to_string->proc~json_value_to_string

Source Code

    recursive subroutine json_value_print(json,p,iunit,str,indent,&
                                          need_comma,colon,is_array_element,&
                                          is_compressed_vector,iloc)

    implicit none

    class(json_core),intent(inout)       :: json
    type(json_value),pointer,intent(in)  :: p
    integer(IK),intent(in)               :: iunit             !! file unit to write to (the
                                                              !! file is assumed to be open)
    integer(IK),intent(in),optional      :: indent            !! indention level
    logical(LK),intent(in),optional      :: is_array_element  !! if this is an array element
    logical(LK),intent(in),optional      :: need_comma        !! if it needs a comma after it
    logical(LK),intent(in),optional      :: colon             !! if the colon was just written
    character(kind=CK,len=:),intent(inout),allocatable :: str
                                                      !! if `iunit==unit2str` (-1) then
                                                      !! the structure is printed to this
                                                      !! string rather than a file. This mode
                                                      !! is used by [[json_value_to_string]].
    integer(IK),intent(inout) :: iloc  !! current index in `str`. should be set to 0 initially.
                                       !! [only used when `str` is used.]
    logical(LK),intent(in),optional :: is_compressed_vector  !! if True, this is an element
                                                             !! from an array being printed
                                                             !! on one line [default is False]

    character(kind=CK,len=max_numeric_str_len) :: tmp !! for value to string conversions
    character(kind=CK,len=:),allocatable :: s_indent !! the string of spaces for
                                                     !! indenting (see `tab` and `spaces`)
    character(kind=CK,len=:),allocatable :: s !! the string appended to `str`
    character(kind=CK,len=:),allocatable :: buf !! temporary buffer for extending `str`
    type(json_value),pointer :: element !! for getting children
    integer(IK) :: tab           !! number of `tabs` for indenting
    integer(IK) :: spaces        !! number of spaces for indenting
    integer(IK) :: i,j           !! counter
    integer(IK) :: count         !! number of children
    logical(LK) :: print_comma   !! if the comma will be printed after the value
    logical(LK) :: write_file    !! if we are writing to a file
    logical(LK) :: write_string  !! if we are writing to a string
    logical(LK) :: is_array      !! if this is an element in an array
    logical(LK) :: is_vector     !! if all elements of a vector
                                 !! are scalars of the same type
    character(kind=CK,len=:),allocatable :: str_escaped !! escaped version of
                                                        !! `name` or `str_value`

    if (.not. json%exception_thrown) then

        if (.not. associated(p)) then
            ! note: a null() pointer will trigger this error.
            ! However, if the pointer is undefined, then this will
            ! crash (if this wasn't here it would crash below when
            ! we try to access the contents)
            call json%throw_exception('Error in json_value_print: '//&
                                      'the pointer is not associated')
            return
        end if

        if (present(is_compressed_vector)) then
            is_vector = is_compressed_vector
        else
            is_vector = .false.
        end if

        !whether to write a string or a file (one or the other):
        write_string = (iunit==unit2str)
        write_file = .not. write_string

        !if the comma will be printed after the value
        ! [comma not printed for the last elements]
        if (present(need_comma)) then
            print_comma = need_comma
        else
            print_comma = .false.
        end if

        !number of "tabs" to indent:
        if (present(indent) .and. .not. json%no_whitespace) then
            tab = indent
        else
            tab = 0
        end if
        !convert to number of spaces:
        spaces = tab*json%spaces_per_tab

        !if this is an element in an array:
        if (present(is_array_element)) then
            is_array = is_array_element
        else
            is_array = .false.
        end if

        !if the colon was the last thing written
        if (present(colon)) then
            s_indent = CK_''
        else
            s_indent = repeat(space, spaces)
        end if

        select case (p%var_type)

        case (json_object)

            count = json%count(p)

            if (count==0) then    !special case for empty object

                s = s_indent//start_object//end_object
                call write_it( comma=print_comma )

            else

                s = s_indent//start_object
                call write_it()

                !if an object is in an array, there is an extra tab:
                if (is_array) then
                    if ( .not. json%no_whitespace) tab = tab+1
                    spaces = tab*json%spaces_per_tab
                end if

                nullify(element)
                element => p%children
                do i = 1, count

                    if (.not. associated(element)) then
                        call json%throw_exception('Error in json_value_print: '//&
                                                  'Malformed JSON linked list')
                        return
                    end if

                    ! print the name
                    if (allocated(element%name)) then
                        call escape_string(element%name,str_escaped,json%escape_solidus)
                        if (json%no_whitespace) then
                            !compact printing - no extra space
                            s = repeat(space, spaces)//quotation_mark//&
                                          str_escaped//quotation_mark//colon_char
                            call write_it(advance=.false.)
                        else
                            s = repeat(space, spaces)//quotation_mark//&
                                          str_escaped//quotation_mark//colon_char//space
                            call write_it(advance=.false.)
                        end if
                    else
                        call json%throw_exception('Error in json_value_print:'//&
                                                  ' element%name not allocated')
                        nullify(element)
                        return
                    end if

                    ! recursive print of the element
                    call json%json_value_print(element, iunit=iunit, indent=tab + 1_IK, &
                                    need_comma=i<count, colon=.true., str=str, iloc=iloc)
                    if (json%exception_thrown) return

                    ! get the next child the list:
                    element => element%next

                end do

                ! [one fewer tab if it isn't an array element]
                if (.not. is_array) then
                    s = repeat(space, max(0_IK,spaces-json%spaces_per_tab))//end_object
                else
                    s = s_indent//end_object
                end if
                call write_it( comma=print_comma )
                nullify(element)

            end if

        case (json_array)

            count = json%count(p)

            if (count==0) then    ! special case for empty array

                s = s_indent//start_array//end_array
                call write_it( comma=print_comma )

            else

                ! if every child is the same type & a scalar:
                is_vector = json%is_vector(p)
                if (json%failed()) return

                s = s_indent//start_array
                call write_it( advance=(.not. is_vector) )

                !if an array is in an array, there is an extra tab:
                if (is_array) then
                    if ( .not. json%no_whitespace) tab = tab+1
                    spaces = tab*json%spaces_per_tab
                end if

                nullify(element)
                element => p%children
                do i = 1, count

                    if (.not. associated(element)) then
                        call json%throw_exception('Error in json_value_print: '//&
                                                  'Malformed JSON linked list')
                        return
                    end if

                    ! recursive print of the element
                    if (is_vector) then
                        call json%json_value_print(element, iunit=iunit, indent=0_IK,&
                                        need_comma=i<count, is_array_element=.false., &
                                        str=str, iloc=iloc,&
                                        is_compressed_vector = .true.)
                    else
                        call json%json_value_print(element, iunit=iunit, indent=tab,&
                                        need_comma=i<count, is_array_element=.true., &
                                        str=str, iloc=iloc)
                    end if
                    if (json%exception_thrown) return

                    ! get the next child the list:
                    element => element%next

                end do

                !indent the closing array character:
                if (is_vector) then
                    s = end_array
                    call write_it( comma=print_comma )
                else
                    s = repeat(space, max(0_IK,spaces-json%spaces_per_tab))//end_array
                    call write_it( comma=print_comma )
                end if
                nullify(element)

            end if

        case (json_null)

            s = s_indent//null_str
            call write_it( comma=print_comma, &
                           advance=(.not. is_vector),&
                           space_after_comma=is_vector )

        case (json_string)

            if (allocated(p%str_value)) then
                ! have to escape the string for printing:
                call escape_string(p%str_value,str_escaped,json%escape_solidus)
                s = s_indent//quotation_mark//str_escaped//quotation_mark
                call write_it( comma=print_comma, &
                               advance=(.not. is_vector),&
                               space_after_comma=is_vector )
            else
                call json%throw_exception('Error in json_value_print:'//&
                                          ' p%value_string not allocated')
                return
            end if

        case (json_logical)

            if (p%log_value) then
                s = s_indent//true_str
                call write_it( comma=print_comma, &
                               advance=(.not. is_vector),&
                               space_after_comma=is_vector )
            else
                s = s_indent//false_str
                call write_it( comma=print_comma, &
                               advance=(.not. is_vector),&
                               space_after_comma=is_vector )
            end if

        case (json_integer)

            call integer_to_string(p%int_value,int_fmt,tmp)

            s = s_indent//trim(tmp)
            call write_it( comma=print_comma, &
                           advance=(.not. is_vector),&
                           space_after_comma=is_vector )

        case (json_real)

            if (allocated(json%real_fmt)) then
                call real_to_string(p%dbl_value,json%real_fmt,json%compact_real,json%non_normals_to_null,tmp)
            else
                !use the default format (user has not called initialize() or specified one):
                call real_to_string(p%dbl_value,default_real_fmt,json%compact_real,json%non_normals_to_null,tmp)
            end if

            s = s_indent//trim(tmp)
            call write_it( comma=print_comma, &
                           advance=(.not. is_vector),&
                           space_after_comma=is_vector )

        case default

            call integer_to_string(p%var_type,int_fmt,tmp)
            call json%throw_exception('Error in json_value_print: '//&
                                      'unknown data type: '//trim(tmp))

        end select

    end if

    contains

        subroutine write_it(advance,comma,space_after_comma)

        !! write the string `s` to the file (or the output string)

        implicit none

        logical(LK),intent(in),optional :: advance           !! to add line break or not
        logical(LK),intent(in),optional :: comma             !! print comma after the string
        logical(LK),intent(in),optional :: space_after_comma !! print a space after the comma

        logical(LK) :: add_comma       !! if a delimiter is to be added after string
        logical(LK) :: add_line_break  !! if a line break is to be added after string
        logical(LK) :: add_space       !! if a space is to be added after the comma
        integer(IK) :: n               !! length of actual string `s` appended to `str`
        integer(IK) :: room_left       !! number of characters left in `str`
        integer(IK) :: n_chunks_to_add !! number of chunks to add to `str` for appending `s`

        if (present(comma)) then
            add_comma = comma
        else
            add_comma = .false. !default is not to add comma
        end if
        if (json%no_whitespace) then
            add_space = .false.
        else
            if (present(space_after_comma)) then
                add_space = space_after_comma
            else
                add_space = .false. !default is not to add space
            end if
        end if
        if (present(advance)) then
            if (json%no_whitespace) then
                ! overrides input value:
                add_line_break = .false.
            else
                add_line_break = advance
            end if
        else
            add_line_break = .not. json%no_whitespace ! default is to advance if
                                                      ! we are printing whitespace
        end if

        ! string to print:
        if (add_comma) then
            if (add_space) then
                s = s // delimiter // space
            else
                s = s // delimiter
            end if
        end if

        if (write_file) then

            if (add_line_break) then
                write(iunit,fmt='(A)') s
            else
                write(iunit,fmt='(A)',advance='NO') s
            end if

        else    !write string

            if (add_line_break) s = s // newline

            n = len(s)
            room_left = len(str)-iloc
            if (room_left < n) then
                ! need to add another chunk to fit this string:
                n_chunks_to_add = max(1_IK, ceiling( real(len(s)-room_left,RK) / real(chunk_size,RK), IK ) )
                allocate(character(kind=CK, len=len(str)+print_str_chunk_size*n_chunks_to_add)::buf)
                buf(1:len(str)) = str
                do j = len(str)+1, len(buf)
                    buf(j:j) = space
                enddo
                call move_alloc(buf, str)
            end if
            ! append s to str:
            str(iloc+1:iloc+n) = s
            iloc = iloc + n

        end if

        end subroutine write_it

    end subroutine json_value_print