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.