Skip to content

3. Walking the tree ​

Before running, solver prints the whole case: every tag, its attributes and its text, indented by depth, and then its boundaries. Nothing here knows the names in advance.

f90
program solver
!< Tutorial, chapter 3: walking the tree.
use foxy
implicit none
type(xml_file)            :: case_file
integer(I4P), allocatable :: ids(:)
integer(I4P)              :: b
integer(I4P)              :: iostat
type(regex)               :: walls

call case_file%parse(filename='case.xml')
print '(A,I0,A)', 'case.xml has ', case_file%tags_number(), ' tags'
call outline(id=1, depth=0)
ids = case_file%find_all(path='case/boundary')       ! every match, in document order
do b=1, size(ids)
   print '(A)', 'boundary '//case_file%attribute(ids(b), 'side')//': '//case_file%attribute(ids(b), 'type')
enddo
call walls%compile('^(wall|outflow)$', iostat=iostat)          ! a regular expression (StringiFor engine)
ids = case_file%matching(walls, ids=case_file%find_all(path='case/boundary'), attribute='type')
print '(A,I0,A)', 'closed boundaries: ', size(ids), ' ('//case_file%attribute(ids(1), 'side')//', ...)'
ids = case_file%select('case/boundary[@type="wall"]')           ! a path expression: the same in one call
print '(A,*(1X,A))', 'walls:', (case_file%attribute(ids(b), 'side'), b=1, size(ids))
contains
   recursive subroutine outline(id, depth)
   !< Print a tag, its attributes and, indented, its children.
   integer(I4P), intent(in)      :: id, depth
   character(len=:), allocatable :: line
   integer(I4P), allocatable     :: kids(:)
   integer(I4P)                  :: a, k

   line = repeat('  ', depth)//case_file%name(id)
   do a=1, case_file%attributes_number(id)            ! the attributes, without knowing their names
      line = line//' '//case_file%attribute_name(id, a)//'='//case_file%attribute(id, case_file%attribute_name(id, a))
   enddo
   if (len(case_file%content(id=id))>0) line = line//': '//case_file%content(id=id)
   print '(A)', line
   kids = case_file%children(id)
   do k=1, size(kids)
      call outline(id=kids(k), depth=depth+1)
   enddo
   endsubroutine outline
endprogram solver
  • tags_number() is the number of tags: the IDs go from 1 to tags_number().
  • children(id) returns the IDs of the direct children of a tag (children(0): the root tags); name(id) its name.
  • attributes_number(id) and attribute_name(id, a) list the attributes of a tag, in source order.
  • find_all returns every match, in document order: here the four boundary tags under case.
  • matching keeps the tags whose name, content or attribute matches a regular expression: here the boundaries whose type is a wall or an outflow. The regex (type(regex), StringiFor's engine) is compiled once.
  • select takes a path expression, a small XPath: / for children, // for descendants, * for any name, and tests in brackets ([@type="wall"], [@side~="^(east|west)$"], [2]). It does in one call what find_all and matching do above; a malformed expression returns XML_MALFORMED with its column. See the path selector.

Running it ​

$ solver
case.xml has 18 tags
case name=cavity version=2
  mesh
    grid ni=64 nj=32 nk=1
    domain: 0.0 1.0 0.0 0.5 0.0 0.0
  time
    dt unit=s: 1.0e-3
    steps: 500
    adaptive: true
  fluid name=air
    density unit=kg/m3: 1.225
    viscosity unit=Pa s: 1.8e-5
  boundary side=west type=inflow
    velocity: 1.0 0.0 0.0
  boundary side=east type=outflow
  boundary side=north type=wall
  boundary side=south type=wall
  output every=100: results.xml
  notes: Lid-driven cavity & inflow, after <paper ref="1">.
boundary west: inflow
boundary east: outflow
boundary north: wall
boundary south: wall
closed boundaries: 3 (east, ...)
walls: north south

The text of notes shows two more things that content does for you: &amp; is decoded, and the <![CDATA[...]]> section is taken literally (its < is text, not a tag).

What you learned

children and name walk the tree, attributes_number and attribute_name list attributes, find_all collects repeated tags, matching filters them by a regular expression, select does both with a path expression. Reference: Querying.

Next: 4. Editing and saving.