FoXy v0.8.0 is out FoXy v0.8.0, a pure Fortran XML library with no C underneath, has been released, completing a rebuild that began at version 0.5 and was carried out with the help of an AI assistant. The release provides five types — xml_file for an in-memory DOM, xml_index for files too large to hold, xml_handler for streaming callbacks, xml_writer for element-by-element output, and xml_tag for single elements — and supports files of any size, including over 2 GiB. The library targets scientific code that reads case files as numbers and writes results metadata as it computes, returning typed errors such as XML_BAD_VALUE, XML_NOT_FOUND and XML_MALFORMED instead of requiring string parsing. Fortran XML for poor people FoXy is a pure Fortran library to read, query, edit, and write XML, with no C underneath: use foxy and your code talks XML hopefully . It started as a small parser for another poor people project VTKFortran ; the last four releases 0.5 to 0.8 rebuilt it with the help of an AI assistant into what scientific code needs from XML at least in my mind, even though I prefer other kinds of I/O formats generally : case files read as numbers, results metadata written as you compute, and files of any size , including over 2 GiB. Five types, one for each way of working with a document: | Type | For | |---|---| | xml file | a whole document in memory a DOM : parse, query, edit, save | | xml index | a file too large to hold: tags and attributes, contents read on demand | | xml handler | a document of any size read once: your callbacks, nothing stored | | xml writer | a document of any size, written element by element to a file, a unit or memory | | xml tag | a single element: build it, parse it, write it | The common case: a solver reads its settings from XML. No string juggling, no read ..., : use foxy type xml file :: doc real R8P :: dt integer I4P :: steps call doc%parse filename='case.xml' call doc%get content id=doc%find path='case/time/dt' , value=dt call doc%get content id=doc%find path='case/time/steps' , value=steps values= into an allocatable array , with iostat / iomsg . A value that is not a number gives XML BAD VALUE and leaves your variable unchanged; a missing tag or attribute gives XML NOT FOUND . 1e3 is not accepted as an integer. parse returns XML MALFORMED with the first problem and its line: tag structure, names, duplicate attributes, a second root, text outside the root, malformed references, ill-formed UTF-8. ids = doc%select 'case/boundary @type="wall" ' attribute value ids = doc%select '// @unit ' any name, at any depth ids = doc%select '/case/boundary 2 ' the second boundary child ids = doc%select '//boundary @side~="^ east|west $" /velocity' regular expression / , // , , @a , @a="v" , @a~="re" , n among siblings. A malformed expression returns no IDs and the column of the problem in matching re, ... , using the StringiFor engine Python re syntax, linear time, no backtracking . find / find all : by prefix, by {uri}local , or with your own prefixes mapped to URIs. type xml writer :: w call w%open call w%start 'cell' call w%attribute 'dt', 0.1 R8P the shortest text that reads back: 0.1 call w%attribute 'extent', 0 I4P, 63 I4P, 0 I4P, 31 I4P call w%start 'volume' call w%text 1. R8P/3. R8P call w%end 'volume' call w%start 'center' call w%text 0.5 R8P, 0.25 R8P, 0. R8P , fmt=' F5.3 ' call w%end 'center' call w%close