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)
Note
Not doing anything special about the -
character to index an array.
This is considered a normal error.
Note
Unlike in the default path mode, the array indices here are 0-based (in accordance with the RFC 6901 standard)
Warning
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.
Warning
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