english
version "1.0"

#: Copyright (c) 2005 by Wayne C. Gramlich.
#, All rights reserved.

module xml

#: This module implements an xml parsing library.

define xml				#: The front of a tag
    record
	attributes vector[xml_attribute] #: Attributes for tag
	between string			#: Chars between attributes and '>'
	content vector[xml]		#: Enclosed content
	end_tag xml			#: End tag (for a {start} tag)
	kind xml_kind			#: Kind of xml element
	name string			#: Tag name
	parent xml			#: Parent tag
	preceeding string		#: Characters preceeding '<'
    generate allocate, erase, identical, print

define xml_attribute			#: An XML attribute
    record
	name string			#: Attribute name
	name_preceeding string		#: White space preceeding name
	equals_preceeding string	#: White space preceeding equals
	quote character			#: Attribute quote character
	quote_preceeding string		#: White space preceeding quote
	value string			#: Attribute value
    generate allocate, erase, identical, print

define xml_document			#: XML document
    record
	prolog xml			#: Prolog (or ?? for none)
	preceeding_comments vector[xml]	#: Comments preceeding root
	root xml			#: Root tree
	trailing_comments vector[xml]	#: Trailing comments
	trailing string			#: Trailing white_space
    generate allocate, erase, print

define xml_kind
    enumeration
	comment				#: Comment: <!-- xxx -->
	empty				#: Empty element: <foo/>
	end				#: End element: ...</foo>)
	error				#: Error
	prolog				#: Prolog: <? ...?>
	start				#: Start (i.e. <foo> ...)
    generate equal, print, unsigned_convert

define xml_parse
    record
	index unsigned			#: Index of unparsed character
	line_number unsigned		#: Current line number
	source string			#: Source string to parse
	stack vector[xml]		#: Tag stack
	temporary string		#: Temporary string
    generate allocate, erase, print

define xml_parse1[type1]		#: Used for error messages
    record
	zilch unsigned
    generate print

define xml_parse2[type1, type2]		#: Used for error messages
    record
	zilch unsigned
    generate print



#: {xml} procedures:

procedure attribute_lookup@xml
    takes
	xml xml
	attribute_name string
    returns string

    #: This procedure will return the attribute value associated with
    #, {attribute_name} in the attributes of {xml}.  If {attribute_name}
    #, name is not found, an error message is printed and ??@{string}
    #, is returned.


procedure buffer_append@xml
    takes
	xml xml
	buffer string
    returns_nothing

    #: This procedure will append {xml} to {buffer}.


procedure parse@xml
    takes
	xml_parse xml_parse
    returns xml

    #: This procedure will parse an {xml} tree from {xml_parse} and return it.


#: {xml_attribute} procedures:

procedure buffer_append@xml_attribute
    takes
	xml_attribute xml_attribute
	buffer string
    returns_nothing


#: {xml_document} procedures:

procedure buffer_append@xml_document
    takes
	xml_document xml_document
	buffer string
    returns_nothing

    #: This procedure will append {xml_document} to {buffer}.


procedure file_parse@xml_document
    takes
	file_name string
    returns xml_document

    #: This procedure will open {file_name}, read it into memory,
    #, parse it into an {xml_document} object and return the result.
    #, Any errors are output to standard error.


procedure string_parse@xml_document
    takes
	source string
    returns xml_document

    #: This procedure will parse {source} into an {xml_document} and
    #, return it.


procedure parse@xml_document
    takes
	xml_parse xml_parse
    returns xml_document

    #: This procedure will parse and return an {xml_document} using
    #, {xml_parse}.


#: {xml_kind} procedures:

procedure string_convert@xml_kind
    takes
	xml_kind xml_kind
    returns string

    #: This procedure will convert {xml_kind} into a string.


#: {xml_parse} procedures:

procedure all_done@xml_parse
    takes
	xml_parse xml_parse
    returns_nothing

    #: This procedure will verify that all of the content in {xml_parse}
    #, has been parsed.


procedure at_xml_letter@xml_parse
    takes
	xml_parse xml_parse
    returns logical

    #: This procedure will return {true} if {xml_parse} is at a
    #, valid XML letter.


procedure attribute_parse@xml_parse
    takes
	xml_parse xml_parse
	indent unsigned
    returns xml_attribute

    #: This procedure will parse and attribute from {xml_parse} or return
    #, ?? if none is found.


procedure attributes_parse@xml_parse
    takes
	xml_parse xml_parse
	indent unsigned
    returns vector[xml_attribute]

    #: This procedure will parse a list of attributes from {xml_parse}
    #, and return it.


procedure character_match@xml_parse
    takes
	xml_parse xml_parse
	match_character character
	indent unsigned
    returns logical

    #: This procedure will return {true}@{logical} if the next character
    #, {xml_parse} matches {match_character}.  If so, the character is
    #, "read" and {true} is returned; otherwise, the character is not
    #, "read" and {false} is returned.


procedure comments_parse@xml_parse
    takes
	xml_parse xml_parse
    returns vector[xml]

    #: This procedure will parse a list of comments from {xml_parse}
    #, and return it.  If there are no comments, an empty list is returned.


procedure content_parse@xml_parse
    takes
	xml_parse xml_parse
    returns string

    #: This procedure will parse the content upto the next "<".


procedure create@xml_parse
    takes
	source string
    returns xml_parse

    #: This procedure will create and return a new {xml_parse} object.


procedure element_parse@xml_parse
    takes
	xml_parse xml_parse
	indent unsigned
    returns xml

    #: This procedure will parse an element from {xml_parse} and return it


procedure elements_parse@xml_parse
    takes
	xml_parse xml_parse
	indent unsigned
    returns vector[xml]

    #: This procedure will parse a list of elements.


procedure element_peek@xml_parse
    takes
	xml_parse xml_parse
	indent unsigned
    returns xml_kind

    #: This procedure will look forward in the parse stream
    #, and return the type of the next element tag.


procedure parse@xml_parse
    takes
	xml_parse xml_parse
	source string
    returns xml_document

    #: This procedure will parse {soruce} and return the corresponding
    #, {xml_document} object.


procedure prolog_parse@xml_parse
    takes
	xml_parse xml_parse
    returns xml

    #: This procedure will parse an XML prolog element from {xml_parse}
    #, or return ?? if none is present.


procedure symbol_parse@xml_parse
    takes
	xml_parse xml_parse
    returns string

    #: This procedure will parse a symbol from {xml_parse} and return it.


procedure white_space_parse@xml_parse
    takes
	xml_parse xml_parse
    returns string

    #: This procedure will parse a sequence of white space from
    #, {xml_parse} and return it.


#: {xml_parse1} procedures:

procedure error@xml_parse1[type1]
    takes
	xml_parse xml_parse
	format string
	type1 type1
    returns_nothing

    #: This procedure will print out an error message using {format} and
    #, {type1}.


procedure error@xml_parse2[type1, type2]
    takes
	xml_parse xml_parse
	format string
	type1 type1
	type2 type2
    returns_nothing

    #: This procedure will print out an error message using {format},
    #, {type1}, and {type2}.