Skip to content

Commit e6ab0ac

Browse files
Merge pull request #319 from jacobwilliams/verify-path
Added routines to verify a path
2 parents 1129010 + 0cb151c commit e6ab0ac

File tree

3 files changed

+200
-3
lines changed

3 files changed

+200
-3
lines changed

src/json_file_module.F90

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ module json_file_module
101101
json_file_rename_name_ascii
102102
#endif
103103

104+
!>
105+
! Verify that a path is valid
106+
! (i.e., a variable with this path exists in the file).
107+
generic,public :: valid_path => MAYBEWRAP(json_file_valid_path)
108+
104109
!>
105110
! Get a variable from a [[json_file(type)]], by specifying the path.
106111
generic,public :: get => MAYBEWRAP(json_file_get_object), &
@@ -167,6 +172,13 @@ module json_file_module
167172
!traverse
168173
procedure,public :: traverse => json_file_traverse
169174

175+
! ***************************************************
176+
! operators
177+
! ***************************************************
178+
179+
generic,public :: operator(.in.) => MAYBEWRAP(json_file_valid_path_op)
180+
procedure,pass(me) :: MAYBEWRAP(json_file_valid_path_op)
181+
170182
! ***************************************************
171183
! private routines
172184
! ***************************************************
@@ -189,6 +201,9 @@ module json_file_module
189201
procedure :: json_file_rename_name_ascii
190202
#endif
191203

204+
!validate path:
205+
procedure :: MAYBEWRAP(json_file_valid_path)
206+
192207
!get:
193208
procedure :: MAYBEWRAP(json_file_get_object)
194209
procedure :: MAYBEWRAP(json_file_get_integer)
@@ -866,6 +881,92 @@ subroutine json_file_get_root(me,p)
866881
end subroutine json_file_get_root
867882
!*****************************************************************************************
868883

884+
!*****************************************************************************************
885+
!> author: Jacob Williams
886+
!
887+
! A wrapper for [[json_file_valid_path]] for the `.in.` operator
888+
889+
function json_file_valid_path_op(path,me) result(found)
890+
891+
implicit none
892+
893+
character(kind=CK,len=*),intent(in) :: path !! the path to the variable
894+
class(json_file),intent(in) :: me !! the JSON file
895+
logical(LK) :: found !! if the variable was found
896+
897+
type(json_core) :: core_copy !! a copy of `core` from `me`
898+
899+
! This is sort of a hack. Since `me` has to have `intent(in)`
900+
! for the operator to work, we need to make a copy of `me%core`
901+
! so we can call the low level routine (since it needs it to
902+
! be `intent(inout)`) because it's technically possible for this
903+
! function to raise an exception. This normally should never
904+
! happen here unless the JSON structure is malformed.
905+
906+
core_copy = me%core ! copy the settings (need them to know
907+
! how to interpret the path)
908+
909+
found = core_copy%valid_path(me%p, path) ! call the low-level routine
910+
911+
call core_copy%destroy() ! just in case (but not really necessary)
912+
913+
end function json_file_valid_path_op
914+
!*****************************************************************************************
915+
916+
!*****************************************************************************************
917+
!> author: Jacob Williams
918+
!
919+
! Alternate version of [[json_file_valid_path_op]], where "path" is kind=CDK.
920+
921+
function wrap_json_file_valid_path_op(path,me) result(found)
922+
923+
implicit none
924+
925+
character(kind=CDK,len=*),intent(in) :: path !! the path to the variable
926+
class(json_file),intent(in) :: me !! the JSON file
927+
logical(LK) :: found !! if the variable was found
928+
929+
found = to_unicode(path) .in. me
930+
931+
end function wrap_json_file_valid_path_op
932+
!*****************************************************************************************
933+
934+
!*****************************************************************************************
935+
!> author: Jacob Williams
936+
!
937+
! Returns true if the `path` is present in the JSON file.
938+
939+
function json_file_valid_path(me,path) result(found)
940+
941+
implicit none
942+
943+
class(json_file),intent(inout) :: me
944+
character(kind=CK,len=*),intent(in) :: path !! the path to the variable
945+
logical(LK) :: found !! if the variable was found
946+
947+
found = me%core%valid_path(me%p, path)
948+
949+
end function json_file_valid_path
950+
!*****************************************************************************************
951+
952+
!*****************************************************************************************
953+
!> author: Jacob Williams
954+
!
955+
! Alternate version of [[json_file_valid_path]], where "path" is kind=CDK.
956+
957+
function wrap_json_file_valid_path(me,path) result(found)
958+
959+
implicit none
960+
961+
class(json_file),intent(inout) :: me
962+
character(kind=CDK,len=*),intent(in) :: path !! the path to the variable
963+
logical(LK) :: found !! if the variable was found
964+
965+
found = me%valid_path(to_unicode(path))
966+
967+
end function wrap_json_file_valid_path
968+
!*****************************************************************************************
969+
869970
!*****************************************************************************************
870971
!> author: Jacob Williams
871972
!

src/json_value_module.F90

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,12 @@ module json_value_module
666666
generic,public :: get_path => MAYBEWRAP(json_get_path)
667667
procedure :: MAYBEWRAP(json_get_path)
668668

669+
!>
670+
! verify if a path is valid
671+
! (i.e., a variable with this path exists in the file).
672+
generic,public :: valid_path => MAYBEWRAP(json_valid_path)
673+
procedure :: MAYBEWRAP(json_valid_path)
674+
669675
procedure,public :: remove => json_value_remove !! Remove a [[json_value]] from a
670676
!! linked-list structure.
671677
procedure,public :: replace => json_value_replace !! Replace a [[json_value]] in a
@@ -5536,6 +5542,47 @@ end subroutine write_it
55365542
end subroutine json_value_print
55375543
!*****************************************************************************************
55385544

