jacobwilliams / json-fortran

A Modern Fortran JSON API
https://jacobwilliams.github.io/json-fortran/
Other
337 stars 86 forks source link

Find Object in Array #472

Closed nyckmaia closed 4 years ago

nyckmaia commented 4 years ago

Hi, I'm a C/C++ programmer and a newer developer in Fortran language....

I would like to develop a Fortran subroutine that return a JSON object located inside a JSON array. Example:

{
  "group": {
    "people": [
      {
        "name": "John",
        "age": 10
      },
      {
        "name": "Luke",
        "age": 22
      }
    ]
  }
}

What I already tried:

module xxx
    type(json_file), private :: json ! json file
    ...
contains
....fortran
subroutine getObjectInArray(jsonArrayPath, objectName, jsonObject, objectFound)
    implicit none
    ! ----- INPUT VARIABLES ----- !
    character(len=*), intent(in) :: jsonArrayPath
    character(len=*), intent(in) :: objectName ! Desired 'name'
    type(json_value), pointer, intent(out) :: jsonObject ! Pointer to the selected object
    logical, intent(out) :: objectFound ! Flag to know if the pointer 'jsonObject' is valid or not

    ! ----- LOCAL VARIABLES ----- !
    integer :: i, arraySize
    character(len=10) :: i_str
    character(kind=json_CK, len=:), allocatable :: tempName

    ! ----- INIT LOCAL VARIABLES -----!
    i = 0
    arraySize = 0

    ! ----- START ----- !
    call json%info(jsonArrayPath, n_children=arraySize)

    ! Error checking
    if (arraySize == 0) then
        call sendErrorMsg("Unable to find "//objectName// " in this path: "//jsonArrayPath//C_NULL_CHAR)
        objectFound = .false.
        jsonObject => null()
        return
    end if

    ! Iterate over all array objects       
    do i = 0, arraySize-1
        write(i_str, fmt='(I10)') i
        i_str = adjustl(i_str)

        jsonField = jsonArrayPath//"/"//i_str

        call json%get(jsonField//"/name", tempName, found)
        if ( .not. found ) stop 1

        if (tempName == objectName) then
            ! OBJECT FOUND IN THE ARRAY
            objectFound = .true.                 
            call json%get(jsonField, jsonObject) ! I DONT HAVE SHURE IF THIS IS RIGHT
            return
        end if
    end do            
end subroutine getObjectInArray

So, I'm trying to call this subroutine like this:

subroutine main() !inside the same module `xxx`
    ! ---- LOCAL VARIABLES ---- !
    character(kind=json_CK, len=:), allocatable :: objectName
    integer :: age
    type(json_value), pointer :: jsonObject
    logical :: objectFound

    ! ---- START ---- !
    objectName = "Luke"

    call getObjectInArray("/group/people", objectName, jsonObject, objectFound)

    if (objectFound .eqv. .false.) return

    call json%print(jsonObject) ! COMPILE TIME ERROR (1)

    call json%get(jsonObject, "age", age) ! WRONG SYNTAX. COMPILE TIME ERROR (2)
    if ( .not. found ) stop 2

My Error (1) is:

Error: Found no matching specific binding for the call to the GENERIC ‘print’ at (1)

My Error (2) is:

Error: Found no matching specific binding for the call to the GENERIC ‘get’ at (1)

Could you please help me to fix this compile time errors above?

My System:

nyckmaia commented 4 years ago

I found my mistake...

I need to declare a new variable:

type(json_core) :: core

Now, I can read the pointer data and get the values using:

call core%print(jsonObject)

call core%get(jsonObject, "age", age)
if ( .not. found ) stop 1