Fortran YAML Library
Reading a YAML File
Our objective is to read value fields parent_1
and parent_2
from the following YAML input.yaml
file:
parent_1: # a map
child_a:
boolean_flag: true
an_aray: [0.999, 1.0]
array_int_2d: [[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]
parent_2: # a sequence
- item: 3 x 3 matrix.
value: [[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]
- item: 4 x 3 matrix
value:
item_is_float_array_2d: [[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]
Keys parent_1
ad parent_2
represent a map and a sequence, respectively. Shortly we will demonstrate
a structure to read both items from the YAML file.
Read a Map
The syntax for reading a map is:
use YAMLRead
character(len=:), allocatable :: fpath
type(YAMLHandler) :: domain
type(YAMLMap) :: parent
type(YAMLMap) :: mapper
integer :: code = 0
fpath = "./input.yaml"
domain = yaml_open_file(fpath)
parent = yaml_start_from_map(domain, "parent_1")
mapper = parent%value_map("child_a")
write(*,*) "map values = ", mapper%value_str("boolean_flag", code)
write(*,*) "map values = ", mapper%value_double_1d("an_aray", code)
write(*,*) "map values = ", mapper%value_int_2d("array_int_2d", code)
call mapper%destroy()
call parent%destroy()
call yaml_close_file(domain)
deallocate(fpath)
After importing the YAMLRead
module, the next step is to declare the variables we will use. A YAMLHandler
instance stores the file pointer and two YAMLMap's are declared as entry points into the
parent_1
and child_a
maps. Each hierarchial level requires its own YAMLMap declaration in order to safely manage
memory associated with those nodes. Therefore, a YAMLMap cannot be resued once it is assigned unless it is destroyed.
Next, we use the yaml_start_from_map function to retrieve the lead
node to designate a location to start scouring the YAML file. Both parent_1
and parent_2
are valid lead nodes in the example file above.
Now with the lead node set, we retrieve the child_a
map through the value_map
module procedure:
mapper = parent%value_map("child_a")
As demonstrated above, there's a different mechanism to access YAML nodes after the lead node is selected. Although it's debatable whether this is a good idea, this decoration exists in order to preserve a consistent access style we see with the YAML-cpp library. Each key value can be accessed using:
write(*,*) "mapper values = ", mapper%value_str("boolean_flag", code)
write(*,*) "mapper values = ", mapper%value_double_1d("an_aray", code)
write(*,*) "mapper values = ", mapper%value_int_2d("array_int_2d", code)
to print YAML content to the console. Objects are deleted in the reverse order they were
allocated to release memory. The code
argument is an exit code. If value extraction is
successful then code == 0
, otherwise it is another positive value.
Read a Sequence
Reading a sequence is similiar to maps:
use YAMLRead
character(len=:), allocatable :: fpath
type(YAMLHandler) :: domain
type(YAMLSequence) :: seq
type(YAMLElement) :: elem
integer :: n, i
fpath = "./input.yaml" !
domain = yaml_open_file(fpath)
seq = yaml_start_from_sequence(domain, "parent_2")
elem = seq%element(0)
write(*,*) "element 1 = ", elem%value_str("item", code)
write(*,*) "element 1 = ", elem%value_int_2d("value", code)
n = size(elem%labels)
do i = 1,n
write(*,*) " ", elem%labels(i)%str
end do
call elem%destroy()
call seq%destroy()
call yaml_close_file(domain)
deallocate(fpath)
One obvious difference is the delcaration of yaml_start_from_sequence
to access the parent_2
lead node.
This function call is necessary since parent_2
is a sequence. Another key difference is the declaration of
YAMLSequence and YAMLElement types in order to access interior
parts of the sequence.
Once variable seq
is assigned, then interior elements can be accessed using the element(...)
module
procedure. Th inpur argument to this procedure is zero-indexed; thus if we wanted to access the second
sequence entry, then the artgument is element(1)
. Sequence values are queried using the value_<>
getters,
a similiarity shared with maps. Resources are destroyed in the reverse order they are allocated.