5545+
!*****************************************************************************************
5546+
!>
5547+
! Returns true if the `path` is present in the `p` JSON structure.
5548+
!
5549+
!@note Just a wrapper for [[json_get_by_path]], so it uses the
5550+
! specified `path_mode` and other settings.
5551+
5552+
function json_valid_path(json, p, path) result(found)
5553+
5554+
implicit none
5555+
5556+
class(json_core),intent(inout) :: json
5557+
type(json_value),pointer,intent(in) :: p !! a JSON linked list
5558+
character(kind=CK,len=*),intent(in) :: path !! path to the variable
5559+
logical(LK) :: found !! true if it was found
5560+
5561+
type(json_value),pointer :: tmp !! pointer to the variable specified by `path`
5562+
5563+
call json%get(p, path, tmp, found)
5564+
5565+
end function json_valid_path
5566+
!*****************************************************************************************
5567+
5568+
!*****************************************************************************************
5569+
!>
5570+
! Alternate version of [[json_valid_path]] where "path" is kind=CDK.
5571+
5572+
function wrap_json_valid_path(json, p, path) result(found)
5573+
5574+
implicit none
5575+
5576+
class(json_core),intent(inout) :: json
5577+
type(json_value),pointer,intent(in) :: p !! a JSON linked list
5578+
character(kind=CDK,len=*),intent(in) :: path !! path to the variable
5579+
logical(LK) :: found !! true if it was found
5580+
5581+
found = json%valid_path(p, to_unicode(path))
5582+
5583+
end function wrap_json_valid_path
5584+
!*****************************************************************************************
5585+
55395586
!*****************************************************************************************
55405587
!>
55415588
! Returns the [[json_value]] pointer given the path string.
@@ -5556,7 +5603,7 @@ subroutine json_get_by_path(json, me, path, p, found)
55565603
type(json_value),pointer,intent(in) :: me !! a JSON linked list
55575604
character(kind=CK,len=*),intent(in) :: path !! path to the variable
55585605
type(json_value),pointer,intent(out) :: p !! pointer to the variable
5559-
!! specify by `path`
5606+
!! specified by `path`
55605607
logical(LK),intent(out),optional :: found !! true if it was found
55615608

55625609
character(kind=CK,len=max_integer_str_len),allocatable :: path_mode_str !! string version
@@ -5822,8 +5869,8 @@ end subroutine json_rename_by_path_path_ascii
58225869
! * [[json_get_by_path_jsonpath_bracket]]
58235870
!
58245871
!@note The syntax is inherited from FSON, and is basically a subset
5825-
! of JSONPath "dot-notation", with the addition allowance of () for
5826-
! array elements.
5872+
! of JSONPath "dot-notation", with the additional allowance of
5873+
! () for array elements.
58275874
!
58285875
!@note JSON `null` values are used here for unknown variables when `create_it` is True.
58295876
! So, it is possible that an existing null variable can be converted to another

src/tests/jf_test_17.F90

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,55 @@ subroutine test_17(error_cnt)
116116
write(error_unit,'(A)') 'Success!'
117117
end if
118118

119+
! test the .in. operator and valid_path:
120+
if (CDK_'city' .in. f ) then
121+
write(error_unit,'(A)') '.in. operator Success!'
122+
else
123+
error_cnt = error_cnt + 1
124+
write(error_unit,'(A)') '.in. operator failed: "city"'
125+
end if
126+
if (CK_'city' .in. f) then
127+
write(error_unit,'(A)') '.in. operator Success!'
128+
else
129+
error_cnt = error_cnt + 1
130+
write(error_unit,'(A)') '.in. operator failed: "city"'
131+
end if
132+
if ('struct.vec' .in. f) then
133+
write(error_unit,'(A)') '.in. operator Success!'
134+
else
135+
error_cnt = error_cnt + 1
136+
write(error_unit,'(A)') '.in. operator failed: "struct.vec"'
137+
end if
138+
139+
if (f%valid_path(CDK_'city')) then
140+
write(error_unit,'(A)') 'valid_path Success!'
141+
else
142+
error_cnt = error_cnt + 1
143+
write(error_unit,'(A)') 'valid_path failed: "city"'
144+
end if
145+
if (f%valid_path(CK_'city')) then
146+
write(error_unit,'(A)') 'valid_path Success!'
147+
else
148+
error_cnt = error_cnt + 1
149+
write(error_unit,'(A)') 'valid_path failed: "city"'
150+
end if
151+
if (f%valid_path(CK_'struct.vec')) then
152+
write(error_unit,'(A)') 'valid_path Success!'
153+
else
154+
error_cnt = error_cnt + 1
155+
write(error_unit,'(A)') 'valid_path failed: "struct.vec"'
156+
end if
157+
! try one not there:
158+
if (.not. f%valid_path(CK_'?????????')) then
159+
write(error_unit,'(A)') 'valid_path Success!'
160+
else
161+
error_cnt = error_cnt + 1
162+
write(error_unit,'(A)') 'valid_path failed: "?????????"'
163+
end if
164+
165+
! cleanup:
166+
call f%destroy()
167+
119168
end subroutine test_17
120169

121170
end module jf_test_17_mod

0 commit comments

Comments
 (0)