Skip to content

foxy_xml_tokenizer ​

FoXy XML tokenizer: a single pass, quotes-aware and resumable tokenizer driving a builder.

The tokenizer recognizes the markup in source order: start, self closing and end tags (any blank separates names and attributes, attribute values single or double quoted), CDATA sections, comments, processing instructions and declarations (e.g. DOCTYPE). It keeps the stack of the open tags (an end tag closes up to its matching start tag, inner open tags are closed implicitly, a stray end tag is ignored) and reports each token to a builder, which builds what it needs (e.g. the DOM of xml_file).

The source is fed in pieces (feed): each call processes the complete tokens of the piece and returns how many characters it consumed; the caller passes the rest again, followed by more characters. Character data, comments, CDATA sections and processing instructions are reported in pieces (a long one never has to fit in memory), tags and declarations whole. All positions are absolute (1 is the first character of the source).

Besides the tags structure, the problems reported (parsing goes on) are: invalid tag and attribute names, duplicate attributes, character data outside the root tag (blanks and a leading UTF-8 byte order mark excepted), a second root tag (XML 1.0 2.1: exactly one root element), a source without tags, ill-formed UTF-8 and malformed references in character data and attribute values. Each piece is checked for UTF-8 once, when it is fed; its first error is reported when the tokenizer reaches it, so that problems are always reported in the order they are met. A UTF-8 sequence or a reference split by the piece end is checked with the next piece.

Source: src/lib/foxy_xml_tokenizer.f90

Dependencies

Contents ​

Variables ​

