@@ -186,25 +186,25 @@ module json_value_module
186186 ! ! type is different from the return type (for
187187 ! ! example, integer to double).
188188
189- logical (LK) :: trailing_spaces_significant = .false. ! ! for name and path comparisons, is trailing
190- ! ! space to be considered significant.
189+ logical (LK) :: trailing_spaces_significant = .false. ! ! for name and path comparisons, if trailing
190+ ! ! space is to be considered significant.
191191
192- logical (LK) :: case_sensitive_keys = .true. ! ! for name and path comparisons, are they
193- ! ! case sensitive.
192+ logical (LK) :: case_sensitive_keys = .true. ! ! if name and path comparisons
193+ ! ! are case sensitive.
194194
195195 logical (LK) :: no_whitespace = .false. ! ! when printing a JSON string, don't include
196196 ! ! non-significant spaces or line breaks.
197197 ! ! If true, the entire structure will be
198198 ! ! printed on one line.
199199
200- logical (LK) :: unescaped_strings = .true. ! ! If false, then the raw escaped
200+ logical (LK) :: unescaped_strings = .true. ! ! If false, then the escaped
201201 ! ! string is returned from [[json_get_string]]
202202 ! ! and similar routines. If true [default],
203203 ! ! then the string is returned unescaped.
204204
205205 logical (LK) :: allow_comments = .true. ! ! if true, any comments will be ignored when
206206 ! ! parsing a file. The comment token is defined
207- ! ! by the `comment_char` string .
207+ ! ! by the `comment_char` character variable .
208208 character (kind= CK,len= 1 ) :: comment_char = CK_' !' ! ! comment token when
209209 ! ! `allow_comments` is true.
210210 ! ! Examples: '`!`' or '`#`'.
@@ -215,6 +215,8 @@ module json_value_module
215215 ! ! * 1 -- Default mode (see [[json_get_by_path_default]])
216216 ! ! * 2 -- as RFC 6901 "JSON Pointer" paths
217217 ! ! (see [[json_get_by_path_rfc6901]])
218+ ! ! * 3 -- JSONPath "bracket-notation" (currently only
219+ ! ! used in [[json_get_path]])
218220
219221 character (kind= CK,len= 1 ) :: path_separator = dot ! ! The `path` separator to use
220222 ! ! in the "default" mode for
@@ -888,7 +890,7 @@ subroutine json_initialize(me,verbose,compact_reals,&
888890 if (present (unescape_strings)) &
889891 me% unescaped_strings = unescape_strings
890892 if (present (path_mode)) then
891- if (path_mode== 1_IK .or. path_mode== 2_IK ) then
893+ if (path_mode== 1_IK .or. path_mode== 2_IK .or. path_mode == 3_IK ) then
892894 me% path_mode = path_mode
893895 else
894896 me% path_mode = 1_IK ! just to have a valid value
@@ -5512,6 +5514,9 @@ end subroutine json_value_print
55125514!
55135515! * The original JSON-Fortran defaults
55145516! * [RFC 6901](https://tools.ietf.org/html/rfc6901)
5517+ !
5518+ ! @warning if `found` is present, we should clear any exceptions that are thrown
5519+ ! to be consistent with other routines. This is not currently being done.
55155520
55165521 subroutine json_get_by_path (json , me , path , p , found )
55175522
@@ -5524,16 +5529,24 @@ subroutine json_get_by_path(json, me, path, p, found)
55245529 ! ! specify by `path`
55255530 logical (LK),intent (out ),optional :: found ! ! true if it was found
55265531
5532+ character (kind= CK,len= max_integer_str_len),allocatable :: path_mode_str ! ! string version
5533+ ! ! of `json%path_mode`
5534+
55275535 nullify(p)
55285536
55295537 if (.not. json% exception_thrown) then
55305538
5531- ! note: it can only be 1 or 2 (which was checked in initialize )
5539+ ! note: it can only be 1 or 2 (3 not currently enabled )
55325540 select case (json% path_mode)
55335541 case (1_IK )
55345542 call json% json_get_by_path_default(me, path, p, found)
55355543 case (2_IK )
55365544 call json% json_get_by_path_rfc6901(me, path, p, found)
5545+ case default
5546+ call integer_to_string(json% path_mode,int_fmt,path_mode_str)
5547+ call json% throw_exception(' Error in json_get_by_path: Unsupported path_mode: ' // &
5548+ trim (path_mode_str))
5549+ if (present (found)) found = .false.
55375550 end select
55385551
55395552 else
@@ -5572,6 +5585,8 @@ subroutine json_create_by_path(json,me,path,p,found,was_created)
55725585 ! ! (as opposed to already being there)
55735586
55745587 type (json_value),pointer :: tmp
5588+ character (kind= CK,len= max_integer_str_len),allocatable :: path_mode_str ! ! string version
5589+ ! ! of `json%path_mode`
55755590
55765591 if (present (p)) nullify(p)
55775592
@@ -5587,7 +5602,17 @@ subroutine json_create_by_path(json,me,path,p,found,was_created)
55875602 case (2_IK )
55885603 ! the problem here is there isn't really a way to disambiguate
55895604 ! the array elements, so '/a/0' could be 'a(1)' or 'a.0'.
5590- call json% throw_exception(' Create by path not supported in RFC 6901 path mode.' )
5605+ call json% throw_exception(' Error in json_create_by_path: ' // &
5606+ ' Create by path not supported in RFC 6901 path mode.' )
5607+ if (present (found)) then
5608+ call json% clear_exceptions()
5609+ found = .false.
5610+ end if
5611+ if (present (was_created)) was_created = .false.
5612+ case default
5613+ call integer_to_string(json% path_mode,int_fmt,path_mode_str)
5614+ call json% throw_exception(' Error in json_create_by_path: Unsupported path_mode: ' // &
5615+ trim (path_mode_str))
55915616 if (present (found)) then
55925617 call json% clear_exceptions()
55935618 found = .false.
@@ -5640,6 +5665,8 @@ end subroutine wrap_json_create_by_path
56405665! ````
56415666!
56425667! ### Notes
5668+ ! The syntax used here is a subset of the
5669+ ! [http://goessner.net/articles/JsonPath/](JSONPath) "dot–notation".
56435670! The following special characters are used to denote paths:
56445671!
56455672! * `$` - root
@@ -5997,6 +6024,9 @@ end subroutine json_get_by_path_default
59976024! (according to the standard, evaluation of non-unique references
59986025! should fail). Like [[json_get_by_path_default]], this one will just return
59996026! the first instance it encounters. This might be changed in the future.
6027+ !
6028+ ! @warning I think the standard indicates that the input paths should use
6029+ ! escaped JSON strings (currently we are assuming they are not escaped).
60006030
60016031 subroutine json_get_by_path_rfc6901 (json , me , path , p , found )
60026032
@@ -6194,6 +6224,12 @@ end subroutine wrap_json_get_by_path
61946224!
61956225! @note If `json%path_mode/=1`, then the `use_alt_array_tokens`
61966226! and `path_sep` inputs are ignored if present.
6227+ !
6228+ ! @note [http://goessner.net/articles/JsonPath/](JSONPath) (`path_mode=3`)
6229+ ! does not specify whether or not the keys should be escaped (this routine
6230+ ! assumes not, as does http://jsonpath.com).
6231+ ! Also, we are using Fortran-style 1-based array indices,
6232+ ! not 0-based, to agree with the assumption in `path_mode=1`
61976233
61986234 subroutine json_get_path (json , p , path , found , use_alt_array_tokens , path_sep )
61996235
@@ -6205,15 +6241,18 @@ subroutine json_get_path(json, p, path, found, use_alt_array_tokens, path_sep)
62056241 logical (LK),intent (out ),optional :: found ! ! true if there were no problems
62066242 logical (LK),intent (in ),optional :: use_alt_array_tokens ! ! if true, then '()' are used for array elements
62076243 ! ! otherwise, '[]' are used [default]
6244+ ! ! (only used if `path_mode=1`)
62086245 character (kind= CK,len= 1 ),intent (in ),optional :: path_sep ! ! character to use for path separator
62096246 ! ! (otherwise use `json%path_separator`)
6247+ ! ! (only used if `path_mode=1`)
62106248
62116249 type (json_value),pointer :: tmp ! ! for traversing the structure
62126250 type (json_value),pointer :: element ! ! for traversing the structure
62136251 integer (IK) :: var_type ! ! JSON variable type flag
62146252 character (kind= CK,len= :),allocatable :: name ! ! variable name
62156253 character (kind= CK,len= :),allocatable :: parent_name ! ! variable's parent name
6216- character (kind= CK,len= max_integer_str_len) :: istr ! ! for integer to string conversion (array indices)
6254+ character (kind= CK,len= max_integer_str_len) :: istr ! ! for integer to string conversion
6255+ ! ! (array indices)
62176256 integer (IK) :: i ! ! counter
62186257 integer (IK) :: n_children ! ! number of children for parent
62196258 logical (LK) :: use_brackets ! ! to use '[]' characters for arrays
@@ -6273,10 +6312,20 @@ subroutine json_get_path(json, p, path, found, use_alt_array_tokens, path_sep)
62736312 end if
62746313 end do
62756314 select case (json% path_mode)
6315+ case (3 )
6316+ ! JSONPath "bracket-notation"
6317+ ! example: `$['key'][1]`
6318+ ! [note: this uses 1-based indices]
6319+ call integer_to_string(i,int_fmt,istr)
6320+ call add_to_path(start_array// single_quote// parent_name// &
6321+ single_quote// end_array// &
6322+ start_array// trim (adjustl (istr))// end_array,CK_' ' )
62766323 case (2 )
6324+ ! rfc6901
62776325 call integer_to_string(i-1 ,int_fmt,istr) ! 0-based index
62786326 call add_to_path(parent_name// slash// trim (adjustl (istr)))
62796327 case (1 )
6328+ ! default
62806329 call integer_to_string(i,int_fmt,istr)
62816330 if (use_brackets) then
62826331 call add_to_path(parent_name// start_array// &
@@ -6291,7 +6340,13 @@ subroutine json_get_path(json, p, path, found, use_alt_array_tokens, path_sep)
62916340 case (json_object)
62926341
62936342 ! process parent on the next pass
6294- call add_to_path(name,path_sep)
6343+ select case (json% path_mode)
6344+ case (3 )
6345+ call add_to_path(start_array// single_quote// name// &
6346+ single_quote// end_array,CK_' ' )
6347+ case default
6348+ call add_to_path(name,path_sep)
6349+ end select
62956350
62966351 case default
62976352
@@ -6305,7 +6360,13 @@ subroutine json_get_path(json, p, path, found, use_alt_array_tokens, path_sep)
63056360
63066361 else
63076362 ! the last one:
6308- call add_to_path(name,path_sep)
6363+ select case (json% path_mode)
6364+ case (3 )
6365+ call add_to_path(start_array// single_quote// name// &
6366+ single_quote// end_array,CK_' ' )
6367+ case default
6368+ call add_to_path(name,path_sep)
6369+ end select
63096370 end if
63106371
63116372 if (associated (tmp% parent)) then
@@ -6328,10 +6389,14 @@ subroutine json_get_path(json, p, path, found, use_alt_array_tokens, path_sep)
63286389 if (json% exception_thrown .or. .not. allocated (path)) then
63296390 path = CK_' '
63306391 else
6331- if (json% path_mode== 2 ) then
6392+ select case (json% path_mode)
6393+ case (3 )
6394+ ! add the outer level object identifier:
6395+ path = root// path
6396+ case (2 )
63326397 ! add the root slash:
63336398 path = slash// path
6334- end if
6399+ end select
63356400 end if
63366401
63376402 ! optional output:
@@ -6355,6 +6420,13 @@ subroutine add_to_path(str,path_sep)
63556420 ! ! (ignored if `json%path_mode/=1`)
63566421
63576422 select case (json% path_mode)
6423+ case (3 )
6424+ ! in this case, the options are ignored
6425+ if (.not. allocated (path)) then
6426+ path = str
6427+ else
6428+ path = str// path
6429+ end if
63586430 case (2 )
63596431 ! in this case, the options are ignored
63606432 if (.not. allocated (path)) then
0 commit comments