Globals Library 1.0
Loading...
Searching...
No Matches
modJsonData.f90
Go to the documentation of this file.
1module jsondata
2
3 use globals
4 use json_module
5
6 implicit none
7
8 private
9
10 !>-------------------------------------------------------------
11 !> @brief Derived data type to handle JSON data
12 !> @details This type acts as a wrapper around json-fortran's `json_file` type.
13 !> It simplifies the API and provides automatic error handling,
14 !> initialization, and type-bound procedures for get/set operations.
15 !<-------------------------------------------------------------
16 type, public :: json_type
17 private
18 !> Internal json-fortran object representing the JSON database.
19 type(json_file) :: data
20 contains
21 procedure, private :: init_core
22 procedure, private :: throw_error
23
24 generic, public :: init => init_empty, init_string
25 procedure, private :: init_empty
26 procedure, private :: init_string
27
28 generic, public :: load_file => load_file_name
29 procedure, private :: load_file_name
30
31 generic, public :: write => write_to_console, write_to_unit, write_to_file
32 procedure, private :: write_to_console
33 procedure, private :: write_to_unit
34 procedure, private :: write_to_file
35
36 generic, public :: clone => assign_json_type
37 procedure, private :: assign_json_type
38
39 generic, public :: has => check_path_is_valid
40 procedure, private :: check_path_is_valid
41
42 generic, public :: rename => rename_path
43 procedure, private :: rename_path
44
45 generic, public :: remove => remove_path
46 procedure, private :: remove_path
47
48 generic, public :: set_null => set_null_value, set_vec_null_value
49 procedure, private :: set_null_value
50 procedure, private :: set_vec_null_value
51
53 procedure, private :: set_object
54 procedure, private :: set_logical
55 procedure, private :: set_integer
56 procedure, private :: set_real
57 procedure, private :: set_string
58
59 generic, public :: set => set_vec_logical, set_vec_integer, set_vec_real
60 procedure, private :: set_vec_logical
61 procedure, private :: set_vec_integer
62 procedure, private :: set_vec_real
63
65 procedure, private :: get_object
66 procedure, private :: get_integer
67 procedure, private :: get_real
68 procedure, private :: get_logical
69 procedure, private :: get_string
70
71 generic, public :: get => get_vec_integer, get_vec_real, get_vec_logical
72 procedure, private :: get_vec_integer
73 procedure, private :: get_vec_real
74 procedure, private :: get_vec_logical
75
76 generic, public :: assignment(=) => assign_json_type, init_string
77
78 generic, public :: kill => kill_json_type
79 procedure, private :: kill_json_type
81 end type json_type
82
83contains
84
85 !>--------------------------------------------------------------------
86 !> @brief Static constructor for internal JSON core settings
87 !> @details Sets the preferred configuration for json-fortran's core.
88 !<---------------------------------------------------------------------
89 subroutine init_core(this)
90 implicit none
91 class(json_type), intent(inout) :: this
92
93 call this%data%initialize(&
94 compact_reals=.true.,&
95 verbose=.false.,& ! if true, a lot of warnings are printed
96 strict_type_checking=.true.,&
97 compress_vectors=.true.,&
98 stop_on_error=.false.,& ! error handling inside this module
99 allow_duplicate_keys=.false.&
100 )
101
102 end subroutine init_core
103
104 !>--------------------------------------------------------------------
105 !> @brief Checks for parsing/runtime errors and raises Fortran exception
106 !> @details If an error has been registered within the `json_file` instance,
107 !> this subroutine throws a standard Fortran `error stop` with the message.
108 !<---------------------------------------------------------------------
109 subroutine throw_error(this)
110 implicit none
111 class(json_type), intent(inout) :: this
112 logical :: json_status
113 character(len=:), allocatable :: error_msg
114
115 call this%data%check_for_errors(json_status, error_msg)
116 if (.not.json_status) error stop error_msg
117
118 end subroutine throw_error
119
120 !>--------------------------------------------------------------------
121 !> @brief Initialize the object as an empty JSON file/database
122 !<---------------------------------------------------------------------
123 subroutine init_empty(this)
124 implicit none
125 class(json_type), intent(inout) :: this
126
127 call this%kill()
128 call this%init_core()
129
130 end subroutine init_empty
131
132 !>--------------------------------------------------------------------
133 !> @brief Initialize the object from a JSON string payload
134 !>
135 !> @param[in ] str: character string payload in JSON format
136 !<---------------------------------------------------------------------
137 subroutine init_string(this,str)
138 implicit none
139 class(json_type), intent(inout) :: this
140 character(len=*), intent(in) :: str
141
142 call this%init_empty()
143 call this%data%deserialize(str)
144 call this%throw_error()
145
146 end subroutine init_string
147
148 !>--------------------------------------------------------------------
149 !> @brief Destroys the JSON object and deallocates internal variables
150 !<---------------------------------------------------------------------
151 subroutine kill_json_type(this)
152 implicit none
153 class(json_type), intent(inout) :: this
154
155 call this%data%destroy(.true.)
156 call this%throw_error()
157
158 end subroutine kill_json_type
159
160 !>--------------------------------------------------------------------
161 !> @brief Finalization routine triggered implicitly when object goes
162 !> out of scope or is destroyed
163 !<---------------------------------------------------------------------
164 subroutine finalize_json_type(this)
165 implicit none
166 type(json_type), intent(inout) :: this
167
168 call this%kill()
169
170 end subroutine finalize_json_type
171
172 !>--------------------------------------------------------------------
173 !> @brief Print the JSON object representation to standard output
174 !<---------------------------------------------------------------------
175 subroutine write_to_console(this)
176 implicit none
177 class(json_type), intent(inout) :: this
178
179 call this%data%print()
180 call this%throw_error()
181
182 end subroutine write_to_console
183
184 !>--------------------------------------------------------------------
185 !> @brief Print the JSON object representation to a specific
186 !> formatted Fortran unit
187 !>
188 !> @param[in ] iunit: integer, connected Fortran file unit
189 !<---------------------------------------------------------------------
190 subroutine write_to_unit(this, iunit)
191 implicit none
192 class(json_type), intent(inout) :: this
193 integer, intent(in) :: iunit
194
195 call this%data%print(iunit)
196 call this%throw_error()
197
198 end subroutine write_to_unit
199
200 !>--------------------------------------------------------------------
201 !> @brief Save the JSON object representation directly to a file
202 !>
203 !> @param[in ] filename: name of the output JSON file
204 !<---------------------------------------------------------------------
205 subroutine write_to_file(this, filename)
206 implicit none
207 class(json_type), intent(inout) :: this
208 character(len=*), intent(in) :: filename
209
210 call this%data%print(filename)
211 call this%throw_error()
212
213 end subroutine
214
215 !>--------------------------------------------------------------------
216 !> @brief Construct a JSON structure from a JSON file path
217 !>
218 !> @param[in ] filename: path to the JSON file to parse
219 !<---------------------------------------------------------------------
220 subroutine load_file_name(this, filename)
221 implicit none
222 class(json_type), intent(inout) :: this
223 character(len=*), intent(in) :: filename
224
225 call this%data%load_file(filename, destroy_pointer=.true.)
226 call this%throw_error()
227
228 end subroutine load_file_name
229
230 !>--------------------------------------------------------------------
231 !> @brief Verify if a specific path exists within the JSON tree
232 !>
233 !> @param[in ] path: valid JSONPath style or key path
234 !> @return found: logical, true if path exists, false otherwise
235 !<---------------------------------------------------------------------
236 function check_path_is_valid(this, path) result(found)
237 implicit none
238 class(json_type), intent(inout) :: this
239 character(len=*), intent(in) :: path
240 logical :: found
241
242 found = this%data%valid_path(path)
243
244 end function check_path_is_valid
245
246 !>--------------------------------------------------------------------
247 !> @brief Rename a node located at the specified path
248 !>
249 !> @param[in ] path: path to the node to rename
250 !> @param[in ] new_name: new string identifier for the node
251 !<---------------------------------------------------------------------
252 subroutine rename_path(this, path, new_name)
253 implicit none
254 class(json_type), intent(inout) :: this
255 character(len=*), intent(in) :: path
256 character(len=*), intent(in) :: new_name
257 logical :: found
258 character(len=256) :: error_msg
259
260 call this%data%rename(path, new_name, found)
261 call this%throw_error()
262 if (.not.found) then
263 write(error_msg,*) "Key '", path, "' not found!"
264 error stop error_msg
265 end if
266
267 end subroutine rename_path
268
269 !>--------------------------------------------------------------------
270 !> @brief Remove a node located at the specified path entirely
271 !>
272 !> @param[in ] path: path to the node to remove
273 !<---------------------------------------------------------------------
274 subroutine remove_path(this, path)
275 implicit none
276 class(json_type), intent(inout) :: this
277 character(len=*), intent(in) :: path
278
279 call this%data%remove(path)
280 call this%throw_error()
281
282 end subroutine remove_path
283
284 !>--------------------------------------------------------------------
285 !> @brief Append a deeply copied instance of another JSON object at path
286 !>
287 !> @param[in ] path: path where the new object will be inserted
288 !> @param[inout] value: standard json_type object (content will be copied)
289 !<---------------------------------------------------------------------
290 subroutine set_object(this, path, value)
291 implicit none
292 class(json_type), intent(inout) :: this
293 character(len=*), intent(in) :: path
294 type(json_type), intent(inout) :: value
295 type(json_value), pointer :: p, pclone
296 type(json_core) :: core
297
298 call this%data%get_core(core)
299 call value%data%get(p)
300 call core%clone(p,pclone)
301 call this%data%add(path, pclone)
302 call this%throw_error()
303
304 end subroutine set_object
305
306 !>--------------------------------------------------------------------
307 !> @brief Setup a logical boolean value inside the JSON tree
308 !>
309 !> @param[in ] path: target property path
310 !> @param[in ] value: target scalar array to map
311 !<---------------------------------------------------------------------
312 subroutine set_logical(this, path, value)
313 implicit none
314 class(json_type), intent(inout) :: this
315 character(len=*), intent(in) :: path
316 logical, intent(in) :: value
317
318 call this%data%add(path, value)
319 call this%throw_error()
320
321 end subroutine set_logical
322
323 !>--------------------------------------------------------------------
324 !> @brief Setup an integer value inside the JSON tree
325 !>
326 !> @param[in ] path: target property path
327 !> @param[in ] value: target scalar to map
328 !<---------------------------------------------------------------------
329 subroutine set_integer(this, path, value)
330 implicit none
331 class(json_type), intent(inout) :: this
332 character(len=*), intent(in) :: path
333 integer, intent(in) :: value
334
335 call this%data%add(path, value)
336 call this%throw_error()
337
338 end subroutine set_integer
339
340 !>--------------------------------------------------------------------
341 !> @brief Setup a float literal (double precision) value into JSON tree
342 !>
343 !> @param[in ] path: target property path
344 !> @param[in ] value: target scalar to map
345 !<---------------------------------------------------------------------
346 subroutine set_real(this, path, value)
347 implicit none
348 class(json_type), intent(inout) :: this
349 character(len=*), intent(in) :: path
350 real(kind=double), intent(in) :: value
351
352 call this%data%add(path, value)
353 call this%throw_error()
354
355 end subroutine set_real
356
357 !>--------------------------------------------------------------------
358 !> @brief Setup a JSON string scalar property
359 !>
360 !> @param[in ] path: target property path
361 !> @param[in ] value: character string to add
362 !<---------------------------------------------------------------------
363 subroutine set_string(this, path, value)
364 implicit none
365 class(json_type), intent(inout) :: this
366 character(len=*), intent(in) :: path
367 character(len=*), intent(in) :: value
368
369 call this%data%add(path, value, trim_str=.true., adjustl_str=.true.)
370 call this%throw_error()
371
372 end subroutine set_string
373
374 !>--------------------------------------------------------------------
375 !> @brief Adds an array dimension of logic variables linearly
376 !>
377 !> @param[in ] path: target property path
378 !> @param[in ] value: logical dimension 1 vector mapping
379 !<---------------------------------------------------------------------
380 subroutine set_vec_logical(this, path, value)
381 implicit none
382 class(json_type), intent(inout) :: this
383 character(len=*), intent(in) :: path
384 logical, dimension(:), intent(in) :: value
385
386 call this%data%add(path, value)
387 call this%throw_error()
388
389 end subroutine set_vec_logical
390
391 !>--------------------------------------------------------------------
392 !> @brief Adds an array block size containing integers to current root
393 !>
394 !> @param[in ] path: target property path
395 !> @param[in ] value: integer target dimensions to add
396 !<---------------------------------------------------------------------
397 subroutine set_vec_integer(this, path, value)
398 implicit none
399 class(json_type), intent(inout) :: this
400 character(len=*), intent(in) :: path
401 integer, dimension(:), intent(in) :: value
402
403 call this%data%add(path, value)
404 call this%throw_error()
405
406 end subroutine set_vec_integer
407
408 !>--------------------------------------------------------------------
409 !> @brief Adds an array literal values consisting of double precisions
410 !>
411 !> @param[in ] path: target property path
412 !> @param[in ] value: sequence representing float point doubles
413 !<---------------------------------------------------------------------
414 subroutine set_vec_real(this, path, value)
415 implicit none
416 class(json_type), intent(inout) :: this
417 character(len=*), intent(in) :: path
418 real(kind=double), dimension(:), intent(in) :: value
419
420 call this%data%add(path, value)
421 call this%throw_error()
422
423 end subroutine set_vec_real
424
425 !>--------------------------------------------------------------------
426 !> @brief Parses a subtree and clones its content into an alternative
427 !> object variable
428 !>
429 !> @param[in ] path: json path identifier to load the object hierarchy
430 !> @param[inout] value: distinct `json_type` object constructed from
431 !> that path copy
432 !<---------------------------------------------------------------------
433 subroutine get_object(this, path, value)
434 implicit none
435 class(json_type), intent(inout) :: this
436 character(len=*), intent(in) :: path
437 type(json_type), intent(inout) :: value
438 type(json_value), pointer :: p, pclone
439 type(json_core) :: core
440
441 call this%data%get(path, p)
442 call this%data%get_core(core)
443 call core%clone(p, pclone)
444 call value%init_empty()
445 call value%data%add(pclone, destroy_original=.false.)
446 call this%throw_error()
447
448 end subroutine get_object
449
450 !>--------------------------------------------------------------------
451 !> @brief Retrive integer primitive from loaded property tree
452 !>
453 !> @param[in ] path: integer json path target to retrieve
454 !> @param[out ] value: output mapped variable memory target
455 !> @param[in ] default: integer default backup variable if path
456 !> does not exist
457 !<---------------------------------------------------------------------
458 subroutine get_integer(this, path, value, default)
459 implicit none
460 class(json_type), intent(inout) :: this
461 character(len=*), intent(in) :: path
462 integer, intent(out) :: value
463 integer, intent(in), optional :: default
464
465 call this%data%get(path, value, default=default)
466 call this%throw_error()
467
468 end subroutine get_integer
469
470 !>--------------------------------------------------------------------
471 !> @brief Retrieve floating point double sequence type variable
472 !>
473 !> @param[in ] path: target search index representing object floating node
474 !> @param[out ] value: output double float mapped variable target
475 !> @param[in ] default: double precision backup variable definition
476 !<---------------------------------------------------------------------
477 subroutine get_real(this, path, value, default)
478 implicit none
479 class(json_type), intent(inout) :: this
480 character(len=*), intent(in) :: path
481 real(kind=double), intent(out) :: value
482 real(kind=double), intent(in), optional :: default
483
484 call this%data%get(path, value, default=default)
485 call this%throw_error()
486
487 end subroutine get_real
488
489 !>--------------------------------------------------------------------
490 !> @brief Get a logical expression defined inside properties list mapping
491 !>
492 !> @param[in ] path: structural map defining where local var resides
493 !> @param[out ] value: mapping output variable allocation logic
494 !> @param[in ] default: literal substitution default sequence expression
495 !<---------------------------------------------------------------------
496 subroutine get_logical(this, path, value, default)
497 implicit none
498 class(json_type), intent(inout) :: this
499 character(len=*), intent(in) :: path
500 logical, intent(out) :: value
501 logical, intent(in), optional :: default
502
503 call this%data%get(path, value, default=default)
504 call this%throw_error()
505
506 end subroutine get_logical
507
508 !>--------------------------------------------------------------------
509 !> @brief Retrieve string character definitions loaded dynamically via
510 !> parsed map length format
511 !>
512 !> @param[in ] path: mapping representation block identifier parameter
513 !> @param[out ] value: explicit allocation string containing sequence
514 !> variable loaded
515 !> @param[in ] default: base case default string text returned as
516 !> alternative definition structure
517 !<---------------------------------------------------------------------
518 subroutine get_string(this, path, value, default)
519 implicit none
520 class(json_type), intent(inout) :: this
521 character(len=*), intent(in) :: path
522 character(len=:), allocatable, intent(out) :: value
523 character(len=*), intent(in), optional :: default
524
525 call this%data%get(path, value, default=default)
526 call this%throw_error()
527
528 end subroutine get_string
529
530 !>--------------------------------------------------------------------
531 !> @brief Parses target dynamically evaluated integer matrix structure
532 !> hierarchy sequences
533 !>
534 !> @param[in ] path: json-fortran query pointer representing valid
535 !> location definitions array
536 !> @param[out ] value: parsed output list of dynamically typed integers map
537 !> @param[in ] default: alternative list sequence to bypass failing
538 !> load tree elements logic structure
539 !<---------------------------------------------------------------------
540 subroutine get_vec_integer(this, path, value, default)
541 implicit none
542 class(json_type), intent(inout) :: this
543 character(len=*), intent(in) :: path
544 integer, dimension(:), allocatable, intent(out) :: value
545 integer, dimension(:), intent(in), optional :: default
546
547 call this%data%get(path, value, default=default)
548 call this%throw_error()
549
550 end subroutine get_vec_integer
551
552 !>--------------------------------------------------------------------
553 !> @brief Retrives continuous unmapped values sequence containing
554 !> decimal arrays
555 !>
556 !> @param[in ] path: standard map search component path lookup
557 !> identifier map sequence
558 !> @param[out ] value: mapped data payload holding dynamic floating
559 !> sequences size allocation
560 !> @param[in ] default: definition array fallback defaults representation
561 !<---------------------------------------------------------------------
562 subroutine get_vec_real(this, path, value, default)
563 implicit none
564 class(json_type), intent(inout) :: this
565 character(len=*), intent(in) :: path
566 real(kind=double), dimension(:), allocatable, intent(out) :: value
567 real(kind=double), dimension(:), intent(in), optional :: default
568
569 call this%data%get(path, value, default=default)
570 call this%throw_error()
571
572 end subroutine get_vec_real
573
574 !>--------------------------------------------------------------------
575 !> @brief Returns memory structure block sequences representing
576 !> dynamically stored logic array data
577 !>
578 !> @param[in ] path: base location directory to find boolean maps vector
579 !> @param[out ] value: memory structure to assign found array boolean
580 !> literals map dynamically
581 !> @param[in ] default: precomputed defaults mapping fallback sequence
582 !> vector structure list
583 !<---------------------------------------------------------------------
584 subroutine get_vec_logical(this, path, value, default)
585 implicit none
586 class(json_type), intent(inout) :: this
587 character(len=*), intent(in) :: path
588 logical, dimension(:), allocatable, intent(out) :: value
589 logical, dimension(:), intent(in), optional :: default
590
591 call this%data%get(path, value, default=default)
592 call this%throw_error()
593
594 end subroutine get_vec_logical
595
596 !>--------------------------------------------------------------------
597 !> @brief Modifies payload hierarchy to explicitly associate a JSON
598 !> null block
599 !>
600 !> @param[in ] path: JSON property where null literal representation
601 !> is added mapping identifier sequence
602 !<---------------------------------------------------------------------
603 subroutine set_null_value(this, path)
604 implicit none
605 class(json_type), intent(inout) :: this
606 character(len=*), intent(in) :: path
607
608 call this%data%add_null(path)
609 call this%throw_error()
610
611 end subroutine set_null_value
612
613 !>--------------------------------------------------------------------
614 !> @brief Evaluates an explicitly formatted sized array mapped block
615 !> of JSON null components
616 !>
617 !> @param[in ] path: directory sequence pointer map parameter
618 !> reference string identifier
619 !> @param[in ] nvalues: amount of mapped identical logical NULL array
620 !> sequence size representation vector
621 !<---------------------------------------------------------------------
622 subroutine set_vec_null_value(this, path, nvalues)
623 implicit none
624 class(json_type), intent(inout) :: this
625 character(len=*), intent(in) :: path
626 integer, intent(in) :: nvalues
627
628 call this%data%add_null(path, nvalues)
629 call this%throw_error()
630
631 end subroutine set_vec_null_value
632
633 !>--------------------------------------------------------------------
634 !> @brief Prepares native assignments logic deeply copies mapping JSON
635 !> representation states
636 !>
637 !> @param[in ] other: representation data map wrapper struct source
638 !> variable reference structure target
639 !<---------------------------------------------------------------------
640 subroutine assign_json_type(this, other)
641 implicit none
642 class(json_type), intent(out) :: this
643 type(json_type), intent(in) :: other
644
645 this%data = other%data
646
647 end subroutine assign_json_type
648
649end module jsondata
subroutine get_integer(this, path, value, default)
Retrive integer primitive from loaded property tree.
subroutine set_logical(this, path, value)
Setup a logical boolean value inside the JSON tree.
subroutine get_vec_integer(this, path, value, default)
Parses target dynamically evaluated integer matrix structure hierarchy sequences.
subroutine finalize_json_type(this)
Finalization routine triggered implicitly when object goes out of scope or is destroyed.
subroutine get_vec_logical(this, path, value, default)
Returns memory structure block sequences representing dynamically stored logic array data.
subroutine get_logical(this, path, value, default)
Get a logical expression defined inside properties list mapping.
subroutine set_real(this, path, value)
Setup a float literal (double precision) value into JSON tree.
logical function check_path_is_valid(this, path)
Verify if a specific path exists within the JSON tree.
subroutine load_file_name(this, filename)
Construct a JSON structure from a JSON file path.
subroutine set_null_value(this, path)
Modifies payload hierarchy to explicitly associate a JSON null block.
subroutine throw_error(this)
Checks for parsing/runtime errors and raises Fortran exception.
subroutine remove_path(this, path)
Remove a node located at the specified path entirely.
subroutine rename_path(this, path, new_name)
Rename a node located at the specified path.
subroutine kill_json_type(this)
Destroys the JSON object and deallocates internal variables.
subroutine assign_json_type(this, other)
Prepares native assignments logic deeply copies mapping JSON representation states.
subroutine set_string(this, path, value)
Setup a JSON string scalar property.
subroutine write_to_console(this)
Print the JSON object representation to standard output.
subroutine init_string(this, str)
Initialize the object from a JSON string payload.
subroutine set_vec_logical(this, path, value)
Adds an array dimension of logic variables linearly.
subroutine get_string(this, path, value, default)
Retrieve string character definitions loaded dynamically via parsed map length format.
subroutine set_vec_real(this, path, value)
Adds an array literal values consisting of double precisions.
subroutine get_real(this, path, value, default)
Retrieve floating point double sequence type variable.
subroutine init_empty(this)
Initialize the object as an empty JSON file/database.
subroutine set_object(this, path, value)
Append a deeply copied instance of another JSON object at path.
subroutine init_core(this)
Static constructor for internal JSON core settings.
subroutine get_vec_real(this, path, value, default)
Retrives continuous unmapped values sequence containing decimal arrays.
subroutine set_integer(this, path, value)
Setup an integer value inside the JSON tree.
subroutine set_vec_null_value(this, path, nvalues)
Evaluates an explicitly formatted sized array mapped block of JSON null components.
subroutine write_to_file(this, filename)
Save the JSON object representation directly to a file.
subroutine set_vec_integer(this, path, value)
Adds an array block size containing integers to current root.
subroutine write_to_unit(this, iunit)
Print the JSON object representation to a specific formatted Fortran unit.
subroutine get_object(this, path, value)
Parses a subtree and clones its content into an alternative object variable.
Derived data type to handle JSON data.