Returns the json_value pointer given the path string, using the “JSON Pointer” path specification defined by RFC 6901.
Note that trailing whitespace significance and case sensitivity
are user-specified. To fully conform to the RFC 6901 standard,
should probably set (via initialize
):
case_sensitive_keys = .true.
[this is the default setting]trailing_spaces_significant = .true.
[this is not the default setting]allow_duplicate_keys = .false.
[this is not the default setting] type(json_core) :: json
type(json_value),pointer :: dat,p
logical :: found
!...
call json%initialize(path_mode=2)
call json%get(dat,'/data/2/version',p,found)
Not doing anything special about the -
character to index an array.
This is considered a normal error.
Unlike in the default path mode, the array indices here are 0-based (in accordance with the RFC 6901 standard)
Not checking if the member that is referenced is unique. (according to the standard, evaluation of non-unique references should fail). Like json_get_by_path_default, this one will just return the first instance it encounters. This might be changed in the future.
I think the standard indicates that the input paths should use escaped JSON strings (currently we are assuming they are not escaped).
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
class(json_core), | intent(inout) | :: | json | |||
type(json_value), | intent(in), | pointer | :: | me | a JSON linked list |
|
character(kind=CK,len=*), | intent(in) | :: | path | path to the variable (an RFC 6901 “JSON Pointer”) |
||
type(json_value), | intent(out), | pointer | :: | p | pointer to the variable
specify by |
|
logical(kind=LK), | intent(out), | optional | :: | found | true if it was found |
subroutine json_get_by_path_rfc6901(json, me, path, p, found)
implicit none
class(json_core),intent(inout) :: json
type(json_value),pointer,intent(in) :: me !! a JSON linked list
character(kind=CK,len=*),intent(in) :: path !! path to the variable
!! (an RFC 6901 "JSON Pointer")
type(json_value),pointer,intent(out) :: p !! pointer to the variable
!! specify by `path`
logical(LK),intent(out),optional :: found !! true if it was found
character(kind=CK,len=:),allocatable :: token !! a token in the path (between the `/` characters)
integer(IK) :: i !! counter
integer(IK) :: islash_curr !! location of current '/' character in the path
integer(IK) :: islash_next !! location of next '/' character in the path
integer(IK) :: ilen !! length of `path` string
type(json_value),pointer :: tmp !! temporary variable for traversing the structure
integer(IK) :: ival !! integer array index value (0-based)
logical(LK) :: status_ok !! error flag
logical(LK) :: child_found !! for getting child values
nullify(p)
if (.not. json%exception_thrown) then
p => me ! initialize
if (path/=CK_'') then
if (path(1:1)==slash) then ! the first character must be a slash
islash_curr = 1 ! initialize current slash index
!keep trailing space or not:
if (json%trailing_spaces_significant) then
ilen = len(path)
else
ilen = len_trim(path)
end if
do
! get the next token by finding the slashes
!
! 1 2 3
! /abc/d/efg
if (islash_curr==ilen) then
!the last token is an empty string
token = CK_''
islash_next = 0 ! will signal to stop
else
! .
! '/123/567/'
! index in remaining string:
islash_next = index(path(islash_curr+1:ilen),slash)
if (islash_next<=0) then
!last token:
token = path(islash_curr+1:ilen)
else
! convert to actual index in path:
islash_next = islash_curr + index(path(islash_curr+1:ilen),slash)
if (islash_next>islash_curr+1) then
token = path(islash_curr+1:islash_next-1)
else
!empty token:
token = CK_''
end if
end if
end if
! remove trailing spaces in the token here if necessary:
if (.not. json%trailing_spaces_significant) &
token = trim(token)
! decode the token:
token = decode_rfc6901(token)
! now, parse the token:
! first see if there is a child with this name
call json%get_child(p,token,tmp,child_found)
if (child_found) then
! it was found
p => tmp
else
! No key with this name.
! Is it an integer? If so,
! it might be an array index.
status_ok = (len(token)>0)
if (status_ok) then
do i=1,len(token)
! It must only contain (0..9) characters
! (it must be unsigned)
if (scan(token(i:i),CK_'0123456789')<1) then
status_ok = .false.
exit
end if
end do
if (status_ok) then
if (len(token)>1 .and. token(1:1)==CK_'0') then
! leading zeros not allowed for some reason
status_ok = .false.
end if
end if
if (status_ok) then
! if we make it this far, it should be
! convertible to an integer, so do it.
call string_to_integer(token,ival,status_ok)
end if
end if
if (status_ok) then
! ival is an array index (0-based)
call json%get_child(p,ival+1_IK,tmp,child_found)
if (child_found) then
p => tmp
else
! not found
status_ok = .false.
end if
end if
if (.not. status_ok) then
call json%throw_exception('Error in json_get_by_path_rfc6901: '//&
'invalid path specification: '//trim(path),found)
exit
end if
end if
if (islash_next<=0) exit ! finished
! set up for next token:
islash_curr = islash_next
end do
else
call json%throw_exception('Error in json_get_by_path_rfc6901: '//&
'invalid path specification: '//trim(path),found)
end if
end if
if (json%exception_thrown) then
nullify(p)
if (present(found)) then
found = .false.
call json%clear_exceptions()
end if
else
if (present(found)) found = .true.
end if
else
if (present(found)) found = .false.
end if
end subroutine json_get_by_path_rfc6901