@@ -510,6 +510,11 @@ module json_value_module
510
510
procedure :: json_value_insert_after
511
511
procedure :: json_value_insert_after_child_by_index
512
512
513
+ ! >
514
+ ! get the path to a JSON variable in a structure:
515
+ generic,public :: get_path = > MAYBEWRAP(json_get_path)
516
+ procedure :: MAYBEWRAP(json_get_path)
517
+
513
518
procedure ,public :: remove = > json_value_remove ! ! Remove a [[json_value]] from a linked-list structure.
514
519
procedure ,public :: check_for_errors = > json_check_for_errors ! ! check for error and get error message
515
520
procedure ,public :: clear_exceptions = > json_clear_exceptions ! ! clear exceptions
@@ -4031,6 +4036,201 @@ subroutine wrap_json_get_by_path(json, me, path, p, found)
4031
4036
end subroutine wrap_json_get_by_path
4032
4037
! *****************************************************************************************
4033
4038
4039
+ ! *****************************************************************************************
4040
+ ! >
4041
+ ! Returns the path to a JSON object that is part
4042
+ ! of a linked list structure.
4043
+ !
4044
+ ! The path returned would be suitable for input to
4045
+ ! [[json_get_by_path]] and related routines.
4046
+ !
4047
+ ! @note If an error occurs (which in this case means a malformed
4048
+ ! JSON structure) then an exception will be thrown, unless
4049
+ ! `found` is present, which will be set to `false`. `path`
4050
+ ! will be a blank string.
4051
+
4052
+ subroutine json_get_path (json , p , path , found , use_alt_array_tokens , path_sep )
4053
+
4054
+ implicit none
4055
+
4056
+ class(json_core),intent (inout ) :: json
4057
+ type (json_value),pointer ,intent (in ) :: p ! ! a JSON linked list object
4058
+ character (kind= CK,len= :),allocatable ,intent (out ) :: path ! ! path to the variable
4059
+ logical (LK),intent (out ),optional :: found ! ! true if there were no problems
4060
+ logical (LK),intent (in ),optional :: use_alt_array_tokens ! ! if true, then '()' are used for array elements
4061
+ ! ! otherwise, '[]' are used [default]
4062
+ character (kind= CK,len= 1 ),intent (in ),optional :: path_sep ! ! character to use for path separator
4063
+ ! ! (default is '.')
4064
+
4065
+ type (json_value),pointer :: tmp ! ! for traversing the structure
4066
+ type (json_value),pointer :: element ! ! for traversing the structure
4067
+ integer (IK) :: var_type ! ! JSON variable type flag
4068
+ character (kind= CK,len= :),allocatable :: name ! ! variable name
4069
+ character (kind= CK,len= :),allocatable :: parent_name ! ! variable's parent name
4070
+ character (kind= CK,len= max_integer_str_len) :: istr ! ! for integer to string conversion (array indices)
4071
+ integer (IK) :: i ! ! counter
4072
+ integer (IK) :: n_children ! ! number of children for parent
4073
+ logical (LK) :: use_brackets ! ! to use '[]' characters for arrays
4074
+ logical (LK) :: parent_is_root ! ! if the parent is the root
4075
+
4076
+ ! initialize:
4077
+ path = ' '
4078
+
4079
+ ! optional input:
4080
+ if (present (use_alt_array_tokens)) then
4081
+ use_brackets = .not. use_alt_array_tokens
4082
+ else
4083
+ use_brackets = .true.
4084
+ end if
4085
+
4086
+ if (associated (p)) then
4087
+
4088
+ ! traverse the structure via parents up to the root
4089
+ tmp = > p
4090
+ do
4091
+
4092
+ if (.not. associated (tmp)) exit ! finished
4093
+
4094
+ ! get info about the current variable:
4095
+ call json% info(tmp,name= name)
4096
+
4097
+ ! if tmp a child of an object, or an element of an array
4098
+ if (associated (tmp% parent)) then
4099
+
4100
+ ! get info about the parent:
4101
+ call json% info(tmp% parent,var_type= var_type,&
4102
+ n_children= n_children,name= parent_name)
4103
+
4104
+ select case (var_type)
4105
+ case (json_array)
4106
+
4107
+ ! get array index of this element:
4108
+ element = > tmp% parent% children
4109
+ do i = 1 , n_children
4110
+ if (.not. associated (element)) then
4111
+ call json% throw_exception(' Error in json_get_path: ' // &
4112
+ ' malformed JSON structure. ' )
4113
+ exit
4114
+ end if
4115
+ if (associated (element,tmp)) then
4116
+ exit
4117
+ else
4118
+ element = > element% next
4119
+ end if
4120
+ if (i== n_children) then ! it wasn't found (should never happen)
4121
+ call json% throw_exception(' Error in json_get_path: ' // &
4122
+ ' malformed JSON structure. ' )
4123
+ exit
4124
+ end if
4125
+ end do
4126
+ call integer_to_string(i,int_fmt,istr)
4127
+ if (use_brackets) then
4128
+ call add_to_path(parent_name// start_array// &
4129
+ trim (adjustl (istr))// end_array,path_sep)
4130
+ else
4131
+ call add_to_path(parent_name// start_array_alt// &
4132
+ trim (adjustl (istr))// end_array_alt,path_sep)
4133
+ end if
4134
+ tmp = > tmp% parent ! already added parent name
4135
+
4136
+ case (json_object)
4137
+
4138
+ ! process parent on the next pass
4139
+ call add_to_path(name,path_sep)
4140
+
4141
+ case default
4142
+
4143
+ call json% throw_exception(' Error in json_get_path: ' // &
4144
+ ' malformed JSON structure. ' // &
4145
+ ' A variable that is not an object ' // &
4146
+ ' or array should not have a child.' )
4147
+ exit
4148
+
4149
+ end select
4150
+
4151
+ else
4152
+ ! the last one:
4153
+ call add_to_path(name,path_sep)
4154
+ end if
4155
+
4156
+ if (associated (tmp% parent)) then
4157
+ ! check if the parent is the root:
4158
+ parent_is_root = (.not. associated (tmp% parent% parent))
4159
+ if (parent_is_root) exit
4160
+ end if
4161
+
4162
+ ! go to parent:
4163
+ tmp = > tmp% parent
4164
+
4165
+ end do
4166
+
4167
+ else
4168
+ call json% throw_exception(' Error in json_get_path: ' // &
4169
+ ' input pointer is not associated' )
4170
+ end if
4171
+
4172
+ ! for errors, return blank string:
4173
+ if (json% exception_thrown) path = ' '
4174
+
4175
+ ! optional output:
4176
+ if (present (found)) then
4177
+ if (json% exception_thrown) then
4178
+ found = .false.
4179
+ call json% clear_exceptions()
4180
+ else
4181
+ found = .true.
4182
+ end if
4183
+ end if
4184
+
4185
+ contains
4186
+
4187
+ subroutine add_to_path (str ,dot )
4188
+ ! ! prepend the string to the path
4189
+ implicit none
4190
+ character (kind= CK,len=* ),intent (in ) :: str ! ! string to prepend to `path`
4191
+ character (kind= CK,len= 1 ),intent (in ),optional :: dot ! ! path separator (default is '.')
4192
+ if (path==' ' ) then
4193
+ path = str
4194
+ else
4195
+ if (present (dot)) then
4196
+ path = str// dot// path
4197
+ else
4198
+ path = str// child// path
4199
+ end if
4200
+ end if
4201
+ end subroutine add_to_path
4202
+
4203
+ end subroutine json_get_path
4204
+ ! *****************************************************************************************
4205
+
4206
+ ! *****************************************************************************************
4207
+ ! >
4208
+ ! Wrapper for [[json_get_path]] where "path" and "path_sep" are kind=CDK.
4209
+
4210
+ subroutine wrap_json_get_path (json , p , path , found , use_alt_array_tokens , path_sep )
4211
+
4212
+ implicit none
4213
+
4214
+ class(json_core),intent (inout ) :: json
4215
+ type (json_value),pointer ,intent (in ) :: p ! ! a JSON linked list object
4216
+ character (kind= CDK,len= :),allocatable ,intent (out ) :: path ! ! path to the variable
4217
+ logical (LK),intent (out ),optional :: found ! ! true if there were no problems
4218
+ logical (LK),intent (in ),optional :: use_alt_array_tokens ! ! if true, then '()' are used for array elements
4219
+ ! ! otherwise, '[]' are used [default]
4220
+ character (kind= CDK,len= 1 ),intent (in ),optional :: path_sep ! ! character to use for path separator
4221
+ ! ! (default is '.')
4222
+
4223
+ character (kind= CK,len= :),allocatable :: ck_path ! ! path to the variable
4224
+
4225
+ ! call the main routine:
4226
+ call json_get_path(json,p,ck_path,found,use_alt_array_tokens,path_sep)
4227
+
4228
+ ! from unicode:
4229
+ path = ck_path
4230
+
4231
+ end subroutine wrap_json_get_path
4232
+ ! *****************************************************************************************
4233
+
4034
4234
! *****************************************************************************************
4035
4235
! >
4036
4236
! Convert a string into an integer.
0 commit comments