NameTypeAttributesDescription
DATA_TEXTinteger(kind=I4P)parameterCharacter data.
DATA_CDATAinteger(kind=I4P)parameterCDATA section (markup included).
DATA_COMMENTinteger(kind=I4P)parameterComment (markup included).
DATA_PIinteger(kind=I4P)parameterProcessing instruction (markup included).
DATA_DECLARATIONinteger(kind=I4P)parameterDeclaration, e.g. DOCTYPE (markup included).
DATA_IGNOREDinteger(kind=I4P)parameterIgnored markup, e.g. a stray end tag.
INITIAL_DEPTHinteger(kind=I4P)parameterInitial capacity of the open tags stack, doubled when full.
LOOKAHEADinteger(kind=I8P)parameterCharacters needed to classify a markup (<![CDATA[).
BLANKScharacter(len=*)parameterXML blanks: space, tab, new line, CR.
NAME_ENDcharacter(len=*)parameterCharacters ending a tag or attribute name.
MAX_REFERENCE_CARRYinteger(kind=I8P)parameterLongest reference start carried to the next piece.
BOMcharacter(len=*)parameterUTF-8 byte order mark (checked byte by byte:

Derived Types ​

xml_builder ​

Builder driven by the tokenizer: one call per token (character data and similar in pieces).

Inheritance

Attributes: abstract

Components ​

NameTypeAttributesDescription
is_stoppedlogicalSet by the builder to stop the tokenizer (checked after each complete start or end tag).

Type-Bound Procedures ​

NameAttributesDescription
start_tagpass(self)A start tag begins.
attributepass(self)An attribute of the current start tag.
start_tag_endpass(self)The current start tag is complete.
end_tagpass(self)An open tag is closed by its end tag.
datapass(self)Character data or other markup.
problempass(self)A problem of malformed input.

open_tag ​

An open tag of the stack.

Components ​

NameTypeAttributesDescription
idinteger(kind=I4P)Tag ID.
startinteger(kind=I8P)Position of <.
open_endinteger(kind=I8P)Position of >.
namecharacter(len=:)allocatableTag name.

attribute_pair ​

An attribute of the current start tag.

Components ​

NameTypeAttributesDescription
namecharacter(len=:)allocatableAttribute name.
valuecharacter(len=:)allocatableAttribute value.

xml_tokenizer ​

Resumable tokenizer.

Components ​

NameTypeAttributesDescription
stacktype(open_tag)allocatableOpen tags.
depthinteger(kind=I4P)Number of open tags.
ntinteger(kind=I4P)Number of start tags.
open_kindinteger(kind=I4P)Kind of the comment/CDATA/PI continuing in the next piece, 0 if none.
open_startinteger(kind=I8P)Position of the comment/CDATA/PI continuing in the next piece.
is_donelogicalThe source is ended (or parsing is stopped).
is_outside_reportedlogicalCharacter data outside the root tags already reported.
is_root_seenlogicalA root tag has been started.
is_second_root_reportedlogicalA second root tag already reported.
utf8_checkedinteger(kind=I8P)Last position checked for UTF-8.
utf8_carrycharacter(len=:)allocatableBytes of a sequence split by the piece end, checked with the next.
utf8_errorinteger(kind=I8P)Position of the first ill-formed UTF-8 byte, 0 if none (yet).
utf8_bytecharacter(len=2)That byte, in hexadecimal.
is_utf8_reportedlogicalThe UTF-8 error has been reported.
ref_carrycharacter(len=:)allocatableStart of a reference split by the piece end (from its &).
ref_carry_posinteger(kind=I8P)Position of that &.
is_ref_reportedlogicalA malformed reference has been reported.
source_namecharacter(len=:)allocatableEncoding of the source if not UTF-8, for the messages.
is_convertedlogicalThe source is converted to UTF-8 (an FF byte is an invalid sequence).

Type-Bound Procedures ​

NameAttributesDescription
feedpass(self)Feed a piece of the source.
resetpass(self)Reset the tokenizer, ready for a new source.
set_sourcepass(self)Set the encoding of the source, for the messages.

Subroutines ​

feed ​

Feed a piece of the source: tokenize its complete tokens, reporting them to the builder.

@note The characters not consumed (an incomplete token at the end of the piece) must be passed again, followed by more characters; with is_last true the source ends with this piece and everything is consumed. Parsing stops at an unterminated markup of the source.

Attributes: pure

fortran
subroutine feed(self, chars, offset, is_last, builder, consumed)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.
charscharacter(len=*)inPiece of the source.
offsetinteger(kind=I8P)inPosition of the character before the piece (0 if first).
is_lastlogicalinThe source ends with this piece.
builderclass(xml_builder)inoutBuilder.
consumedinteger(kind=I8P)outNumber of characters consumed.

Call graph

reset ​

Reset the tokenizer, ready for a new source.

Attributes: elemental

fortran
subroutine reset(self)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.

report_markup ​

Report an open comment, CDATA section or PI up to its end, or up to the piece end if it continues in the next piece.

@note When the end is not in the piece, the last characters that may start the terminator are not consumed (never those before search_from, i.e. the opening markup). An unterminated markup is reported up to the source end.

Attributes: pure

fortran
subroutine report_markup(self, chars, offset, from, search_from, is_last, builder, pos, is_closed)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.
charscharacter(len=*)inPiece of the source.
offsetinteger(kind=I8P)inPosition of the character before the piece.
frominteger(kind=I8P)inFirst character to report.
search_frominteger(kind=I8P)inFirst character where the terminator is searched.
is_lastlogicalinThe source ends with this piece.
builderclass(xml_builder)inoutBuilder.
posinteger(kind=I8P)inoutPosition after the reported characters.
is_closedlogicaloutThe markup is closed: tokenizing goes on in this piece.

Call graph

add_attribute ​

Add an attribute to the list of the current start tag (values are double quoted: " escaped in single quoted ones).

Attributes: pure

fortran
subroutine add_attribute(attributes, na, name, value, quote)

Arguments

NameTypeIntentAttributesDescription
attributestype(attribute_pair)inoutallocatableAttributes.
nainteger(kind=I4P)inoutNumber of attributes.
namecharacter(len=*)inAttribute name.
valuecharacter(len=*)inAttribute value.
quotecharacter(len=1)inAttribute value quote.

Call graph

set_source ​

Set the encoding of the source (not UTF-8), for the messages of the invalid sequences: converted to UTF-8, an invalid sequence is the byte FF; read as UTF-8, a byte not UTF-8 is reported with the encoding.

Attributes: pure

fortran
subroutine set_source(self, name, is_converted)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.
namecharacter(len=*)inEncoding name.
is_convertedlogicalinThe source is converted to UTF-8.

Call graph

check_utf8 ​

Check for UTF-8 the bytes of a piece not checked yet (a piece may hold again the bytes not consumed before); the bytes of a sequence split by the piece end are kept, to be checked with the next piece. Only the first error is kept.

Attributes: pure

fortran
subroutine check_utf8(self, chars, offset, is_last)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.
charscharacter(len=*)inPiece of the source.
offsetinteger(kind=I8P)inPosition of the character before the piece.
is_lastlogicalinThe source ends with this piece.

Call graph

check_references ​

Check the references of a piece of character data; with is_open (the data continues in the next piece) a final reference without its ; is carried, to be checked with the continuation.

Attributes: pure

fortran
subroutine check_references(self, builder, chars, first, is_open)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.
builderclass(xml_builder)inoutBuilder.
charscharacter(len=*)inCharacter data.
firstinteger(kind=I8P)inPosition of the first character.
is_openlogicalinThe data continues in the next piece.

Call graph

close_reference ​

Check a carried reference whose character data ended (by markup or by the source end): it has no ;.

Attributes: pure

fortran
subroutine close_reference(self, builder, upto)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.
builderclass(xml_builder)inoutBuilder.
uptointeger(kind=I8P)inPosition reached by the tokenizer.

Call graph

flush_utf8 ​

Report the UTF-8 error, if any and not reported yet, when the tokenizer has reached its position.

Attributes: pure

fortran
subroutine flush_utf8(self, builder, upto)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.
builderclass(xml_builder)inoutBuilder.
uptointeger(kind=I8P)inPosition reached by the tokenizer.

Call graph

report ​

Report a problem found when the tokenizer has reached upto, after the UTF-8 error met before it (if any).

Attributes: pure

fortran
subroutine report(self, builder, upto, pos, message)

Arguments

NameTypeIntentAttributesDescription
selfclass(xml_tokenizer)inoutTokenizer.
builderclass(xml_builder)inoutBuilder.
uptointeger(kind=I8P)inPosition reached by the tokenizer.
posinteger(kind=I8P)inPosition of the problem.
messagecharacter(len=*)inProblem description.

Call graph

first_problem ​

Keep a problem only if it is the first one.

Attributes: pure

fortran
subroutine first_problem(problem, problem_pos, pos, message)

Arguments

NameTypeIntentAttributesDescription
problemcharacter(len=:)inoutallocatableFirst problem, unallocated if none yet.
problem_posinteger(kind=I8P)inoutPosition of the first problem.
posinteger(kind=I8P)inPosition of the problem.
messagecharacter(len=*)inProblem description.

Call graph

read_name ​

Read a (tag or attribute) name starting at pos, ended by a blank, /, >, = or the source end; pos is moved after the name.

Attributes: pure

fortran
subroutine read_name(source, pos, name)

Arguments

NameTypeIntentAttributesDescription
sourcecharacter(len=*)inSource.
posinteger(kind=I8P)inoutCurrent position.
namecharacter(len=:)outallocatableName, empty if none.

Call graph

skip_blanks ​

Move pos after the blanks (space, tab, new line, carriage return) starting at it.

Attributes: pure

fortran
subroutine skip_blanks(source, pos)

Arguments

NameTypeIntentAttributesDescription
sourcecharacter(len=*)inSource.
posinteger(kind=I8P)inoutCurrent position.

Call graph

Functions ​

located ​

Return a problem description prefixed by its line in the source.

Attributes: pure

Returns: character(len=:)

fortran
function located(source, pos, message) result(problem)

Arguments

NameTypeIntentAttributesDescription
sourcecharacter(len=*)inSource.
posinteger(kind=I8P)inPosition of the problem.
messagecharacter(len=*)inProblem description.

Call graph

located_in_file ​

Return a problem description prefixed by its line in a file (read again in chunks, counting the new lines; for a converted source, of the converted text).

Returns: character(len=:)

fortran
function located_in_file(filename, pos, message, chunk_size, encoding) result(problem)

Arguments

NameTypeIntentAttributesDescription
filenamecharacter(len=*)inFile name.
posinteger(kind=I8P)inPosition of the problem.
messagecharacter(len=*)inProblem description.
chunk_sizeinteger(kind=I8P)inSize of the chunks read from the file.
encodingtype(source_encoding)inoptionalEncoding of the file.

Call graph

reference_excerpt ​

Return the reference starting a text: up to its ;, or its first characters if it has none.

Attributes: pure

Returns: character(len=:)

fortran
function reference_excerpt(text) result(excerpt)

Arguments

NameTypeIntentAttributesDescription
textcharacter(len=*)inText starting with &.

Call graph

is_attribute_present ​

Return true if the current start tag has already an attribute named name.

Attributes: pure

Returns: logical

fortran
function is_attribute_present(attributes, na, name) result(is_present)

Arguments

NameTypeIntentAttributesDescription
attributestype(attribute_pair)inallocatableAttributes.
nainteger(kind=I4P)inNumber of attributes.
namecharacter(len=*)inAttribute name.

Call graph

is_data_outside ​

Return true if character data found outside the root tags is not only blanks (a byte order mark at the source start excepted).

Attributes: pure

Returns: logical

fortran
function is_data_outside(chars, first) result(is_outside)

Arguments

NameTypeIntentAttributesDescription
charscharacter(len=*)inCharacters.
firstinteger(kind=I8P)inPosition of the first character.

Call graph

after_declaration ​

Return the position after a <!...> declaration (e.g. DOCTYPE) starting at start, 0 if it is unterminated.

@note Quoted strings and the [...] internal subset may contain >.

Attributes: pure

Returns: integer(kind=I8P)

fortran
function after_declaration(source, start) result(after)

Arguments

NameTypeIntentAttributesDescription
sourcecharacter(len=*)inSource.
startinteger(kind=I8P)inDeclaration start (<) position.

Call graph

escaped_double_quotes ​

Return string with " replaced by &quot;.

Attributes: pure

Returns: character(len=:)

fortran
function escaped_double_quotes(string) result(escaped)

Arguments

NameTypeIntentAttributesDescription
stringcharacter(len=*)inString.

Call graph