@@ -186,25 +186,25 @@ module json_value_module
186
186
! ! type is different from the return type (for
187
187
! ! example, integer to double).
188
188
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.
191
191
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.
194
194
195
195
logical (LK) :: no_whitespace = .false. ! ! when printing a JSON string, don't include
196
196
! ! non-significant spaces or line breaks.
197
197
! ! If true, the entire structure will be
198
198
! ! printed on one line.
199
199
200
- logical (LK) :: unescaped_strings = .true. ! ! If false, then the raw escaped
200
+ logical (LK) :: unescaped_strings = .true. ! ! If false, then the escaped
201
201
! ! string is returned from [[json_get_string]]
202
202
! ! and similar routines. If true [default],
203
203
! ! then the string is returned unescaped.
204
204
205
205
logical (LK) :: allow_comments = .true. ! ! if true, any comments will be ignored when
206
206
! ! parsing a file. The comment token is defined
207
- ! ! by the `comment_char` string .
207
+ ! ! by the `comment_char` character variable .
208
208
character (kind= CK,len= 1 ) :: comment_char = CK_' !' ! ! comment token when
209
209
! ! `allow_comments` is true.
210
210
! ! Examples: '`!`' or '`#`'.
@@ -215,6 +215,8 @@ module json_value_module
215
215
! ! * 1 -- Default mode (see [[json_get_by_path_default]])
216
216
! ! * 2 -- as RFC 6901 "JSON Pointer" paths
217
217
! ! (see [[json_get_by_path_rfc6901]])
218
+ ! ! * 3 -- JSONPath "bracket-notation" (currently only
219
+ ! ! used in [[json_get_path]])
218
220
219
221
character (kind= CK,len= 1 ) :: path_separator = dot ! ! The `path` separator to use
220
222
! ! in the "default" mode for
@@ -888,7 +890,7 @@ subroutine json_initialize(me,verbose,compact_reals,&
888
890
if (present (unescape_strings)) &
889
891
me% unescaped_strings = unescape_strings
890
892
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
892
894
me% path_mode = path_mode
893
895
else
894
896
me% path_mode = 1_IK ! just to have a valid value
@@ -5512,6 +5514,9 @@ end subroutine json_value_print
5512
5514
!
5513
5515
! * The original JSON-Fortran defaults
5514
5516
! * [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.
5515
5520
5516
5521
subroutine json_get_by_path (json , me , path , p , found )
5517
5522
@@ -5524,16 +5529,24 @@ subroutine json_get_by_path(json, me, path, p, found)
5524
5529
! ! specify by `path`
5525
5530
logical (LK),intent (out ),optional :: found ! ! true if it was found
5526
5531
5532
+ character (kind= CK,len= max_integer_str_len),allocatable :: path_mode_str ! ! string version
5533
+ ! ! of `json%path_mode`
5534
+
5527
5535
nullify(p)
5528
5536
5529
5537
if (.not. json% exception_thrown) then
5530
5538
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 )
5532
5540
select case (json% path_mode)
5533
5541
case (1_IK )
5534
5542
call json% json_get_by_path_default(me, path, p, found)
5535
5543
case (2_IK )
5536
5544
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.
5537
5550
end select
5538
5551
5539
5552
else
@@ -5572,6 +5585,8 @@ subroutine json_create_by_path(json,me,path,p,found,was_created)
5572
5585
! ! (as opposed to already being there)
5573
5586
5574
5587
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`
5575
5590
5576
5591
if (present (p)) nullify(p)
5577
5592
@@ -5587,7 +5602,17 @@ subroutine json_create_by_path(json,me,path,p,found,was_created)
5587
5602
case (2_IK )
5588
5603
! the problem here is there isn't really a way to disambiguate
5589
5604
! 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))
5591
5616
if (present (found)) then
5592
5617
call json% clear_exceptions()
5593
5618
found = .false.
@@ -5640,6 +5665,8 @@ end subroutine wrap_json_create_by_path
5640
5665
! ````
5641
5666
!
5642
5667
! ### Notes
5668
+ ! The syntax used here is a subset of the
5669
+ ! [http://goessner.net/articles/JsonPath/](JSONPath) "dot–notation".
5643
5670
! The following special characters are used to denote paths:
5644
5671
!
5645
5672
! * `$` - root
@@ -5997,6 +6024,9 @@ end subroutine json_get_by_path_default
5997
6024
! (according to the standard, evaluation of non-unique references
5998
6025
! should fail). Like [[json_get_by_path_default]], this one will just return
5999
6026
! 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).
6000
6030
6001
6031
subroutine json_get_by_path_rfc6901 (json , me , path , p , found )
6002
6032
@@ -6194,6 +6224,12 @@ end subroutine wrap_json_get_by_path
6194
6224
!
6195
6225
! @note If `json%path_mode/=1`, then the `use_alt_array_tokens`
6196
6226
! 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`
6197
6233
6198
6234
subroutine json_get_path (json , p , path , found , use_alt_array_tokens , path_sep )
6199
6235
@@ -6205,15 +6241,18 @@ subroutine json_get_path(json, p, path, found, use_alt_array_tokens, path_sep)
6205
6241
logical (LK),intent (out ),optional :: found ! ! true if there were no problems
6206
6242
logical (LK),intent (in ),optional :: use_alt_array_tokens ! ! if true, then '()' are used for array elements
6207
6243
! ! otherwise, '[]' are used [default]
6244
+ ! ! (only used if `path_mode=1`)
6208
6245
character (kind= CK,len= 1 ),intent (in ),optional :: path_sep ! ! character to use for path separator
6209
6246
! ! (otherwise use `json%path_separator`)
6247
+ ! ! (only used if `path_mode=1`)
6210
6248
6211
6249
type (json_value),pointer :: tmp ! ! for traversing the structure
6212
6250
type (json_value),pointer :: element ! ! for traversing the structure
6213
6251
integer (IK) :: var_type ! ! JSON variable type flag
6214
6252
character (kind= CK,len= :),allocatable :: name ! ! variable name
6215
6253
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)
6217
6256
integer (IK) :: i ! ! counter
6218
6257
integer (IK) :: n_children ! ! number of children for parent
6219
6258
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)
6273
6312
end if
6274
6313
end do
6275
6314
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_' ' )
6276
6323
case (2 )
6324
+ ! rfc6901
6277
6325
call integer_to_string(i-1 ,int_fmt,istr) ! 0-based index
6278
6326
call add_to_path(parent_name// slash// trim (adjustl (istr)))
6279
6327
case (1 )
6328
+ ! default
6280
6329
call integer_to_string(i,int_fmt,istr)
6281
6330
if (use_brackets) then
6282
6331
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)
6291
6340
case (json_object)
6292
6341
6293
6342
! 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
6295
6350
6296
6351
case default
6297
6352
@@ -6305,7 +6360,13 @@ subroutine json_get_path(json, p, path, found, use_alt_array_tokens, path_sep)
6305
6360
6306
6361
else
6307
6362
! 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
6309
6370
end if
6310
6371
6311
6372
if (associated (tmp% parent)) then
@@ -6328,10 +6389,14 @@ subroutine json_get_path(json, p, path, found, use_alt_array_tokens, path_sep)
6328
6389
if (json% exception_thrown .or. .not. allocated (path)) then
6329
6390
path = CK_' '
6330
6391
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 )
6332
6397
! add the root slash:
6333
6398
path = slash// path
6334
- end if
6399
+ end select
6335
6400
end if
6336
6401
6337
6402
! optional output:
@@ -6355,6 +6420,13 @@ subroutine add_to_path(str,path_sep)
6355
6420
! ! (ignored if `json%path_mode/=1`)
6356
6421
6357
6422
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
6358
6430
case (2 )
6359
6431
! in this case, the options are ignored
6360
6432
if (.not. allocated (path)) then
0 commit comments