Skip to content

9. Robust input and text ​

Case files are written by hand, and hands make mistakes. broken.xml forgets an end tag:

xml
<case name="cavity">
  <time>
    <dt unit="s">1.0e-3</dt>
    <steps>500
  </time>
</case>
f90
program solver
!< Tutorial, chapter 9: robust input and text.
use foxy
implicit none
type(xml_file)     :: case_file
integer(I4P)       :: iostat
character(len=256) :: iomsg

call case_file%parse(filename='broken.xml', iostat=iostat, iomsg=iomsg)
if (iostat==XML_MALFORMED) print '(A)', 'broken.xml: '//trim(iomsg)
print '(A)', 'dt is still read: '//case_file%content('dt')          ! tolerant: the document is built anyway
call case_file%parse(filename='case.xml')
print '(A)', 'notes:  '//case_file%content('notes')                  ! references decoded, CDATA literal
print '(A)', 'escape: '//xml_escape('a < b & "c"')
print '(A)', 'raw:    '//xml_unescape('1 &lt; 2 &#x26; &#233;t&#233;')
call case_file%parse(string='<p>the <b>lid</b> moves at <v>1</v> m/s</p>')
print '(A)', 'mixed:  '//case_file%content('p')                     ! the direct text of p, children excluded
print '(A)', case_file%stringify()                                   ! written back as it was
endprogram solver
  • Parsing is tolerant: the document is built as far as possible, and iostat=XML_MALFORMED with iomsg reports the first problem and its line. Besides the tags structure, FoXy reports invalid names, duplicate attributes, text outside the root element, more root elements, an empty source, ill-formed UTF-8, malformed references (a bare &, &nbsp;), and an encoding it does not read or that contradicts the byte order mark.
  • Sources in UTF-16, UTF-32, ISO-8859-1 or windows-1252 are converted to UTF-8 as they are read: everything you get back, and save, is UTF-8 (Encodings).
  • Stored text is the source text: stringify writes back what was read. The accessors decode it: references (&amp;, &#233;) become characters, CDATA sections are literal, comments are skipped, line ends are LF.
  • xml_escape and xml_unescape convert text yourself; content set with set_content or xml_tag(content=) is not escaped (it may hold markup), so escape user data first.
  • Mixed content (text around child tags) is kept: content returns the direct text of a tag, without its children.

Running it ​

$ solver
broken.xml: line 5: end tag </time> closes open tag <steps>
dt is still read: 1.0e-3
notes:  Lid-driven cavity & inflow, after <paper ref="1">.
escape: a &lt; b &amp; &quot;c&quot;
raw:    1 < 2 & été
mixed:  the  moves at  m/s
<p>the <b>lid</b> moves at <v>1</v> m/s</p>

What you learned

Check iostat/iomsg of parse; read text through the accessors, escape what you write as content. Reference: Parsing.

This is the end of the tutorial: the cookbook has short recipes for everyday tasks, the reference every method.