Editing
Building a document
program build_document
use foxy
implicit none
type(xml_file) :: doc
integer(I4P) :: root, solver
call doc%add_tag(xml_tag(name='config'), id=root)
call doc%add_tag(xml_tag(name='dt', content='0.01', attributes_stream='unit="s"'), parent=root)
call doc%add_tag(xml_tag(name='solver', attributes_stream='kind="cg" tol="1e-6"'), parent=root, id=solver)
call doc%add_tag(xml_tag(name='restart', is_self_closing=.true.), parent=solver)
print '(A)', doc%stringify()
endprogram build_document$ build_document
<config>
<dt unit="s">0.01</dt>
<solver kind="cg" tol="1e-6">
<restart/>
</solver>
</config>add_tag(tag, [parent=], [id=]) appends an xml_tag as the last child of parent (one level deeper, indented two more spaces), or as a root tag without parent. Tags are appended, so the IDs of a built document follow the insertion order. With before= (or after=) the tag is inserted right before (after) a sibling, after its whole subtree for after: it takes that place in the document order and the following IDs are renumbered. id returns the new ID, 0 if the tag is not added: parent, before or after is not a tag, the sibling is not a child of parent, or both before and after are passed. See Single tags for xml_tag.
Editing by ID
time = case_file%find(path='case/time')
call case_file%set_content(id=case_file%find(name='steps', parent=time), value=1000_I4P) ! numbers as they read back
call case_file%set_attribute(id=case_file%find(name='dt', parent=time), name='unit', value='ms')
call case_file%set_content(id=case_file%find(name='dt', parent=time), value=0.5_R8P)
call case_file%delete_attribute(id=case_file%find(name='output'), name='every')
call case_file%delete_tag(name='notes') ! the tag and its subtree
call case_file%set_name(id=case_file%find(name='output'), name='results') ! rename
call case_file%add_tag(xml_tag(name='restart'), after=time, id=restart) ! right after <time>
call case_file%add_tag(xml_tag(name='from', content='results.xml'), parent=restart)
call case_file%add_tag(xml_tag(name='step', content='500'), parent=restart)| Method | Does |
|---|---|
set_content(id, content, [iostat=], [iomsg=]) | replaces the whole content of a tag with text: its children (with their subtrees) are deleted; a self-closing tag gets an end tag |
set_content(id, value | values, [fmt=], [iostat=], [iomsg=]) | the same with a number (I1P…I8P, R4P, R8P), a logical (true/false) or a rank-1 list (values separated by a space); reals are written with the shortest text that reads back exactly (StringiFor shortest), unless fmt formats them |
set_attribute(id, name, value | values, [fmt=], [iostat=], [iomsg=]) | adds the attribute (last) or replaces its value: text, a number, a logical or a list, as set_content |
delete_attribute(id, name, [iostat=], [iomsg=]) | deletes an attribute |
delete_tag([name=], [id=]) | deletes the first tag named name, or tag id, with its subtree |
set_name(id, name, [iostat=], [iomsg=]) | renames a tag; XML_MALFORMED if name is not an XML name |
free() | empties the document |
iostat is XML_NOT_FOUND for a tag or attribute that does not exist, XML_MALFORMED for an invalid attribute name, and XML_BAD_VALUE when fmt= cannot write the value (an invalid format, or a value that does not fit its field: asterisks); without it, errors are silent. IDs change with the structure: a deletion (delete_tag, set_content on a tag with children) or an insertion (before=, after=) renumbers the following tags, an append (parent=) takes the next free ID. Look IDs up again after a structural edit.
Escaping
set_attribute escapes the value: attribute() returns it as you passed it. set_content and xml_tag(content=) store the content as it is, since it may hold markup (a nested tag): escape text that is not markup with xml_escape.
program escape_text
use foxy
implicit none
type(xml_file) :: doc
character(len=:), allocatable :: user_text
user_text = 'p < 1 & "fast"'
call doc%add_tag(xml_tag(name='note', content=xml_escape(user_text))) ! contents are stored as they are
print '(A)', doc%stringify()
print '(A)', doc%content('note') ! read back decoded
endprogram escape_text$ escape_text
<note>p < 1 & "fast"</note>
p < 1 & "fast"Saving
call case_file%save(filename='restart.xml', iostat=iostat)| Method | Does |
|---|---|
stringify([linearize=]) | the document as a string: the prolog, then the tags laid out (mixed content kept inline); linearize=.true. lists the tags one by one, for debugging |
save(filename, [is_declared=], [iostat=], [iomsg=]) | writes the prolog, stringify() and a final new line to a file |
With is_declared=.true., save writes <?xml version="1.0"?> first, unless the prolog already starts with a declaration. iostat is the I/O error, or XML_MALFORMED for a document with more root tags (written anyway: XML allows one root, other readers reject it). Without iostat, an I/O error stops the program.
Next: Writing.