Skip to content

Features ​

One module ​

Everything comes from the foxy module: the five types, the kinds, the error codes and a few helpers.

fortran
use foxy                       ! xml_file, xml_index, xml_handler (with xml_attribute), xml_writer, xml_tag;
                               ! I1P...I8P, R4P, R8P; XML_MALFORMED, XML_NOT_FOUND, XML_BAD_VALUE;
                               ! xml_escape, xml_unescape, to_value, to_values; regex, regex_match (StringiFor)
type(xml_file) :: doc

call doc%parse(filename='case.xml')
print '(A)', doc%content('dt')

Feature map ​

AreaFeaturesWhere
Parsingstrings and files (read in chunks, larger than 2 GiB); one tokenizer for everything; tolerant: the first problem reported with its line (XML_MALFORMED), the document built anyway; prolog, comments, PIs and CDATA keptParsing
Queryingtags by name, path or parent; children, parent, level; attributes by name or listed; text with references decoded, CDATA literal, mixed contentQuerying
Typed valuescontents and attributes as integers (I1P…I8P), reals (R4P, R8P), logicals or lists; XML_NOT_FOUND, XML_BAD_VALUETyped values
Editingbuild in code (add_tag); edit by ID: content (text or numbers), attributes, names, insertion before or after a sibling, deletion; stringify, saveEditing
Writingxml_writer: streaming to a file, a unit or memory; layout, escaping, numbers and lists, binary blocks; only well-formed XML (names, attributes, text, one root element)Writing
Large filesxml_index: tags without content, contents on demand, byte ranges, scan stopped before raw dataThe index
Streamingxml_handler: your callbacks for each element, text and problem, in one pass over a source of any size; decoded text, balanced elements, stop_parsingStreaming parser
Namespacesprefix, local name, namespace of each tag; queries by {uri}local or with your own prefixesNamespaces
Regular expressionsfilter tags by name, content or attribute value with a compiled regex (StringiFor engine: Python re syntax without backreferences or lookaround), chained with any queryRegular expressions
Path selectorselect('//event[@type="x"]/origin[1]'): children, descendants, any name, attribute and regex predicates, positions; a malformed expression reported with its columnQuerying
EncodingsUTF-8, UTF-16, UTF-32, ISO-8859-1, windows-1252 and US-ASCII sources read (converted to UTF-8 as they are read, StringiFor engine); other encodings reported; output always UTF-8Parsing
Single tagsxml_tag: create, parse, add and delete attributes, write a start tag, content or end tagSingle tags
Every methodthe arguments of each type-bound procedure, in tablesMethods summary

Design ​

  • Pure Fortran 2008, no C bindings. The tokenizer, the lookups (find, find_all, matching) and the edits are pure; select (it compiles regexes), the typed getters and the I/O are not.
  • One parser: documents, files in chunks, the index, the streaming parser, single tags and attribute streams go through the same single-pass tokenizer, so they all accept, and report, the same things.
  • A flat DOM: an xml_file is an array of tags in document order, linked by IDs; no pointers, nothing to free by hand.
  • Faithful: tags, attributes, text, CDATA, comments and PIs are kept as read, so stringify writes an equivalent document; start tags are rewritten (double quotes, one space between attributes), element-only content is laid out again, the spaces around the text of a leaf tag are dropped. The accessors decode the stored text.
  • Linear: parsing and writing are O(n); find(parent=) and path segments walk the children lists; sources over 2 GiB are fine (64-bit positions).

Modules ​

ModuleHolds
foxythe public names (use only this one)
foxy_xml_filexml_file, the DOM
foxy_xml_indexxml_index, the index of a file
foxy_xml_eventsxml_handler, the streaming parser
foxy_xml_writerxml_writer, the streaming writer
foxy_xml_tagxml_tag, a single element
foxy_xml_sourcethe encoding of a source: detection, conversion to UTF-8
foxy_xml_tokenizerthe tokenizer, fed in pieces, driving a builder
foxy_xml_treethe queries shared by the DOM and the index
foxy_xml_valuesthe conversion of text to numbers and logicals
foxy_xml_entitiescharacter references, escaping, XML names

Compiler support ​

CompilerStatus
GNU gfortran 14, 16tested (CI: gfortran 14)
Intel ifx 2025.3tested (build with -heap-arrays)
NVIDIA nvfortran 26.5, 26.9tested (build with -D_NVF)

Limits ​

  • Entities defined by a DTD (e.g.  ) are not expanded: only the predefined and the numeric references are.
  • Undeclared namespace prefixes are not reported (their namespace is '').
  • Encodings other than UTF-8, UTF-16, UTF-32, ISO-8859-1, windows-1252 and US-ASCII are reported, then read as UTF-8; xml_index refuses UTF-16 and UTF-32 files (its positions are file bytes).
  • XPath only as the subset of select (/, //, *, [@k], [@k="v"], [@k~="re"], [n]): no axes, no functions, no boolean operators.
  • Regular expressions without backreferences or lookaround (StringiFor's engine, linear time).

Next: Parsing.