--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Interface for a list of XML attributes.
+module sax::attributes
+
+# Interface for a list of XML attributes.
+#
+# This interface allows access to a list of attributes in
+# three different ways:
+#
+# * by attribute index;
+# * by Namespace-qualified name; or
+# * by qualified (prefixed) name.
+#
+# The list will not contain attributes that were declared
+# `#IMPLIED` but not specified in the start tag. It will also not
+# contain attributes used as Namespace declarations (`xmlns*`) unless
+# the `http://xml.org/sax/features/namespace-prefixes`
+# feature is set to `true` (it is `false` by default).
+# Because SAX2 conforms to the "Namespaces in XML" specification,
+# it does not give namespace declaration attributes a namespace URI.
+# Some other W3C specifications are in conflict with that, expecting
+# these declarations to be in a namespace.
+# Handler code may need to resolve that conflict.
+#
+# If the namespace-prefixes feature (see above) is `false`,
+# access by qualified name may not be available; if the
+# `http://xml.org/sax/features/namespaces`
+# feature is `false`, access by Namespace-qualified names
+# may not be available.
+#
+# The order of attributes in the list is unspecified, and will
+# vary from implementation to implementation.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+#
+# SEE: `sax::helpers::AttributesImpl`
+#
+# SEE: `sax::ext::DeclHandler.attribute_decl`
+interface Attributes
+
+ # Return the number of attributes in the list.
+ fun length: Int is abstract
+
+ # Look up an attribute's Namespace URI by index.
+ #
+ # Parameters:
+ #
+ # * `index`: attribute index.
+ #
+ # Returns:
+ #
+ # The Namespace URI, or the empty string if none
+ # is available, or `null` if the index is out of
+ # range.
+ #
+ # SEE: `length`
+ fun uri(index: Int): nullable String is abstract
+
+ # Look up an attribute's local name by index.
+ #
+ # Parameters:
+ #
+ # * `index`: attribute index.
+ #
+ # Returns:
+ #
+ # The local name, or the empty string if Namespace
+ # processing is not being performed, or `null`
+ # if the index is out of range.
+ #
+ # SEE: `length`
+ fun local_name(index: Int): nullable String is abstract
+
+ # Look up an attribute's XML 1.0 qualified name by index.
+ #
+ # Parameters:
+ #
+ # * `index`: attribute index.
+ #
+ # Returns:
+ #
+ # The XML 1.0 qualified name, or the empty string
+ # if none is available, or `null` if the index
+ # is out of range.
+ #
+ # SEE: `length`
+ fun qname(index: Int): nullable String is abstract
+
+ # Look up an attribute's type by index.
+ #
+ # The attribute type is one of the strings `CDATA`, `ID`,
+ # `IDREF`, `IDREFS`, `NMTOKEN`, `NMTOKENS`, `ENTITY`, `ENTITIES`,
+ # or `NOTATION` (always in upper case).
+ #
+ # If the parser has not read a declaration for the attribute,
+ # or if the parser does not report attribute types, then it must
+ # return the value `CDATA` as stated in the XML 1.0 Recommentation
+ # (clause 3.3.3, "Attribute-Value Normalization").
+ #
+ # For an enumerated attribute that is not a notation, the
+ # parser will report the type as `NMTOKEN`.
+ #
+ # Parameters:
+ #
+ # * `index: Int`: attribute index.
+ # * `index: String`: XML 1.0 qualified (prefixed) name.
+ #
+ # Returns:
+ #
+ # The attribute's type as a string, or `null` if the specified
+ # attribute is not in the list or if qualified names
+ # are not available.
+ #
+ # SEE: `length`
+ fun type_of(index: Object): nullable String is abstract
+
+ # Look up an attribute's value by index.
+ #
+ # If the attribute value is a list of tokens (`IDREFS`,
+ # `ENTITIES`, or `NMTOKENS`), the tokens will be concatenated
+ # into a single string with each token separated by a
+ # single space.
+ #
+ # Parameters:
+ #
+ # * `index: Int`: attribute index.
+ # * `index: String`: XML 1.0 qualified (prefixed) name.
+ #
+ # Returns:
+ #
+ # The attribute's value as a string, or `null` if the specified
+ # attribute is not in the list or if qualified names
+ # are not available.
+ #
+ # SEE: `length`
+ fun value_of(index: Object): nullable String is abstract
+
+ # Look up the index of an attribute by Namespace name.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if
+ # the name has no Namespace URI.
+ # * `local_name`: attribute's local name.
+ #
+ # Returns:
+ #
+ # The index of the attribute, or -1 if it does not
+ # appear in the list.
+ fun index_ns(uri: String, local_name: String): Int is abstract
+
+ # Look up the index of an attribute by XML 1.0 qualified name.
+ #
+ # Parameters:
+ #
+ # * `qname`: XML 1.0 qualified (prefixed) name.
+ #
+ # Returns:
+ #
+ # The index of the attribute, or -1 if it does not
+ # appear in the list.
+ fun index_of(qname: String): Int is abstract
+
+ # Look up an attribute's type by Namespace name.
+ #
+ # See `type_of` for a description
+ # of the possible types.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if
+ # the name has no Namespace URI.
+ #
+ # * `local_name`: attribute's local name.
+ #
+ # Returns:
+ #
+ # The attribute type as a string, or `null` if the
+ # attribute is not in the list or if Namespace
+ # processing is not being performed.
+ fun type_ns(uri: String, local_name: String): nullable String is abstract
+
+ # Look up an attribute's value by Namespace name.
+ #
+ # See `value_of` for a description
+ # of the possible values.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if
+ # the name has no Namespace URI.
+ #
+ # * `local_name`: attribute's local name.
+ #
+ # Returns:
+ #
+ # The attribute value as a string, or `null` if the
+ # attribute is not in the list or if Namespace
+ # processing is not being performed.
+ fun value_ns(uri: String, local_name: String): nullable String is abstract
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Receives notification of the logical content of a document.
+module sax::content_handler
+
+import attributes
+import sax_locator
+
+# Receives notification of the logical content of a document.
+#
+# This is the main interface that most SAX applications
+# implement: if the application needs to be informed of basic parsing
+# events, it implements this interface and registers an instance with
+# the SAX parser using the `sax::XMLReader.content_handler`
+# attribute. The parser uses the instance to report
+# basic document-related events like the start and end of elements
+# and character data.
+#
+# The order of events in this interface is very important, and
+# mirrors the order of information in the document itself. For
+# example, all of an element's content (character data, processing
+# instructions, and/or subelements) will appear, in order, between
+# the startElement event and the corresponding endElement event.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+#
+# SEE: `sax::XMLReader`
+#
+# SEE: `sax::DTDHandler`
+#
+# SEE: `sax::ErrorHandler`
+abstract class ContentHandler
+
+ # Receive an object for locating the origin of SAX document events.
+ #
+ # SAX parsers are strongly encouraged (though not absolutely
+ # required) to supply a locator: if it does so, it must supply
+ # the locator to the application by invoking this method before
+ # invoking any of the other methods in the ContentHandler
+ # interface.
+ #
+ # The locator allows the application to determine the end
+ # position of any document-related event, even if the parser is
+ # not reporting an error. Typically, the application will
+ # use this information for reporting its own errors (such as
+ # character content that does not match an application's
+ # business rules). The information returned by the locator
+ # is probably not sufficient for use with a search engine.
+ #
+ # Note that the locator will return correct information only
+ # during the invocation of the events in this interface. The
+ # application should not attempt to use it at any other time.
+ #
+ # Parameter:
+ #
+ # * `locator`: object that can return the location of
+ # any SAX document event.
+ #
+ # SEE: `sax::SAXLocator`
+ fun document_locator=(locator: SAXLocator) do end
+
+
+ # Receive notification of the beginning of a document.
+ #
+ # The SAX parser will invoke this method only once, before any
+ # other event callbacks (except for `document_locator`).
+ #
+ # SEE: `end_document`
+ fun start_document do end
+
+
+ # Receive notification of the end of a document.
+ #
+ # The SAX parser will invoke this method only once, and it will
+ # be the last method invoked during the parse. The parser shall
+ # not invoke this method until it has either abandoned parsing
+ # (because of an unrecoverable error) or reached the end of
+ # input.
+ #
+ # SEE: `start_document`
+ fun end_document do end
+
+
+ # Begin the scope of a prefix-URI Namespace mapping.
+ #
+ # The information from this event is not necessary for
+ # normal Namespace processing: the SAX XML reader will
+ # automatically replace prefixes for element and attribute
+ # names when the `http://xml.org/sax/features/namespaces`
+ # feature is `true` (the default).
+ #
+ # There are cases, however, when applications need to
+ # use prefixes in character data or in attribute values,
+ # where they cannot safely be expanded automatically; the
+ # `start/end_prefix_mapping` event supplies the information
+ # to the application to expand prefixes in those contexts
+ # itself, if necessary.
+ #
+ # Note that `start/end_prefix_mapping` events are not
+ # guaranteed to be properly nested relative to each other:
+ # all `start/end_prefix_mapping` events will occur immediately before the
+ # corresponding `start_element` event,
+ # and all `end_prefix_mapping`
+ # events will occur immediately after the corresponding
+ # `end_element` event, but their order is not otherwise
+ # guaranteed.
+ #
+ # There should never be `start/end_prefix_mapping` events for the
+ # `xml` prefix, since it is predeclared and immutable.
+ #
+ # Parameters:
+ #
+ # * `prefix`: Namespace prefix being declared.
+ #An empty string is used for the default element namespace,
+ #which has no prefix.
+ # * `uri`: Namespace URI the prefix is mapped to.
+ #
+ # SEE: `end_prefix_mapping`
+ # SEE: `start_element`
+ fun start_prefix_mapping(prefix: String, uri: String) do end
+
+
+ # End the scope of a prefix-URI mapping.
+ #
+ # See `start_prefix_mapping` for
+ # details. These events will always occur immediately after the
+ # corresponding `end_prefix_mapping` event, but the order of
+ # `end_prefix_mapping` events is not otherwise
+ # guaranteed.
+ #
+ # Parameter:
+ #
+ # * `prefix`: prefix that was being mapping.
+ # This is the empty string when a default mapping scope ends.
+ #
+ # SEE: `start_prefix_mapping`
+ # SEE: `end_element`
+ fun end_prefix_mapping(prefix: String) do end
+
+ # Receive notification of the beginning of an element.
+ #
+ # The Parser will invoke this method at the beginning of every
+ # element in the XML document; there will be a corresponding
+ # `end_element` event for every startElement event
+ # (even when the element is empty). All of the element's content will be
+ # reported, in order, before the corresponding `end_element`
+ # event.
+ #
+ # This event allows up to three name components for each
+ # element:
+ #
+ # 1. the Namespace URI;
+ # 2. the local name; and
+ # 3. the qualified (prefixed) name.
+ #
+ # Any or all of these may be provided, depending on the
+ # values of the `http://xml.org/sax/features/namespaces`
+ # and the `http://xml.org/sax/features/namespace-prefixes`
+ # properties:
+ #
+ # * the Namespace URI and local name are required when
+ # the namespaces property is `true` (the default), and are
+ # optional when the namespaces property is `false` (if one is
+ # specified, both must be);
+ # * the qualified name is required when the namespace-prefixes property
+ # is `true`, and is optional when the namespace-prefixes property
+ # is `false` (the default).
+ #
+ # Note that the attribute list provided will contain only
+ # attributes with explicit values (specified or defaulted):
+ # `#IMPLIED` attributes will be omitted. The attribute list
+ # will contain attributes used for Namespace declarations
+ # (`xmlns*` attributes) only if the
+ # `http://xml.org/sax/features/namespace-prefixes`
+ # property is true (it is `false` by default, and support for a
+ # `true` value is optional).
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if the
+ # element has no Namespace URI or if Namespace
+ # processing is not being performed.
+ # * `localName`: local name (without prefix), or the
+ # empty string if Namespace processing is not being
+ # performed.
+ # * `qname`: The qualified XML 1.0 name (with prefix), or the
+ # empty string if qualified names are not available.
+ # * `atts`: attributes attached to the element.
+ #
+ # SEE: `end_element`
+ # SEE: `sax::Attributes`
+ fun start_element(uri: String, local_name: String, qname: String,
+ atts: Attributes) do end
+
+ # Receive notification of the end of an element.
+ #
+ # The SAX parser will invoke this method at the end of every
+ # element in the XML document; there will be a corresponding
+ # `start_element` event for every `end_element`
+ # event (even when the element is empty).
+ #
+ # For information on the names, see `start_element`.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if the
+ # element has no Namespace URI or if Namespace
+ # processing is not being performed.
+ # * `localName`: local name (without prefix), or the
+ # empty string if Namespace processing is not being
+ # performed.
+ # * `qname`: The qualified XML 1.0 name (with prefix), or the
+ # empty string if qualified names are not available.
+ fun end_element(uri: String, local_name: String, qname: String) do end
+
+ # Receive notification of character data.
+ #
+ # The Parser will call this method to report each chunk of
+ # character data. SAX parsers may return all contiguous character
+ # data in a single chunk, or they may split it into several
+ # chunks; however, all of the characters in any single event
+ # must come from the same external entity so that the `SAXLocator`
+ # provides useful information.
+ #
+ # Note that some parsers will report whitespace in element
+ # content using the `ignorable_whitespace`
+ # method rather than this one (validating parsers *must* do so).
+ #
+ # Parameter:
+ #
+ # * `str`: characters from the XML document.
+ #
+ # SEE: `ignorable_whitespace`
+ # SEE: `sax::SAXLocator`
+ fun characters(str: String) do end
+
+ # Receive notification of ignorable whitespace in element content.
+ #
+ # Validating Parsers must use this method to report each chunk
+ # of whitespace in element content (see the W3C XML 1.0 recommendation,
+ # section 2.10): non-validating parsers may also use this method
+ # if they are capable of parsing and using content models.
+ #
+ # SAX parsers may return all contiguous whitespace in a single
+ # chunk, or they may split it into several chunks; however, all of
+ # the characters in any single event must come from the same
+ # external entity, so that the `SAXLocator` provides useful
+ # information.
+ #
+ # Parameter:
+ #
+ # * `str`: characters from the XML document.
+ #
+ # SEE: `characters`
+ fun ignorable_whitespace(str: String) do end
+
+ # Receive notification of a processing instruction.
+ #
+ # The Parser will invoke this method once for each processing
+ # instruction found: note that processing instructions may occur
+ # before or after the main document element.
+ #
+ # A SAX parser must never report an XML declaration (XML 1.0,
+ # section 2.8) or a text declaration (XML 1.0, section 4.3.1)
+ # using this method.
+ #
+ # Parameters:
+ #
+ # * `target`: processing instruction target.
+ # * `data`: processing instruction data, or `null` if
+ # none was supplied. The data does not include any
+ # whitespace separating it from the target.
+ fun processing_instruction(target: String, data: nullable String) do end
+
+ # Receive notification of a skipped entity.
+ #
+ # This is not called for entity references within markup constructs
+ # such as element start tags or markup declarations. (The XML
+ # recommendation requires reporting skipped external entities.
+ # SAX also reports internal entity expansion/non-expansion, except
+ # within markup constructs.)
+ #
+ # The Parser will invoke this method each time the entity is
+ # skipped. Non-validating processors may skip entities if they
+ # have not seen the declarations (because, for example, the
+ # entity was declared in an external DTD subset). All processors
+ # may skip external entities, depending on the values of the
+ # `http://xml.org/sax/features/external-general-entities`
+ # and the
+ # `http://xml.org/sax/features/external-parameter-entities`
+ # properties.
+ #
+ # Parameter:
+ #
+ # * `name`: The name of the skipped entity. If it is a
+ # parameter entity, the name will begin with `%`, and if
+ # it is the external DTD subset, it will be the string
+ # `[dtd]`.
+ fun skipped_entity(name: String) do end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Receives notification of basic DTD-related events.
+module sax::dtd_handler
+
+# Receives notification of basic DTD-related events.
+#
+# If a SAX application needs information about notations and
+# unparsed entities, then the application implements this
+# interface and registers an instance with the SAX parser using
+# the parser's `dtd_handler` property. The parser uses the
+# instance to report notation and unparsed entity declarations to
+# the application.
+#
+# Note that this interface includes only those DTD events that
+# the XML recommendation *requires* processors to report:
+# notation and unparsed entity declarations.
+#
+# The SAX parser may report these events in any order, regardless
+# of the order in which the notations and unparsed entities were
+# declared; however, all DTD events must be reported after the
+# document handler's `start_document` event, and before the first
+# `start_element` event.
+# (If the `sax::ext::LexicalHandler` is
+# used, these events must also be reported before the `end_dtd` event.)
+#
+# It is up to the application to store the information for
+# future use (perhaps in a hash table or object tree).
+# If the application encounters attributes of type `NOTATION`,
+# `ENTITY`, or `ENTITIES`, it can use the information that it
+# obtained through this interface to find the entity and/or
+# notation corresponding with the attribute value.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+#
+# SEE: `sax::XMLReader.dtd_handler`
+abstract class DTDHandler
+
+ # Receive notification of a notation declaration event.
+ #
+ # It is up to the application to record the notation for later
+ # reference, if necessary;
+ # notations may appear as attribute values and in unparsed entity
+ # declarations, and are sometime used with processing instruction
+ # target names.
+ #
+ # At least one of `public_id` and `system_id` must be non-null.
+ # If a system identifier is present, and it is a URL, the SAX
+ # parser must resolve it fully before passing it to the
+ # application through this event.
+ #
+ # There is no guarantee that the notation declaration will be
+ # reported before any unparsed entities that use it.
+ #
+ # Parameters:
+ #
+ # * `name`: notation name.
+ # * `public_id`: notation's public identifier, or null if none was given.
+ # * `system_id`: notation's system identifier, or null if none was given.
+ #
+ # SEE: `sax::Attributes`
+ fun notation_decl(name: String, public_id: String, system_id: String) do end
+
+ # Receive notification of an unparsed entity declaration event.
+ #
+ # Note that the notation name corresponds to a notation
+ # reported by the `notation_decl` event.
+ # It is up to the application to record the entity for later
+ # reference, if necessary;
+ # unparsed entities may appear as attribute values.
+ #
+ # If the system identifier is a URL, the parser must resolve it
+ # fully before passing it to the application.
+ #
+ # Parameters:
+ #
+ # * `name`: unparsed entity's name.
+ # * `public_id`: entity's public identifier, or null if none was given.
+ # * `system_id`: entity's system identifier, or null if none was given.
+ #
+ # SEE: `sax::Attributes`
+ fun unparsed_entity_decl(name: String, public_id: String,
+ system_id: String) do end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Basic interface for resolving entities.
+module sax::entity_resolver
+
+import input_source
+
+# Basic interface for resolving entities.
+#
+# If a SAX application needs to implement customized handling
+# for external entities, it must implement this interface and
+# register an instance with the SAX driver using the
+# `sax::XMLReader.entity_resolver` property.
+#
+# The XML reader will then allow the application to intercept any
+# external entities (including the external DTD subset and external
+# parameter entities, if any) before including them.
+#
+# Many SAX applications will not need to implement this interface,
+# but it will be especially useful for applications that build
+# XML documents from databases or other specialised input sources,
+# or for applications that use URI types other than URLs.
+#
+# The application can also use this interface to redirect system
+# identifiers to local URIs or to look up replacements in a catalog
+# (possibly by using the public identifier).
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+#
+# SEE: `sax::XMLReader.entity_resolver`
+#
+# SEE: `sax::InputSource`
+abstract class EntityResolver
+
+ # Allow the application to resolve external entities.
+ #
+ # The parser will call this method before opening any external
+ # entity except the top-level document entity. Such entities include
+ # the external DTD subset and external parameter entities referenced
+ # within the DTD (in either case, only if the parser reads external
+ # parameter entities), and external general entities referenced
+ # within the document element (if the parser reads external general
+ # entities). The application may request that the parser locate
+ # the entity itself, that it use an alternative URI, or that it
+ # use data provided by the application (as a character or byte
+ # input stream).
+ #
+ # Application writers can use this method to redirect external
+ # system identifiers to secure and/or local URIs, to look up
+ # public identifiers in a catalogue, or to read an entity from a
+ # database or other input source (including, for example, a dialog
+ # box). Neither XML nor SAX specifies a preferred policy for using
+ # public or system IDs to resolve resources. However, SAX specifies
+ # how to interpret any InputSource returned by this method, and that
+ # if none is returned, then the system ID will be dereferenced as
+ # a URL.
+ #
+ # If the system identifier is a URL, the SAX parser must
+ # resolve it fully before reporting it to the application.
+ #
+ # Parameters:
+ #
+ # * `public_id`: public identifier of the external entity
+ # being referenced, or `null` if none was supplied.
+ # * `system_id`: system identifier of the external entity
+ # being referenced.
+ #
+ # Returns:
+ #
+ # An `InputSource` object describing the new input source,
+ # or `null` to request that the parser open a regular
+ # URI connection to the system identifier.
+ fun resolve_entity(public_id: nullable String, system_id: nullable String):
+ nullable InputSource do
+ return null
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Basic interface for SAX error handlers.
+module sax::error_handler
+
+import sax_parse_exception
+
+# Basic interface for SAX error handlers.
+#
+# If a SAX application needs to implement customized error
+# handling, it must implement this interface and then register an
+# instance with the XML reader using the `sax::XMLReader.error_handler
+# property. The parser will then report all errors and warnings
+# through this interface.
+#
+# **WARNING:** If an application does *not* register an `ErrorHandler`,
+# XML parsing errors will go unreported and bizarre behaviour may result.
+#
+# For XML processing errors, a SAX driver must use this interface
+# instead of throwing an exception: it is up to the application
+# to decide whether to throw an exception for different types of
+# errors and warnings. Note, however, that there is no requirement that
+# the parser continue to provide useful information after a call to
+# `fatal_error` (in other words, a SAX driver class
+# could catch an exception and report a `fatal_error`).
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+#
+# SEE: `sax::XMLReader.error_handler`
+abstract class ErrorHandler
+
+ # Receive notification of a warning.
+ #
+ # SAX parsers will use this method to report conditions that
+ # are not errors or fatal errors as defined by the XML 1.0
+ # recommendation. The default behaviour is to take no action.
+ #
+ # The SAX parser must continue to provide normal parsing events
+ # after invoking this method: it should still be possible for the
+ # application to process the document through to the end.
+ #
+ # Filters may use this method to report other, non-XML warnings
+ # as well.
+ #
+ # Parameter:
+ #
+ # * `exception`: warning information encapsulated in a SAX parse
+ # exception.
+ fun warning(exception: SAXParseException) do end
+
+ # Receive notification of a recoverable error.
+ #
+ # This corresponds to the definition of "error" in section 1.2
+ # of the W3C XML 1.0 Recommendation. For example, a validating
+ # parser would use this callback to report the violation of a
+ # validity constraint. The default behaviour is to take no
+ # action.
+ #
+ # The SAX parser must continue to provide normal parsing events
+ # after invoking this method: it should still be possible for the
+ # application to process the document through to the end. If the
+ # application cannot do so, then the parser should report a fatal
+ # error even if the XML 1.0 recommendation does not require it to
+ # do so.
+ #
+ # Filters may use this method to report other, non-XML errors
+ # as well.
+ #
+ # Parameter:
+ #
+ # * `exception`: error information encapsulated in a SAX parse
+ # exception.
+ fun error(exception: SAXParseException) do end
+
+ # Receive notification of a non-recoverable error.
+ #
+ # This corresponds to the definition of "fatal error" in
+ # section 1.2 of the W3C XML 1.0 Recommendation. For example, a
+ # parser would use this callback to report the violation of a
+ # well-formedness constraint.
+ #
+ # The application must assume that the document is unusable
+ # after the parser has invoked this method, and should continue
+ # (if at all) only for the sake of collecting additional error
+ # messages: in fact, SAX parsers are free to stop reporting any
+ # other events once this method has been invoked.
+ #
+ # Parameter:
+ #
+ # * `exception`: error information encapsulated in a SAX parse
+ # exception.
+ fun fatal_error(exception: SAXParseException) do
+ exception.throw
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# SAX2 extension handler for DTD declaration events.
+module sax::ext::decl_handler
+
+# SAX2 extension handler for DTD declaration events.
+#
+# This is an optional extension handler for SAX2 to provide more
+# complete information about DTD declarations in an XML document.
+# XML readers are not required to recognize this handler, and it
+# is not part of core-only SAX2 distributions.
+#
+# Note that data-related DTD declarations (unparsed entities and
+# notations) are already reported through the `DTDHandler` interface.
+#
+# If you are using the declaration handler together with a lexical
+# handler, all of the events will occur between the `start_dtd` and the
+# `end_dtd` events.
+#
+# To set the `DeclHandler` for an XML reader, use the
+# `set_property` method with the property name
+# `http://xml.org/sax/properties/declaration-handler`
+# and an object implementing this interface (or `null`) as the value.
+abstract class DeclHandler
+ # Report an element type declaration.
+ #
+ # The content model will consist of the string `EMPTY`, the
+ # string `ANY`, or a parenthesised group, optionally followed
+ # by an occurrence indicator. The model will be normalized so
+ # that all parameter entities are fully resolved and all whitespace
+ # is removed,and will include the enclosing parentheses. Other
+ # normalization (such as removing redundant parentheses or
+ # simplifying occurrence indicators) is at the discretion of the
+ # parser.
+ #
+ # Parameters:
+ #
+ # * `name`: element type name.
+ # * `model`: content model as a normalized string.
+ fun element_decl(name: String, model: String) do end
+
+ # Report an attribute type declaration.
+ #
+ # Only the effective (first) declaration for an attribute will
+ # be reported. The type will be one of the strings `CDATA`,
+ # `ID`, `IDREF`, `IDREFS`, `NMTOKEN`, `NMTOKENS`, `ENTITY`,
+ # `ENTITIES`, a parenthesized token group with
+ # the separator `|` and all whitespace removed, or the word
+ # `NOTATION` followed by a space followed by a parenthesized
+ # token group with all whitespace removed.
+ #
+ # The value will be the value as reported to applications,
+ # appropriately normalized and with entity and character
+ # references expanded.
+ #
+ # Parameters:
+ #
+ # * `element_name`: name of the associated element.
+ # * `attribute_name`: name of the attribute.
+ # * `attribute_type`: string representing the attribute type.
+ # * `mode`: string representing the attribute defaulting mode (`#IMPLIED`,
+ # `#REQUIRED`, or `#FIXED`) or `null` if none of these applies.
+ # * `value`: string representing the attribute's default value,
+ # or `null` if there is none.
+ fun attribute_decl(element_name: String,
+ attribute_name: String,
+ attribute_type: String,
+ mode: nullable String,
+ value: nullable String) do end
+
+ # Report an internal entity declaration.
+ #
+ # Only the effective (first) declaration for each entity
+ # will be reported. All parameter entities in the value
+ # will be expanded, but general entities will not.
+ #
+ # Parameters:
+ #
+ # * `name`: name of the entity. If it is a parameter entity, the name will
+ # begin with `%`.
+ # * `value`: replacement text of the entity.
+ #
+ # SEE: `external_entity_decl`
+ #
+ # SEE: `sax::DTDHandler.unparsed_entity_decl`
+ fun internal_entity_decl(name: String, value: String) do end
+
+ # Report a parsed external entity declaration.
+ #
+ # Only the effective (first) declaration for each entity
+ # will be reported.
+ #
+ # Parameters:
+ #
+ # * `name`: name of the entity. If it is a parameter entity, the name will
+ # begin with `%`.
+ # * `public_id`: declared public identifier of the entity, or `null` if
+ # none was declared.
+ # * `system_id`: declared system identifier of the entity.
+ #
+ # SEE: `internal_entity_decl`
+ #
+ # SEE: `sax::DTDHandler.unparsed_entity_decl`
+ fun external_entity_decl(name: String, value: String) do end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Interfaces to optional SAX2 handlers.
+#
+# See [http://www.saxproject.org](http://www.saxproject.org)
+# for more information about SAX.
+#
+# The package is independent of the SAX2 core, though the functionality
+# exposed generally needs to be implemented within a parser.
+# That independence has several consequences:
+#
+# * SAX2 drivers are *not* required to recognize these handlers,
+# and you cannot assume that the class files will be present in every SAX2
+# installation.
+#
+# * This package may be updated independently of SAX2 (i.e. new
+# handlers may be added without updating SAX2 itself).
+#
+# * The handlers are not implemented by the SAX2
+# `org.xml.sax.helpers.XMLFilterImpl` class.
+# You can subclass these if you need such behaviour.
+#
+# * The handlers need to be registered differently than regular SAX2
+# handlers.
+#
+# This package, SAX2-ext, is a standardized extension to SAX2. It is
+# designed both to allow SAX parsers to pass certain types of information
+# to applications, and to serve as a simple model for other SAX2 parser
+# extension packages. Not all such extension packages should need to
+# be recognized directly by parsers, however.
+# As an example, most schema systems can be cleanly layered on top
+# of parsers supporting the standardized SAX2 interfaces.
+#
+# Note: this package alone does add any
+# functionality; it simply provides optional interfaces for SAX2 drivers
+# to use. You must use a SAX2 driver that recognizes these interfaces if
+# you actually want to have access to lexical and declaration
+# information.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+module sax::ext
+
+import sax
+import decl_handler
+import lexical_handler
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# SAX2 extension handler for lexical events.
+module sax::ext::lexical_handler
+
+# SAX2 extension handler for lexical events.
+#
+#
+# This is an optional extension handler for SAX2 to provide
+# lexical information about an XML document, such as comments
+# and `CDATA` section boundaries.
+# XML readers are not required to recognize this handler, and it
+# is not part of core-only SAX2 distributions.
+#
+# The events in the lexical handler apply to the entire document,
+# not just to the document element, and all lexical handler events
+# must appear between the content handler's startDocument and
+# endDocument events.
+#
+# To set the LexicalHandler for an XML reader, use the
+# `setProperty` method
+# with the property name
+# `http://xml.org/sax/properties/lexical-handler`
+# and an object implementing this interface (or `null`) as the value.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+abstract class LexicalHandler
+
+ # Report the start of DTD declarations, if any.
+ #
+ # This method is intended to report the beginning of the
+ # `DOCTYPE` declaration; if the document has no `DOCTYPE` declaration,
+ # this method will not be invoked.
+ #
+ # All declarations reported through `DTDHandler` or `DeclHandler` events
+ # must appear between the `start_dtd` and `end_dtd` events.
+ # Declarations are assumed to belong to the internal DTD subset
+ # unless they appear between `start_entity` and `end_entity` events.
+ # Comments and processing instructions from the DTD should also be reported
+ # between the `start_dtd` and `end_dtd` events, in their original
+ # order of (logical) occurrence; they are not required to
+ # appear in their correct locations relative to `DTDHandler`
+ # or `DeclHandler` events, however.
+ #
+ # Note that the `start_dtd`/`end_dtd` events will appear within
+ # the `start_document` and `end_document` events from `ContentHandler` and
+ # before the first `start_element` event.
+ #
+ # Parameters:
+ #
+ # * `name`: document type name.
+ # * `public_id`: declared public identifier for the
+ # external DTD subset, or `null` if none was declared.
+ # * `system_id`: declared system identifier for the
+ # external DTD subset, or `null` if none was declared.
+ # (Note that this is not resolved against the document
+ # base URI.)
+ #
+ # SEE: `end_dtd`
+ #
+ # SEE: `start_entity`
+ fun start_dtd(name: String, public_id: nullable String,
+ system_id: nullable String) do end
+
+ # Report the end of DTD declarations.
+ #
+ # This method is intended to report the end of the
+ # `DOCTYPE` declaration; if the document has no `DOCTYPE` declaration,
+ # this method will not be invoked.
+ #
+ # SEE: `start_dtd`
+ fun end_dtd do end
+
+ # Report the beginning of some internal and external XML entities.
+ #
+ # The reporting of parameter entities (including
+ # the external DTD subset) is optional, and SAX2 drivers that
+ # report `LexicalHandler` events may not implement it; you can use the
+ # `http://xml.org/sax/features/lexical-handler/parameter-entities`
+ # feature to query or control the reporting of parameter entities.
+ #
+ # General entities are reported with their regular names,
+ # parameter entities have `%` prepended to their names, and
+ # the external DTD subset has the pseudo-entity name `[dtd]`.
+ #
+ # When a SAX2 driver is providing these events, all other
+ # events must be properly nested within start/end entity
+ # events. There is no additional requirement that events from
+ # `DeclHandler` or `org.xml.sax.DTDHandler DTDHandler` be properly ordered.
+ #
+ # Note that skipped entities will be reported through the
+ # `skippedEntity` event, which is part of the `ContentHandler` interface.
+ #
+ # Because of the streaming event model that SAX uses, some
+ # entity boundaries cannot be reported under any
+ # circumstances:
+ #
+ # * general entities within attribute values
+ # * parameter entities within declarations
+ #
+ # These will be silently expanded, with no indication of where
+ # the original entity boundaries were.
+ #
+ # Note also that the boundaries of character references (which
+ # are not really entities anyway) are not reported.
+ #
+ # All `start_entity` and `end_entity` events must be properly nested.
+ #
+ # Parameter:
+ #
+ # * `name`: name of the entity. If it is a parameter
+ # entity, the name will begin with `%`, and if it is the
+ # external DTD subset, it will be `[dtd]`.
+ #
+ # SEE: `end_entity`
+ #
+ # SEE: `sax::ext::DeclHandler.internal_entity_decl`
+ #
+ # SEE: `sax::ext::DeclHandler.external_entity_decl`
+ fun start_entity(name: String) do end
+
+ # Report the end of an entity.
+ #
+ # * `name`: name of the entity that is ending.
+ #
+ # SEE: `start_entity`
+ fun end_entity(name: String) do end
+
+ # Report the start of a `CDATA` section.
+ #
+ # The contents of the `CDATA` section will be reported through
+ # the regular `characters` event; this event is intended only to report
+ # the boundary.
+ #
+ # SEE: `end_cdata`
+ fun start_cdata do end
+
+ # Report the end of a CDATA section.
+ #
+ # SEE: `start_cdata`
+ fun end_cdata do end
+
+ # Report an XML comment anywhere in the document.
+ #
+ # This callback will be used for comments inside or outside the
+ # document element, including comments in the external DTD
+ # subset (if read). Comments in the DTD must be properly
+ # nested inside `start/end_dtd` and `start/end_entity` events (if
+ # used).
+ #
+ # Parameters:
+ #
+ # * `str`: characters in the comment.
+ fun comment(str: String) do end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Default implementation of the Attributes interface.
+module sax::attributes_impl
+
+import sax::attributes
+
+# Default implementation of the Attributes interface.
+#
+# This class provides a default implementation of the SAX2
+# `Attributes` interface, with the addition of manipulators so that the list
+# can be modified or reused.
+#
+# There are two typical uses of this class:
+#
+# * to take a persistent snapshot of an Attributes object in a `start_element`
+# event; or
+# * to construct or modify an Attributes object in a SAX2 driver or filter.
+#
+# Note: The original source code and documentation of this class comes, in part,
+# from [SAX 2.0](http://www.saxproject.org).
+class AttributesImpl
+ super Attributes
+
+ private var data: Array[String] = new Array[String]
+ redef var length: Int = 0
+
+ redef fun uri(index: Int): nullable String do
+ if index >= 0 and index < length then
+ return data[index * 5]
+ else
+ return null
+ end
+ end
+
+ redef fun local_name(index: Int): nullable String do
+ if index >= 0 and index < length then
+ return data[index * 5 + 1]
+ else
+ return null
+ end
+ end
+
+ redef fun qname(index: Int): nullable String do
+ if index >= 0 and index < length then
+ return data[index * 5 + 2]
+ else
+ return null
+ end
+ end
+
+ # Look up an attribute's type by index.
+ #
+ # The attribute type is one of the strings `CDATA`, `ID`,
+ # `IDREF`, `IDREFS`, `NMTOKEN`, `NMTOKENS`, `ENTITY`, `ENTITIES`,
+ # or `NOTATION` (always in upper case).
+ #
+ # If the parser has not read a declaration for the attribute,
+ # or if the parser does not report attribute types, then it must
+ # return the value `CDATA` as stated in the XML 1.0 Recommentation
+ # (clause 3.3.3, "Attribute-Value Normalization").
+ #
+ # For an enumerated attribute that is not a notation, the
+ # parser will report the type as `NMTOKEN`.
+ #
+ # Parameters:
+ #
+ # * `index: Int`: attribute index.
+ # * `index: String`: XML 1.0 qualified (prefixed) name.
+ # In many cases, it will be more efficient to look up the name once and
+ # query by `Int` index rather than quering by name repeatedly.
+ #
+ # Returns:
+ #
+ # The attribute's type as a string, or `null` if the specified
+ # attribute is not in the list or if qualified names
+ # are not available.
+ #
+ # SEE: `length`
+ redef fun type_of(index): nullable String do
+ if index isa Int then
+ if index >= 0 and index < length then
+ return data[index * 5 + 3]
+ end
+ else if index isa String and "" != index then
+ var i: Int = 0
+
+ while i < data.length do
+ if data[i + 2] == index then
+ return data[i + 3]
+ end
+ i += 5
+ end
+ end
+ return null
+ end
+
+ # Look up an attribute's value by index.
+ #
+ # If the attribute value is a list of tokens (`IDREFS`,
+ # `ENTITIES`, or `NMTOKENS`), the tokens will be concatenated
+ # into a single string with each token separated by a
+ # single space.
+ #
+ # Parameters:
+ #
+ # * `index: Int`: attribute index.
+ # * `index: String`: XML 1.0 qualified (prefixed) name.
+ # In many cases, it will be more efficient to look up the name once and
+ # query by `Int` index rather than quering by name repeatedly.
+ #
+ # Returns:
+ #
+ # The attribute's value as a string, or `null` if the specified
+ # attribute is not in the list or if qualified names
+ # are not available.
+ #
+ # SEE: `length`
+ redef fun value_of(index): nullable String do
+ if index isa Int then
+ if index >= 0 and index < length then
+ return data[index * 5 + 4]
+ end
+ else if index isa String and "" != index then
+ var i: Int = 0
+
+ while i < data.length do
+ if data[i + 2] == index then
+ return data[i + 4]
+ end
+ i += 5
+ end
+ end
+ return null
+ end
+
+ # Look up the index of an attribute by Namespace name.
+ #
+ # In many cases, it will be more efficient to look up the name once and
+ # query by `Int` index rather than quering by name repeatedly.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if
+ # the name has no Namespace URI.
+ # * `local_name`: attribute's local name.
+ #
+ # Returns:
+ #
+ # The index of the attribute, or -1 if it does not
+ # appear in the list.
+ redef fun index_ns(uri: String, local_name: String): Int do
+ var i: Int = 0
+
+ if "" != local_name then
+ while i < data.length do
+ if data[i] == uri and data[i + 1] == local_name then
+ return i / 5
+ end
+ i += 5
+ end
+ end
+ return -1
+ end
+
+ # Look up the index of an attribute by XML 1.0 qualified name.
+ #
+ # In many cases, it will be more efficient to look up the name once and
+ # query by `Int` index rather than quering by name repeatedly.
+ #
+ # Parameters:
+ #
+ # * `qname`: XML 1.0 qualified (prefixed) name.
+ #
+ # Returns:
+ #
+ # The index of the attribute, or -1 if it does not
+ # appear in the list.
+ redef fun index_of(qname: String): Int do
+ var i: Int = 0
+
+ if "" != qname then
+ while i < data.length do
+ if data[i + 2] == qname then
+ return i / 5
+ end
+ i += 5
+ end
+ end
+ return -1
+ end
+
+ # Look up an attribute's type by Namespace name.
+ #
+ # In many cases, it will be more efficient to look up the name once and
+ # query by `Int` index rather than quering by name repeatedly.
+ #
+ # See `type_of` for a description
+ # of the possible types.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if
+ # the name has no Namespace URI.
+ #
+ # * `local_name`: attribute's local name.
+ #
+ # Returns:
+ #
+ # The attribute type as a string, or `null` if the
+ # attribute is not in the list or if Namespace
+ # processing is not being performed.
+ redef fun type_ns(uri: String, local_name: String): nullable String do
+ var i: Int = 0
+
+ if "" != local_name then
+ while i < data.length do
+ if data[i] == uri and data[i + 1] == local_name then
+ return data[i + 3]
+ end
+ i += 5
+ end
+ end
+ return null
+ end
+
+ # Look up an attribute's value by Namespace name.
+ #
+ # In many cases, it will be more efficient to look up the name once and
+ # query by `Int` index rather than quering by name repeatedly.
+ #
+ # See `value_of` for a description
+ # of the possible values.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if
+ # the name has no Namespace URI.
+ #
+ # * `local_name`: attribute's local name.
+ #
+ # Returns:
+ #
+ # The attribute value as a string, or `null` if the
+ # attribute is not in the list or if Namespace
+ # processing is not being performed.
+ redef fun value_ns(uri: String, local_name: String): nullable String do
+ var i: Int = 0
+
+ if "" != local_name then
+ while i < data.length do
+ if data[i] == uri and data[i + 1] == local_name then
+ return data[i + 4]
+ end
+ i += 5
+ end
+ end
+ return null
+ end
+
+ # Clear the attribute list for reuse.
+ fun clear do
+ data.clear
+ length = 0
+ end
+
+ # Copy an entire Attributes object.
+ #
+ # It may be more efficient to reuse an existing object
+ # rather than constantly allocating new ones.
+ #
+ # Parameters:
+ #
+ # * `atts`: attributes to copy.
+ fun attributes=(atts: Attributes) do
+ var i: Int = 0
+
+ clear
+ length = atts.length
+ data.enlarge(length * 5)
+ while i < length do
+ data.push(atts.uri(i).as(not null))
+ data.push(atts.local_name(i).as(not null))
+ data.push(atts.qname(i).as(not null))
+ data.push(atts.type_of(i).as(not null))
+ data.push(atts.value_of(i).as(not null))
+ i += 1
+ end
+ end
+
+ # Add an attribute to the end of the list.
+ #
+ # For the sake of speed, this method does no checking
+ # to see if the attribute is already in the list: that is
+ # the responsibility of the application.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI, or the empty string if
+ # none is available or Namespace processing is not being performed.
+ # * `local_name`: local name, or the empty string if
+ # Namespace processing is not being performed.
+ # * `qname`: qualified (prefixed) name, or the empty string
+ # if qualified names are not available.
+ # * `attribute_type`: attribute type as a string.
+ # * `value`: attribute value.
+ fun add(uri: String, local_name: String, qname: String,
+ attribute_type: String, value: String) do
+ ensure_capacity(length + 1)
+ data.push(uri)
+ data.push(local_name)
+ data.push(qname)
+ data.push(attribute_type)
+ data.push(value)
+ length += 1
+ end
+
+ # Set an attribute in the list.
+ #
+ # For the sake of speed, this method does no checking
+ # for name conflicts or well-formedness: such checks are the
+ # responsibility of the application.
+ #
+ # Parameters:
+ #
+ # * `index`: index of the attribute (zero-based).
+ # * `uri`: Namespace URI, or the empty string if
+ # none is available or Namespace processing is not being performed.
+ # * `local_name`: local name, or the empty string if
+ # Namespace processing is not being performed.
+ # * `qname`: qualified (prefixed) name, or the empty string
+ # if qualified names are not available.
+ # * `attribute_type`: attribute type as a string.
+ # * `value`: attribute value.
+ fun set(index: Int, uri: String, local_name: String, qname: String,
+ attribute_type: String, value: String) do
+ assert index_in_bounds: index >= 0 and index < length
+ data[index * 5] = uri
+ data[index * 5 + 1] = local_name
+ data[index * 5 + 2] = qname
+ data[index * 5 + 3] = attribute_type
+ data[index * 5 + 4] = value
+ end
+
+ # Remove an attribute from the list.
+ #
+ # Parameters:
+ #
+ # * `index`: index of the attribute (zero-based).
+ fun remove_at(index: Int) do
+ assert index_in_bounds: index >= 0 and index < length
+ index = index * 5
+ for i in [1..5] do
+ data.remove_at(index)
+ end
+ length -= 1
+ end
+
+ # Set the Namespace URI of a specific attribute.
+ #
+ # Parameters:
+ #
+ # * `index`: index of the attribute (zero-based).
+ # * `uri`: attribute's Namespace URI, or the empty string for none.
+ fun uri=(index: Int, uri: String) do
+ assert index_in_bounds: index >= 0 and index < length
+ data[index * 5] = uri
+ end
+
+ # Set the local name of a specific attribute.
+ #
+ # Parameters:
+ #
+ # * `index`: index of the attribute (zero-based).
+ # * `local_name`: attribute's local name, or the empty string for none.
+ fun local_name=(index: Int, local_name: String) do
+ assert index_in_bounds: index >= 0 and index < length
+ data[index * 5 + 1] = local_name
+ end
+
+ # Set the qualified name of a specific attribute.
+ #
+ # Parameters:
+ #
+ # * `index`: index of the attribute (zero-based).
+ # * `qname`: attribute's qualified name, or the empty string for none.
+ fun qname=(index: Int, qname: String) do
+ assert index_in_bounds: index >= 0 and index < length
+ data[index * 5 + 2] = qname
+ end
+
+ # Set the type of a specific attribute.
+ #
+ # Parameters:
+ #
+ # * `index`: index of the attribute (zero-based).
+ # * `attribute_type`: attribute's type.
+ fun type_of=(index: Int, attribute_type: String) do
+ assert index_in_bounds: index >= 0 and index < length
+ data[index * 5 + 3] = attribute_type
+ end
+
+ # Set the value of a specific attribute.
+ #
+ # Parameters:
+ #
+ # * `index`: index of the attribute (zero-based).
+ # * `value`: attribute's value.
+ fun value_of=(index: Int, value: String) do
+ assert index_in_bounds: index >= 0 and index < length
+ data[index * 5 + 4] = value
+ end
+
+ # Ensure the internal array's capacity.
+ #
+ # Parameters:
+ #
+ # * `n`: minimum number of attributes that the array must be able to hold.
+ private fun ensure_capacity(n: Int) do
+ data.enlarge(n * 5)
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Contains "helper" classes, including support for bootstrapping SAX-based applications.
+#
+# See [http://www.saxproject.org](http://www.saxproject.org)
+# for more information about SAX.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+module sax::helpers
+
+import sax
+import attributes_impl
+import namespace_support
+import sax_locator_impl
+import xml_filter_impl
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Encapsulates Namespace logic for use by applications using SAX, or internally by SAX drivers.
+module sax::helpers::namespace_support
+
+# Encapsulates Namespace logic for use by applications using SAX, or internally by SAX drivers.
+#
+# This class encapsulates the logic of Namespace processing:
+# it tracks the declarations currently in force for each context
+# and automatically processes qualified XML names into their
+# Namespace parts; it can also be used in reverse for generating
+# XML qualified names from Namespaces.
+#
+# Namespace support objects are reusable, but the reset method
+# must be invoked between each session.
+#
+# Here is a simple session:
+#
+# var parts: Array[String] = new Array[String].with_capacity(3)
+# var support = new NamespaceSupport
+# #
+# support.push_context
+# support.declare_prefix("", "http://www.w3.org/1999/xhtml")
+# support.declare_prefix("dc", "http://www.purl.org/dc#")
+# #
+# parts = support.process_name("p", parts, false).as(not null)
+# assert parts[0] == "http://www.w3.org/1999/xhtml"
+# assert parts[1] == "p"
+# assert parts[2] == "p"
+# #
+# parts = support.process_name("dc:title", parts, false).as(not null)
+# assert parts[0] == "http://www.purl.org/dc#"
+# assert parts[1] == "title"
+# assert parts[2] == "dc:title"
+# #
+# support.pop_context
+#
+# Note that this class is optimized for the use case where most
+# elements do not contain Namespace declarations: if the same
+# prefix/URI mapping is repeated for each context (for example), this
+# class will be somewhat less efficient.
+#
+# Although SAX drivers (parsers) may choose to use this class to
+# implement namespace handling, they are not required to do so.
+# Applications must track namespace information themselves if they
+# want to use namespace information.
+#
+# Note: The original source code and documentation of this class comes, in part,
+# from [SAX 2.0](http://www.saxproject.org).
+class NamespaceSupport
+ # The XML Namespace URI as a constant.
+ #
+ # The value is `http://www.w3.org/XML/1998/namespace`
+ # as defined in the “Namespaces in XML” specification.
+ #
+ # This is the Namespace URI that is automatically mapped
+ # to the `xml` prefix.
+ var xmlns = "http://www.w3.org/XML/1998/namespace"
+
+ # The namespace declaration URI as a constant.
+ #
+ # The value is `http://www.w3.org/xmlns/2000/`, as defined
+ # in a erratum to the “Namespaces in XML” recommendation.
+ #
+ # This is the Namespace URI that is automatically mapped
+ # to the `xmlns` prefix.
+ var nsdecl = "http://www.w3.org/xmlns/2000/"
+
+ private var contexts: Array[Context] = new Array[Context].with_capacity(32)
+ private var current_context: Context = new Context
+ private var context_position: Int = 0
+
+ init do
+ contexts.push(current_context)
+ current_context.declare_prefix("xml", xmlns)
+ current_context.declare_prefix("xmlns", nsdecl)
+ end
+
+ # Reset this Namespace support object for reuse.
+ #
+ # It is necessary to invoke this method before reusing the
+ # Namespace support object for a new session.
+ fun reset do
+ contexts.clear
+ contexts.enlarge(32)
+ context_position = 0
+ current_context = new Context
+ contexts.push(current_context)
+ current_context.declare_prefix("xml", xmlns)
+ current_context.declare_prefix("xmlns", nsdecl)
+ end
+
+ # Start a new Namespace context.
+ #
+ # The new context will automatically inherit
+ # the declarations of its parent context, but it will also keep
+ # track of which declarations were made within this context.
+ #
+ # Event callback code should start a new context once per element.
+ # This means being ready to call this in either of two places.
+ # For elements that don't include namespace declarations, the
+ # `ContentHandler.start_element` callback is the right place.
+ # For elements with such a declaration, it'd done in the first
+ # `ContentHandler.start_prefix_mapping` callback.
+ # A boolean flag can be used to
+ # track whether a context has been started yet. When either of
+ # those methods is called, it checks the flag to see if a new context
+ # needs to be started. If so, it starts the context and sets the
+ # flag. After `ContentHandler.start_element` does that, it always clears
+ # the flag.
+ #
+ # Normally, SAX drivers would push a new context at the beginning
+ # of each XML element. Then they perform a first pass over the
+ # attributes to process all namespace declarations, making
+ # `ContentHandler.start_prefix_mapping` callbacks.
+ # Then a second pass is made, to determine the namespace-qualified
+ # names for all attributes and for the element name.
+ # Finally all the information for the
+ # `ContentHandler.start_element` callback is available,
+ # so it can then be made.
+ #
+ # The Namespace support object always starts with a base context
+ # already in force: in this context, only the `xml` prefix is
+ # declared.
+ #
+ # SEE: `sax::ContentHandler`
+ #
+ # SEE: `pop_context`
+ fun push_context do
+ current_context.decls_ok = false
+ context_position += 1
+
+ # Extend the array if necessary.
+ if context_position >= contexts.length then
+ current_context = new Context
+ contexts.push(current_context)
+ else
+ current_context = contexts[context_position]
+ end
+
+ # Set the parent, if any.
+ if context_position > 0 then
+ current_context.parent = contexts[context_position - 1]
+ end
+ end
+
+ # Revert to the previous Namespace context.
+ #
+ # Normally, you should pop the context at the end of each
+ # XML element. After popping the context, all Namespace prefix
+ # mappings that were previously in force are restored.
+ #
+ # You must not attempt to declare additional Namespace
+ # prefixes after popping a context, unless you push another
+ # context first.
+ #
+ # SEE: `push_context`
+ fun pop_context do
+ assert stack_not_empty: context_position > 0
+ current_context.clear
+ context_position -= 1
+ current_context = contexts[context_position]
+ end
+
+ # Declare a Namespace prefix.
+ #
+ # All prefixes must be declared before they are referenced.
+ # For example, a SAX driver (parser)
+ # would scan an element's attributes
+ # in two passes: first for namespace declarations,
+ # then a second pass using `process_name` to
+ # interpret prefixes against (potentially redefined) prefixes.
+ #
+ # This method declares a prefix in the current Namespace
+ # context; the prefix will remain in force until this context
+ # is popped, unless it is shadowed in a descendant context.
+ #
+ # To declare the default element Namespace, use the empty string as
+ # the prefix.
+ #
+ # Note that you must *not* declare a prefix after
+ # you've pushed and popped another Namespace context, or
+ # treated the declarations phase as complete by processing
+ # a prefixed name.
+ #
+ # Note that there is an asymmetry in this library:
+ # `prefix` will not return the `""` prefix,
+ # even if you have declared a default element namespace.
+ # To check for a default namespace,
+ # you have to look it up explicitly using `uri`.
+ # This asymmetry exists to make it easier to look up prefixes
+ # for attribute names, where the default prefix is not allowed.
+ #
+ # Parameters:
+ #
+ # * `prefix`: prefix to declare, or the empty string to
+ # indicate the default element namespace. This may never have
+ # the value `xml` or `xmlns`.
+ # * `uri`: The Namespace URI to associate with the prefix.
+ #
+ #
+ # Returns:
+ #
+ # `true` if the prefix and the URI are legal, `false` otherwise.
+ #
+ # SEE: `process_name`
+ #
+ # SEE: `uri`
+ #
+ # SEE: `prefix`
+ fun declare_prefix(prefix: String, uri: String): Bool do
+ if prefix == "xml" or prefix == "xmlns" or
+ uri == xmlns or uri == nsdecl then
+ return false
+ else
+ current_context.declare_prefix(prefix, uri)
+ return true
+ end
+ end
+
+ # Process a raw XML qualified name, after all declarations in the current context have been handled by `declare_prefix`.
+ #
+ # This method processes a raw XML qualified name in the current
+ # context by removing the prefix and looking it up among the
+ # prefixes currently declared. The return value will be the
+ # array supplied by the caller, filled in as follows:
+ #
+ # * `parts[0]`: Namespace URI, or an empty string if none is in use.
+ # * `parts[1]`: local name (without prefix).
+ # * `parts[2]`: original raw name.
+ #
+ # If the raw name has a prefix that has not been declared, then
+ # the return value will be `null`.
+ #
+ # Note that attribute names are processed differently than
+ # element names: an unprefixed element name will receive the
+ # default Namespace (if any), while an unprefixed attribute name
+ # will not.
+ #
+ # Parameters:
+ #
+ # * `qname`: raw XML qualified name to be processed.
+ # * `parts`: array supplied by the caller. Will be enlarged to 3 elements if
+ # needed. If the specified array contains more than 3 elements, its length
+ # will be kept intact.
+ # * `is_attribute`: flag indicating whether this is an attribute name
+ # (`true`) or an element name (`false`).
+ #
+ # SEE: `declare_prefix`
+ fun process_name(qname: String, parts: Array[String], is_attribute: Bool):
+ nullable Array[String] do
+ var my_parts = current_context.process_name(qname, is_attribute)
+
+ if my_parts == null then
+ return null
+ else
+ parts[0] = my_parts[0]
+ parts[1] = my_parts[1]
+ parts[2] = my_parts[2]
+ if parts[0] == "" and qname == "xmlns" and is_attribute then
+ parts[0] = nsdecl
+ parts[1] = ""
+ end
+ return parts
+ end
+ end
+
+ # Look up a prefix and get the currently-mapped Namespace URI.
+ #
+ # This method looks up the prefix in the current context.
+ # Use the empty string (`""`) for the default Namespace.
+ #
+ # Parameters:
+ #
+ # * `prefix`: The prefix to look up.
+ #
+ # Returns:
+ #
+ # The associated Namespace URI, or `null` if the prefix
+ # is undeclared in this context.
+ #
+ # SEE: `prefix`
+ #
+ # SEE: `prefixes_of`
+ fun uri(prefix: String): nullable String do
+ return current_context.uri(prefix)
+ end
+
+ # Return all prefixes currently declared.
+ #
+ # Note: if there is a default prefix, it will not be
+ # returned in this enumeration; check for the default prefix
+ # using the `uri` with an argument of `""` or use `declared_prefixes`.
+ #
+ # Returns:
+ #
+ # All prefixes declared in the current context except
+ # for the empty (default) prefix.
+ #
+ # SEE: `declared_prefixes`
+ #
+ # SEE: `uri`
+ fun prefixes: Collection[String] do return current_context.prefixes
+
+ # Return one of the prefixes mapped to a Namespace URI.
+ #
+ # If more than one prefix is currently mapped to the same
+ # URI, this method will make an arbitrary selection; if you
+ # want all of the prefixes, use the `prefixes_of` method instead.
+ #
+ # Note: this will never return the empty (default) prefix;
+ # to check for a default prefix, use the `uri`
+ # method with an argument of `""`.
+ #
+ # Parameters:
+ #
+ # * `uri`: Namespace URI.
+ #
+ # Returns:
+ #
+ # One of the prefixes currently mapped to the URI supplied,
+ # or `null` if none is mapped or if the URI is assigned to
+ # the default Namespace.
+ #
+ # SEE: `prefixes_of`
+ #
+ # SEE: `uri`
+ fun prefix(uri: String): nullable String do
+ return current_context.prefix(uri)
+ end
+
+ # Return all prefixes currently declared for an URI.
+ #
+ # This method returns prefixes mapped to a specific Namespace
+ # URI. The `xml` prefix will be included. If you want only one
+ # prefix that's mapped to the Namespace URI, and you don't care
+ # which one you get, use the `prefix` method instead.
+ #
+ # Note: the empty (default) prefix is *never* included
+ # in this enumeration; to check for the presence of a default
+ # Namespace, use the `uri` method with an argument of `""`.
+ #
+ # Parameters:
+ #
+ # * `uri`: The Namespace URI.
+ #
+ # SEE: `prefix`
+ #
+ # SEE: `declared_prefixes`
+ #
+ # SEE: `uri`
+ fun prefixes_of(uri: String): Collection[String] do
+ var prefixes = new Array[String]
+ var all_prefixes = self.prefixes
+
+ for prefix in all_prefixes do
+ if uri == self.uri(prefix) then
+ prefixes.push(prefix)
+ end
+ end
+ return prefixes
+ end
+
+ # Return all prefixes declared (and undeclared) in this context.
+ #
+ # The empty (default) prefix will be included in this
+ # enumeration; note that this behaviour differs from that of
+ # `prefix`, `prefixes` and `prefixes_of`.
+ #
+ # SEE: `prefixes`
+ #
+ # SEE: `uri`
+ fun declared_prefixes: Collection[String] do
+ return current_context.declared_prefixes
+ end
+end
+
+
+# Internal class for a single Namespace context.
+#
+# This module caches and reuses Namespace contexts,
+# so the number allocated
+# will be equal to the element depth of the document, not to the total
+# number of elements (i.e. 5-10 rather than tens of thousands).
+# Also, data structures used to represent contexts are shared when
+# possible (child contexts without declarations) to further reduce
+# the amount of memory that's consumed.
+#
+# Note: The original source code and documentation of this class comes, in part,
+# from [SAX 2.0](http://www.saxproject.org).
+private class Context
+
+ private var empty: Collection[String] = new Array[String].with_capacity(0)
+
+ # `prefix` -> `uri`
+ private var prefix_table: nullable Map[String, String] = null
+
+ # Cache of `process_name` for elements.
+ #
+ # `qname -> [uri, local_name, qname]`
+ private var element_name_table: nullable Map[String, Array[String]] = null
+
+ # Cache of `process_name` for attributes.
+ #
+ # `qname -> [uri, local_name, qname]`
+ private var attribute_name_table: nullable Map[String, Array[String]] = null
+
+ # Namespace in absence of prefix.
+ private var default_ns: nullable String = null
+
+ # Can we currently declare prefixes in this context?
+ var decls_ok: Bool = true is writable
+
+ # All prefixes declared in this context.
+ private var declarations: nullable Array[String] = null
+
+ # Was `copy_tables` called since the last call to `parent=`?
+ private var decl_seen: Bool = false
+
+ # Parent context.
+ private var p_parent: nullable Context = null
+
+ init do
+ end
+
+ # (Re)set the parent of this Namespace context.
+ #
+ # The context must either have been freshly constructed,
+ # or must have been cleared.
+ #
+ # Parameters:
+ #
+ # * `context`: parent Namespace context object.
+ fun parent=(parent: Context) do
+ p_parent = parent
+ declarations = null
+ prefix_table = parent.prefix_table
+ element_name_table = parent.element_name_table
+ attribute_name_table = parent.attribute_name_table
+ default_ns = parent.default_ns
+ decl_seen = false
+ decls_ok = true
+ end
+
+ # Makes associated state become collectible, invalidating this context.
+ #
+ # `parent=` must be called before this context may be used again.
+ fun clear do
+ p_parent = null
+ prefix_table = null
+ element_name_table = null
+ attribute_name_table = null
+ default_ns = null
+ declarations = null
+ end
+
+ # Declare a Namespace prefix for this context.
+ #
+ # Parameters:
+ #
+ # * `prefix`: prefix to declare.
+ # * `uri`: associated Namespace URI.
+ #
+ # SEE: `NamespaceSupport.declare_prefix`
+ fun declare_prefix(prefix: String, uri: String) do
+ assert legal_state: decls_ok else
+ sys.stderr.write("Can't declare any more prefixes in this context.\n")
+ end
+
+ # Lazy processing...
+ if not decl_seen then
+ copy_tables
+ end
+
+ if "" == prefix then
+ if "" == uri then
+ default_ns = null
+ else
+ default_ns = uri
+ end
+ else if "" == uri then
+ prefix_table.keys.remove(prefix)
+ else
+ prefix_table[prefix] = uri
+ end
+ declarations.push(prefix)
+ end
+
+ # Process a raw XML qualified name in this context.
+ #
+ # Parameters:
+ #
+ # * `qname`: raw XML qualified name.
+ # * `is_attribute`: `true` if this is an attribute name.
+ #
+ # Returns:
+ #
+ # An array of three strings containing the URI part (or empty string),
+ # the local part and the raw name, or `null` if there is an undeclared
+ # prefix.
+ #
+ # SEE: `NamespaceSupport.process_name`
+ fun process_name(qname: String, is_attribute: Bool):
+ nullable Array[String] do
+ var name: Array[String]
+ var table: Map[String, Array[String]]
+ var match: nullable Match
+
+ # Detect errors in call sequence.
+ decls_ok = false
+ # Select the appropriate table.
+ if is_attribute then
+ table = attribute_name_table.as(not null)
+ else
+ table = element_name_table.as(not null)
+ end
+
+ # Start by looking in the cache, and
+ # return immediately if the name
+ # is already known in this content.
+ if table.keys.has(qname) then
+ return table[qname]
+ end
+
+ # We haven't seen this name in this
+ # context before. Maybe in the parent
+ # context, but we can't assume prefix
+ # bindings are the same.
+ name = new Array[String].with_capacity(3)
+ match = qname.search(':')
+
+ if match == null then
+ # No prefix
+ if is_attribute then
+ name.push("")
+ else
+ name.push(default_ns or else "")
+ end
+ name.push(qname)
+ name.push(qname)
+ else
+ # Prefix
+ var prefix = qname.substring(0, match.from)
+
+ if prefix == "" then
+ if is_attribute then
+ name.push("")
+ else
+ name.push(default_ns or else "")
+ end
+ name.push(qname.substring_from(match.after))
+ name.push(qname)
+ else if (not is_attribute) and "xmlns" == prefix then
+ return null
+ else if prefix_table.keys.has(prefix) then
+ name.push(prefix_table[prefix])
+ name.push(qname.substring_from(match.after))
+ name.push(qname)
+ else
+ return null
+ end
+ end
+
+ # Save in the cache for future use.
+ # (Could be shared with parent context...)
+ table[qname] = name
+ return name
+ end
+
+ # Look up the URI associated with a prefix in this context.
+ #
+ # Return `null` if no URI is associated with a specified prefix.
+ #
+ # Parameters:
+ #
+ # * `prefix`: prefix to look up.
+ #
+ # SEE: `NamespaceSupport.uri`
+ fun uri(prefix: String): nullable String do
+ if "" == prefix then
+ return default_ns
+ else if prefix_table == null then
+ return null
+ else
+ return prefix_table.get_or_null(prefix)
+ end
+ end
+
+ # Look up one of the prefixes associated with a URI in this context.
+ #
+ # Since many prefixes may be mapped to the same URI,
+ # the return value may be unreliable.
+ #
+ # Parameters:
+ #
+ # * `uri`: URI to look up.
+ #
+ # Returns:
+ #
+ # The associated prefix, or `null` if none is declared.
+ #
+ # SEE: `NamespaceSupport.prefix`
+ fun prefix(uri: String): nullable String do
+ # Note: We do not use the original code from SAX 2.0.1 because it is
+ # buggy with redefined prefixes. For example, with
+ # `<x xmlns:y="1"><z xmlns:y="2" /></x>`, when in `z`, `uri("1")`
+ # returns `"y"` in the original code while it should return `null`.
+ # Our code is slower, but it works.
+ var all_prefixes = prefixes
+
+ for prefix in all_prefixes do
+ if uri == self.uri(prefix) then
+ return prefix
+ end
+ end
+ return null
+ end
+
+ # Return all prefixes declared in this context (possibly empty).
+ #
+ # SEE: `NamespaceSupport.declared_prefixes`
+ fun declared_prefixes: Collection[String] do
+ return declarations or else empty
+ end
+
+ # Return all prefixes currently in force.
+ #
+ # The default prefix, if in force, is *not*
+ # returned, and will have to be checked for separately.
+ #
+ # SEE: `NamespaceSupport.prefixes`
+ fun prefixes: Collection[String] do
+ if prefix_table == null then
+ return empty
+ else
+ return prefix_table.keys
+ end
+ end
+
+ # Copy on write for the internal tables in this context.
+ #
+ # This class is optimized for the normal case where most
+ # elements do not contain Namespace declarations.
+ private fun copy_tables do
+ if prefix_table != null then
+ var old_prefix_table = prefix_table.as(not null)
+ prefix_table = new HashMap[String, String]
+ prefix_table.recover_with(old_prefix_table)
+ else
+ prefix_table = new HashMap[String, String]
+ end
+ element_name_table = new HashMap[String, Array[String]]
+ attribute_name_table = new HashMap[String, Array[String]]
+ declarations = new Array[String]
+ decl_seen = true
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Provides an optional convenience implementation of `Locator`.
+module sax::helpers::sax_locator_impl
+
+import sax::sax_locator
+
+# Provides an optional convenience implementation of `Locator`.
+#
+# This class is available mainly for application writers, who
+# can use it to make a persistent snapshot of a locator at any
+# point during a document parse:
+#
+# module example
+# #
+# import sax::helpers::SAXLocatorImpl
+# import sax::ContentHandler
+# #
+# class Example super ContentHandler
+# private var _locator: nullable SAXLocator = null
+# private var start_loc: nullable SAXLocator = null
+# #
+# fun locator=(Locator locator) do
+# # note the locator
+# _locator = locator
+# end
+# #
+# fun start_document do
+# # save the location of the start of the document
+# # for future use.
+# start_loc = new SAXLocatorImpl.from(locator)
+# end
+# end
+#
+# Normally, parser writers will not use this class, since it
+# is more efficient to provide location information only when
+# requested, rather than constantly updating a `Locator` object.
+#
+# Note: The original source code and documentation of this class comes, in part,
+# from [SAX 2.0](http://www.saxproject.org).
+class SAXLocatorImpl super SAXLocator
+ redef var public_id: nullable String = null is writable
+ redef var system_id: nullable String = null is writable
+ redef var line_number: Int = -1 is writable
+ redef var column_number: Int = -1 is writable
+
+ # Zero-argument constructor.
+ #
+ # This will not normally be useful, since the main purpose
+ # of this class is to make a snapshot of an existing Locator.
+ init do
+ end
+
+ # Copy constructor.
+ #
+ # Create a persistent copy of the current state of a locator.
+ # When the original locator changes, this copy will still keep
+ # the original values (and it can be used outside the scope of
+ # `ContentHandler` methods).
+ #
+ # Parameters:
+ #
+ # * `locator`: locator to copy.
+ init with(locator: SAXLocator) do
+ public_id = locator.public_id
+ system_id = locator.system_id
+ line_number = locator.line_number
+ column_number = locator.column_number
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Test suite for `attributes_impl`.
+module test_attributes_impl is test_suite
+
+import test_suite
+import sax::helpers::attributes_impl
+
+class TestAttributesImpl
+ super TestSuite
+
+ private fun sample: AttributesImpl do
+ var subject: AttributesImpl = new AttributesImpl
+
+ # The parser may include everything...
+ subject.add("http://example.com/", "bar", "foo:bar", "CDATA", "baz")
+ # ... or omit the `qname`...
+ subject.add("urn:is:not:often:used", "i-am_ME", "", "ID", "noop")
+ # ... or retrieve an attribute with an empty value (that *must* be kept intact)...
+ subject.add("http://www.w3.org/XML/1998/namespace", "lang", "xml:lang",
+ "NMTOKEN", "")
+ # ... or omit to process the namespace.
+ subject.add("", "", "xml:space", "NMTOKEN", "default")
+ return subject
+ end
+
+ fun test_length do
+ var subject: AttributesImpl = new AttributesImpl
+
+ assert 0 == subject.length
+ subject.add("http://example.com/", "bar", "foo:bar", "CDATA", "baz")
+ assert 1 == subject.length
+ subject.add("http://example.com/", "bar", "foo:bar", "CDATA", "baz")
+ assert 2 == subject.length
+ subject.clear
+ assert 0 == subject.length
+ # Clearing twice must not produce erroneous data.
+ subject.clear
+ assert 0 == subject.length
+ end
+
+ fun test_uri do
+ var subject: AttributesImpl = sample
+
+ assert "http://example.com/" == subject.uri(0)
+ assert "urn:is:not:often:used" == subject.uri(1)
+ assert "http://www.w3.org/XML/1998/namespace" == subject.uri(2)
+ assert "" == subject.uri(3)
+ assert subject.uri(4) == null
+ assert subject.uri(-1) == null
+ subject.clear
+ assert subject.uri(0) == null
+ end
+
+ fun test_local_name do
+ var subject: AttributesImpl = sample
+
+ assert "bar" == subject.local_name(0)
+ assert "i-am_ME" == subject.local_name(1)
+ assert "lang" == subject.local_name(2)
+ assert "" == subject.local_name(3)
+ assert subject.local_name(4) == null
+ assert subject.local_name(-1) == null
+ subject.clear
+ assert subject.local_name(0) == null
+ end
+
+ fun test_qname do
+ var subject: AttributesImpl = sample
+
+ assert "foo:bar" == subject.qname(0)
+ assert "" == subject.qname(1)
+ assert "xml:lang" == subject.qname(2)
+ assert "xml:space" == subject.qname(3)
+ assert subject.qname(4) == null
+ assert subject.qname(-1) == null
+ subject.clear
+ assert subject.qname(0) == null
+ end
+
+ fun test_type_of do
+ var subject: AttributesImpl = sample
+
+ assert "CDATA" == subject.type_of(0)
+ assert "ID" == subject.type_of(1)
+ assert "NMTOKEN" == subject.type_of(2)
+ assert "NMTOKEN" == subject.type_of(3)
+ assert subject.type_of(4) == null
+ assert subject.type_of(-1) == null
+ subject.clear
+ assert subject.type_of(0) == null
+ end
+
+ fun test_type_of_qname do
+ var subject: AttributesImpl = sample
+
+ assert "CDATA" == subject.type_of("foo:bar")
+ assert subject.type_of("") == null
+ assert "NMTOKEN" == subject.type_of("xml:lang")
+ assert "NMTOKEN" == subject.type_of("xml:space")
+ assert subject.type_of("bob") == null
+ subject.clear
+ assert subject.type_of("xml:lang") == null
+ end
+
+ fun test_value_of do
+ var subject: AttributesImpl = sample
+
+ assert "baz" == subject.value_of(0)
+ assert "noop" == subject.value_of(1)
+ assert "" == subject.value_of(2)
+ assert "default" == subject.value_of(3)
+ assert subject.value_of(4) == null
+ assert subject.value_of(-1) == null
+ subject.clear
+ assert subject.value_of(0) == null
+ end
+
+ fun test_value_of_qname do
+ var subject: AttributesImpl = sample
+
+ assert "baz" == subject.value_of("foo:bar")
+ assert subject.value_of("") == null
+ assert "" == subject.value_of("xml:lang")
+ assert "default" == subject.value_of("xml:space")
+ assert subject.value_of("bob") == null
+ subject.clear
+ assert subject.value_of("xml:lang") == null
+ end
+
+ fun test_index_ns do
+ var subject: AttributesImpl = sample
+
+ assert 0 == subject.index_ns("http://example.com/", "bar")
+ assert 1 == subject.index_ns("urn:is:not:often:used", "i-am_ME")
+ assert 2 == subject.index_ns("http://www.w3.org/XML/1998/namespace", "lang")
+ assert -1 == subject.index_ns("", "")
+ assert -1 == subject.index_ns("http://www.w3.org/XML/1998/namespace", "space")
+ subject.clear
+ assert -1 == subject.index_ns("http://example.com/", "bar")
+ end
+
+ fun test_index_of do
+ var subject: AttributesImpl = sample
+
+ assert 0 == subject.index_of("foo:bar")
+ assert -1 == subject.index_of("")
+ assert 2 == subject.index_of("xml:lang")
+ assert 3 == subject.index_of("xml:space")
+ assert -1 == subject.index_of("i-am_ME")
+ subject.clear
+ assert -1 == subject.index_of("foo:bar")
+ end
+
+ fun test_type_ns do
+ var subject: AttributesImpl = sample
+
+ assert "CDATA" == subject.type_ns("http://example.com/", "bar")
+ assert "ID" == subject.type_ns("urn:is:not:often:used", "i-am_ME")
+ assert "NMTOKEN" == subject.type_ns("http://www.w3.org/XML/1998/namespace", "lang")
+ assert subject.type_ns("", "") == null
+ assert subject.type_ns("http://www.w3.org/XML/1998/namespace", "space") == null
+ subject.clear
+ assert subject.type_ns("http://example.com/", "bar") == null
+ end
+
+ fun test_value_ns do
+ var subject: AttributesImpl = sample
+
+ assert "baz" == subject.value_ns("http://example.com/", "bar")
+ assert "noop" == subject.value_ns("urn:is:not:often:used", "i-am_ME")
+ assert "" == subject.value_ns("http://www.w3.org/XML/1998/namespace", "lang")
+ assert subject.value_ns("", "") == null
+ assert subject.value_ns("http://www.w3.org/XML/1998/namespace", "space") == null
+ subject.clear
+ assert subject.value_ns("http://example.com/", "bar") == null
+ end
+
+ fun test_attributes_set do
+ var subject: AttributesImpl = sample
+ var subject2: AttributesImpl = new AttributesImpl
+
+ subject.attributes = subject2
+ assert subject.length == 0
+ subject2 = sample
+ subject.attributes = subject2
+ assert subject.length == 4
+ end
+
+ fun test_set do
+ var subject: AttributesImpl = sample
+
+ subject.set(1, "urn:is:not:often:used", "i-am_ME", "i-am_ME", "ID",
+ "noop")
+ assert "i-am_ME" == subject.qname(1)
+ subject.set(0, "http://example.com/", "bar", "foo:bar", "NMTOKENS", "baz")
+ assert "NMTOKENS" == subject.type_of(0)
+ end
+
+ fun test_remove_at do
+ var subject: AttributesImpl = sample
+
+ subject.remove_at(1)
+ assert 3 == subject.length
+ assert "xml:lang" == subject.qname(1)
+ end
+
+ fun test_uri_set do
+ var subject: AttributesImpl = sample
+
+ subject.uri(0) = "https://example.org/serious"
+ subject.uri(1) = "ftp://wat"
+ assert "ftp://wat" == subject.uri(1)
+ assert "https://example.org/serious" == subject.uri(0)
+ end
+
+ fun test_local_name_set do
+ var subject: AttributesImpl = sample
+
+ subject.local_name(0) = "trololol"
+ subject.local_name(1) = "ImYou42"
+ assert "trololol" == subject.local_name(0)
+ assert "ImYou42" == subject.local_name(1)
+ end
+
+ fun test_qname_set do
+ var subject: AttributesImpl = sample
+
+ subject.qname(0) = "go-to:bar"
+ subject.qname(1) = "yo:i-am_ME"
+ assert "go-to:bar" == subject.qname(0)
+ assert "yo:i-am_ME" == subject.qname(1)
+ end
+
+ fun test_type_of_set do
+ var subject: AttributesImpl = sample
+
+ subject.type_of(0) = "NMTOKENS"
+ subject.type_of(1) = "ENTITY"
+ assert "NMTOKENS" == subject.type_of(0)
+ assert "ENTITY" == subject.type_of(1)
+ end
+
+ fun test_value_of_set do
+ var subject: AttributesImpl = sample
+
+ subject.value_of(0) = "buz"
+ subject.value_of(1) = "bizzz"
+ assert "buz" == subject.value_of(0)
+ assert "bizzz" == subject.value_of(1)
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Test suite for `namespace_support`.
+module test_namespace_support is test_suite
+
+import test_suite
+import sax::helpers::namespace_support
+
+class TestNamespaceSupport
+ super TestSuite
+
+ private fun sample: NamespaceSupport do
+ var subject = new NamespaceSupport
+
+ subject.push_context
+ subject.declare_prefix("", "http://www.w3.org/1999/xhtml")
+ subject.declare_prefix("dc", "http://www.purl.org/dc#")
+ return subject
+ end
+
+ fun test_reset do
+ var subject = sample
+
+ subject.reset
+ assert subject.xmlns == subject.uri("xml")
+ assert subject.nsdecl == subject.uri("xmlns")
+ assert subject.prefix("http://www.w3.org/1999/xhtml") == null
+ assert 2 == subject.declared_prefixes.length
+ assert 2 == subject.prefixes.length
+ end
+
+ fun test_push_context_override_default do
+ var subject = sample
+
+ subject.push_context
+ subject.declare_prefix("", "this:is:a:test")
+ assert "this:is:a:test" == subject.uri("")
+ assert "http://www.purl.org/dc#" == subject.uri("dc")
+ assert subject.xmlns == subject.uri("xml")
+ assert subject.nsdecl == subject.uri("xmlns")
+ assert subject.prefix("http://www.w3.org/1999/xhtml") == null
+ assert 1 == subject.declared_prefixes.length
+ assert 3 == subject.prefixes.length
+ end
+
+ fun test_push_context_override_dc do
+ var subject = sample
+
+ subject.push_context
+ subject.declare_prefix("dc", "this:is:a:test")
+ assert "this:is:a:test" == subject.uri("dc")
+ assert "http://www.w3.org/1999/xhtml" == subject.uri("")
+ assert subject.xmlns == subject.uri("xml")
+ assert subject.prefix("http://www.purl.org/dc#") == null
+ assert 1 == subject.declared_prefixes.length
+ assert 3 == subject.prefixes.length
+ end
+
+ fun test_push_context_undeclare do
+ var subject = sample
+
+ subject.push_context
+ subject.declare_prefix("dc", "")
+ assert subject.uri("dc") == null
+ assert 1 == subject.declared_prefixes.length
+ assert 2 == subject.prefixes.length
+ end
+
+ fun test_pop_context do
+ var subject = sample
+
+ subject.pop_context
+ assert subject.xmlns == subject.uri("xml")
+ assert subject.prefix("http://www.w3.org/1999/xhtml") == null
+ assert 2 == subject.declared_prefixes.length
+ assert 2 == subject.prefixes.length
+ end
+
+ #fun test_declare_prefix # SEE: test_push_context_*
+
+ fun test_process_name do
+ var subject = sample
+ var parts = new Array[String]
+
+ assert ["http://www.w3.org/1999/xhtml", "p", "p"] == subject.process_name("p", parts, false)
+ assert ["", "p", "p"] == subject.process_name("p", parts, true)
+ assert ["http://www.purl.org/dc#", "title", "dc:title"] == subject.process_name("dc:title", parts, false)
+ assert ["http://www.purl.org/dc#", "title", "dc:title"] == subject.process_name("dc:title", parts, true)
+ assert [subject.xmlns, "lang", "xml:lang"] == subject.process_name("xml:lang", parts, false)
+ assert ["http://www.w3.org/1999/xhtml", "p", ":p"] == subject.process_name(":p", parts, false)
+ assert ["", "p", ":p"] == subject.process_name(":p", parts, true)
+ assert subject.process_name("foo:bar", parts, false) == null
+ assert subject.process_name("foo:bar", parts, true) == null
+ subject.pop_context
+ assert ["", "p", "p"] == subject.process_name("p", parts, false)
+ assert ["", "p", "p"] == subject.process_name("p", parts, true)
+ end
+
+ fun test_process_name_xmlns do
+ var subject = sample
+ var parts = new Array[String].with_capacity(3)
+
+ assert [subject.nsdecl, "", "xmlns"] == subject.process_name("xmlns", parts, true)
+ assert ["http://www.w3.org/1999/xhtml", "xmlns", "xmlns"] == subject.process_name("xmlns", parts, false)
+ end
+
+ fun test_declare_prefix_illegal do
+ var subject = sample
+
+ assert not subject.declare_prefix("xml", "http://example.org")
+ assert not subject.declare_prefix("xmlns", "http://www2.example.org")
+ assert not subject.declare_prefix("foo", subject.xmlns)
+ assert not subject.declare_prefix("bar", subject.nsdecl)
+ assert 2 == subject.declared_prefixes.length
+ end
+
+ fun test_uri do
+ var subject = sample
+
+ assert "http://www.w3.org/1999/xhtml" == subject.uri("")
+ assert "http://www.purl.org/dc#" == subject.uri("dc")
+ assert subject.xmlns == subject.uri("xml")
+ assert subject.uri("foo") == null
+ end
+
+ fun test_prefixes do
+ var subject = sample
+ var res = sample.prefixes
+
+ assert 3 == res.length else
+ sys.stderr.write("Expected 3; got {res.length}.\n")
+ end
+ assert res.has("dc")
+ assert res.has("xml")
+ assert res.has("xmlns")
+ end
+
+ fun test_prefix do
+ var subject = sample
+
+ assert subject.prefix("http://www.w3.org/1999/xhtml") == null
+ assert "dc" == subject.prefix("http://www.purl.org/dc#")
+ assert "xml" == subject.prefix(subject.xmlns)
+ assert subject.prefix("https://example.org/serious") == null
+ end
+
+ fun test_prefixes_of do
+ var subject = sample
+ var res: Collection[String]
+
+ assert new Array[String] == subject.prefixes_of("http://www.w3.org/1999/xhtml")
+ assert ["dc"] == subject.prefixes_of("http://www.purl.org/dc#")
+ assert ["xml"] == subject.prefixes_of(subject.xmlns)
+ assert new Array[String] == subject.prefixes_of("https://example.org/serious")
+ subject.declare_prefix("html", "http://www.w3.org/1999/xhtml")
+ assert ["html"] == subject.prefixes_of("http://www.w3.org/1999/xhtml")
+ subject.declare_prefix("dc2", "http://www.purl.org/dc#")
+ res = subject.prefixes_of("http://www.purl.org/dc#")
+ assert 2 == res.length else
+ sys.stderr.write("Expected 2; got {res.length}.\n")
+ end
+ assert res.has_all(["dc", "dc2"])
+ end
+
+ fun test_declared_prefixes do
+ var subject = sample
+ var res = sample.declared_prefixes
+
+ assert 2 == res.length else
+ sys.stderr.write("Expected 2; got {res.length}.\n")
+ end
+ assert res.has("")
+ assert res.has("dc")
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Base class for deriving an XML filter.
+module sax::helpers::xml_filter_impl
+
+import sax::xml_reader
+import sax::xml_filter
+import sax::input_source
+import sax::sax_locator
+import sax::attributes
+import sax::entity_resolver
+import sax::dtd_handler
+import sax::content_handler
+import sax::error_handler
+import sax::sax_parse_exception
+
+# Base class for deriving an XML filter.
+#
+# This class is designed to sit between an `XMLReader`
+# and the client application's event handlers. By default, it
+# does nothing but pass requests up to the reader and events
+# on to the handlers unmodified, but subclasses can override
+# specific methods to modify the event stream or the configuration
+# requests as they pass through.
+#
+# Note: The original source code and documentation of this class comes, in part,
+# from [SAX 2.0](http://www.saxproject.org).
+class XMLFilterImpl
+ super XMLFilter
+ super EntityResolver
+ super DTDHandler
+ super ContentHandler
+ super ErrorHandler
+
+ # XMLFilter
+
+ redef var parent: nullable XMLReader = null is writable
+
+ # XMLReader
+
+ redef var entity_resolver: nullable EntityResolver = null is writable
+ redef var dtd_handler: nullable DTDHandler = null is writable
+ redef var content_handler: nullable ContentHandler = null is writable
+ redef var error_handler: nullable ErrorHandler = null is writable
+
+
+ ############################################################################
+ # XMLReader
+
+ # Construct an empty XML filter, with no parent.
+ #
+ # This filter will have no parent: you must assign a parent
+ # before you start a parse or do any configuration with
+ # `feature=` or `property=`, unless you use this as
+ # a pure event consumer rather than as an `XMLReader`.
+ #
+ # SEE: `parent`
+ init do
+ end
+
+ # Construct an XML filter with the specified parent.
+ #
+ # SEE: `parent`
+ init with_parent(parent_reader: XMLReader) do
+ parent = parent_reader
+ end
+
+ redef fun feature_recognized(name: String): Bool do
+ if parent == null then
+ return false
+ else
+ return parent.feature_recognized(name)
+ end
+ end
+
+ redef fun feature_readable(name: String): Bool do
+ if parent == null then
+ return false
+ else
+ return parent.feature_readable(name)
+ end
+ end
+
+ redef fun feature_writable(name: String): Bool do
+ if parent == null then
+ return false
+ else
+ return parent.feature_writable(name)
+ end
+ end
+
+ # Look up the value of a feature.
+ #
+ # This will always fail if the parent is `null`.
+ #
+ # Parameters:
+ #
+ # * `name`: The feature name.
+ #
+ # Returns:
+ #
+ # The current value of the feature.
+ #
+ # SEE: `feature_recognized`
+ #
+ # SEE: `feature_readable`
+ redef fun feature(name: String): Bool do
+ assert sax_recognized: parent != null else
+ sys.stderr.write("Feature: {name}\n")
+ end
+ return parent.feature(name)
+ end
+
+ # Set the value of a feature.
+ #
+ # This will always fail if the parent is `null`.
+ #
+ # Parameters:
+ #
+ # * `name`: feature name.
+ # * `value`: requested feature value.
+ #
+ # Returns:
+ #
+ # `true` if the feature is set; `false` if the feature can not be set given
+ # the current context.
+ #
+ # SEE: `feature_recognized`
+ #
+ # SEE: `feature_writable`
+ redef fun feature=(name: String, value: Bool) do
+ assert sax_recognized: parent != null else
+ sys.stderr.write("Feature: {name}\n")
+ end
+ parent.feature(name) = value
+ end
+
+ redef fun property_recognized(name: String): Bool do
+ if parent == null then
+ return false
+ else
+ return parent.property_recognized(name)
+ end
+ end
+
+ redef fun property_readable(name: String): Bool do
+ if parent == null then
+ return false
+ else
+ return parent.property_readable(name)
+ end
+ end
+
+ redef fun property_writable(name: String): Bool do
+ if parent == null then
+ return false
+ else
+ return parent.property_writable(name)
+ end
+ end
+
+ # Look up the value of a property.
+ #
+ # Parameters:
+ #
+ # * `name`: The property name.
+ #
+ # Returns:
+ #
+ # The current value of the property.
+ #
+ # SEE: `property_recognized`
+ #
+ # SEE: `property_readable`
+ redef fun property(name: String): nullable Object do
+ assert sax_recognized: parent != null else
+ sys.stderr.write("Property: {name}\n")
+ end
+ return parent.property(name)
+ end
+
+ # Set the value of a property.
+ #
+ # This will always fail if the parent is `null`.
+ #
+ # Parameters:
+ #
+ # * `name`: property name.
+ # * `value`: requested feature value.
+ #
+ # Returns:
+ #
+ # `true` if the property is set; `false` if the property can not be set
+ # given the current context.
+ #
+ # SEE: `property_recognized`
+ #
+ # SEE: `property_writable`
+ redef fun property=(name: String, value: nullable Object) do
+ assert sax_recognized: parent != null else
+ sys.stderr.write("Property: {name}\n")
+ end
+ parent.property(name) = value
+ end
+
+ redef fun parse(input: InputSource) do
+ setup_parse
+ parent.parse(input)
+ end
+
+ redef fun parse_file(system_id: String) do
+ var source = new InputSource
+
+ source.system_id = system_id
+ parse(source)
+ end
+
+
+ ############################################################################
+ # EntityResolver
+
+ redef fun resolve_entity(public_id: nullable String,
+ system_id: nullable String):
+ nullable InputSource do
+ if entity_resolver == null then
+ return null
+ else
+ return entity_resolver.resolve_entity(public_id, system_id)
+ end
+ end
+
+
+ ############################################################################
+ # DTDHandler
+
+ redef fun notation_decl(name: String, public_id: String,
+ system_id: String) do
+ if dtd_handler != null then
+ dtd_handler.notation_decl(name, public_id, system_id)
+ end
+ end
+
+ redef fun unparsed_entity_decl(name: String, public_id: String,
+ system_id: String) do
+ if dtd_handler != null then
+ dtd_handler.unparsed_entity_decl(name, public_id, system_id)
+ end
+ end
+
+
+ ############################################################################
+ # ContentHandler
+
+ redef fun document_locator=(locator: SAXLocator) do
+ if content_handler != null then
+ content_handler.document_locator = locator
+ end
+ end
+
+ redef fun start_document do
+ if content_handler != null then
+ content_handler.start_document
+ end
+ end
+
+ redef fun end_document do
+ if content_handler != null then
+ content_handler.end_document
+ end
+ end
+
+ redef fun start_prefix_mapping(prefix: String, uri: String) do
+ if content_handler != null then
+ content_handler.start_prefix_mapping(prefix, uri)
+ end
+ end
+
+ redef fun end_prefix_mapping(prefix: String) do
+ if content_handler != null then
+ content_handler.end_prefix_mapping(prefix)
+ end
+ end
+
+ redef fun start_element(uri: String, local_name: String, qname: String,
+ atts: Attributes) do
+ if content_handler != null then
+ content_handler.start_element(uri, local_name, qname, atts)
+ end
+ end
+
+ redef fun end_element(uri: String, local_name: String, qname: String) do
+ if content_handler != null then
+ content_handler.end_element(uri, local_name, qname)
+ end
+ end
+
+ redef fun characters(str: String) do
+ if content_handler != null then
+ content_handler.characters(str)
+ end
+ end
+
+ redef fun ignorable_whitespace(str: String) do
+ if content_handler != null then
+ content_handler.ignorable_whitespace(str)
+ end
+ end
+
+ redef fun processing_instruction(target: String, data: nullable String) do
+ if content_handler != null then
+ content_handler.processing_instruction(target, data)
+ end
+ end
+
+ redef fun skipped_entity(name: String) do
+ if content_handler != null then
+ content_handler.skipped_entity(name)
+ end
+ end
+
+
+ ############################################################################
+ # ErrorHandler
+
+ redef fun warning(exception: SAXParseException) do
+ if error_handler != null then
+ error_handler.warning(exception)
+ end
+ end
+
+ redef fun error(exception: SAXParseException) do
+ if error_handler != null then
+ error_handler.error(exception)
+ end
+ end
+
+ redef fun fatal_error(exception: SAXParseException) do
+ if error_handler != null then
+ error_handler.fatal_error(exception)
+ else
+ exception.throw
+ end
+ end
+
+ ############################################################################
+ # private
+
+ # Set up before a parse.
+ #
+ # Before every parse, check whether the parent is
+ # non-null, and re-register the filter for all of the
+ # events.
+ private fun setup_parse do
+ assert parent_is_not_null: parent != 0 else
+ sys.stderr.write("No parent for filter.")
+ end
+ parent.entity_resolver = self
+ parent.dtd_handler = self
+ parent.content_handler = self
+ parent.error_handler = self
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# A single input source for an XML entity.
+module sax::input_source
+
+# A single input source for an XML entity.
+#
+# This class allows a SAX application to encapsulate information
+# about an input source in a single object, which may include
+# a public identifier, a system identifier and a stream (possibly
+# with a specified encoding).
+#
+# There are two places that the application can deliver an
+# input source to the parser: as the argument to the `XMLReader.parse`
+# method, or as the return value of the `EntityResolver.resolve_entity`
+# method.
+#
+# The SAX parser will use the `InputSource` object to determine how to read XML
+# input. If there is a byte stream, the parser will use that byte stream, using
+# the encoding specified in the InputSource or else (if no encoding is
+# specified) autodetecting the character encoding using an algorithm
+# such as the one in the XML specification. If no byte stream is available, the
+# parser will attempt to open a URI connection to the resource identified by
+# the system identifier.
+#
+# An InputSource object belongs to the application: the SAX parser
+# shall never modify it in any way (it may modify a copy if
+# necessary). However, standard processing of the stream is to close it on as
+# part of end-of-parse cleanup, so applications should not attempt to re-use
+# such streams after they have been handed to a parser.
+#
+# Note: The original documentation comes, in part,
+# from [SAX 2.0](http://www.saxproject.org).
+class InputSource
+
+ init do end
+
+ # Create a new input source with the specified system identifier.
+ #
+ # Applications may use `public_id=` to include a public identifier as well,
+ # or `encoding=` to specify the character encoding, if known.
+ #
+ # If the system identifier is a URL, it must be fully resolved (it may not
+ # be a relative URL).
+ init with_system_id(system_id: String) do
+ self.system_id = system_id
+ end
+
+ # Create a new input source with the specified stream.
+ #
+ # Application writers should use `system_id=` to provide a base for
+ # resolving relative URIs, may use `public_id=` to include a public
+ # identifier, and may use `encoding=` to specify the object's character
+ # encoding.
+ init with_stream(stream: IStream) do
+ self.stream = stream
+ end
+
+ # The public identifier as a string.
+ #
+ # The public identifier is always optional: if the application
+ # writer includes one, it will be provided as part of the
+ # location information.
+ var public_id: nullable String = null is writable
+
+ # The system identifier as a string.
+ #
+ # If its an URL, it must be fully resolved (it may not be a relative URL).
+ #
+ # Applications may set `public_id` to include a
+ # public identifier as well, or set `encoding` to specify
+ # the character encoding, if known.
+ var system_id: nullable String = null is writable
+
+ # The stream containing the document.
+ #
+ # Application writers should set `system_id` to provide a base
+ # for resolving relative URIs, may set `public_id` to include a
+ # public identifier, and may set `encoding` to specify the object's
+ # character encoding.
+ var stream: nullable IStream = null is writable
+
+ # The character encoding, if known.
+ #
+ # The encoding must be a string acceptable for an
+ # XML encoding declaration (see section 4.3.3 of the XML 1.0
+ # recommendation).
+ var encoding: nullable String = null is writable
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Core SAX APIs.
+#
+# This is a (partial) port of the original SAX API. See
+# [http://www.saxproject.org](http://www.saxproject.org) for more information
+# about SAX.
+#
+# SAX2 Standard Feature Flags:
+#
+# One of the essential characteristics of SAX2 is that it added
+# feature flags which can be used to examine and perhaps modify
+# parser modes, in particular modes such as validation.
+# Since features are identified by (absolute) URIs, anyone
+# can define such features.
+#
+# For default values not specified by SAX2,
+# each `XMLReader` implementation specifies its default,
+# or may choose not to expose the feature flag.
+# Unless otherwise specified here,
+# implementations may support changing current values
+# of these standard feature flags, but not while parsing.
+#
+# Currently defined standard feature URIs have the prefix
+# `http://xml.org/sax/features/` before an identifier such as
+# `validation`. Support for the default values of the
+# `namespaces` and `namespace-prefixes`
+# properties is required. Turn features on or off using
+# `feature=`. Those standard identifiers are:
+#
+# `external-general-entities`:
+#
+# * Access: read/write
+# * Default: unspecified
+# * Description: Reports whether this parser processes external general
+# entities; always `true` if validating.
+#
+# `external-parameter-entities`:
+#
+# * Access: read/write
+# * Default: unspecified
+# * Description: Reports whether this parser processes external parameter
+# entities; always `true` if validating.
+#
+# `is-standalone`:
+#
+# * Access: read-only while parsing, none while not parsing
+# * Default: not applicable
+# * Description: May be examined only during a parse, after the `start_document`
+# callback has been completed; read-only. The value is `true` if the document
+# specified `standalone="yes"` in its XML declaration, and otherwise is `false`.
+#
+# `lexical-handler/parameter-entities`:
+#
+# * Access: read/write
+# * Default: unspecified
+# * Description: `true` indicates that the LexicalHandler will report the
+# beginning and end of parameter entities.
+#
+# `namespaces`:
+#
+# * Access: read/write
+# * Default: `true`
+# * Description: `true` indicates namespace URIs and unprefixed local names
+# for element and attribute names will be available.
+#
+# `namespace-prefixes`:
+#
+# * Access: read/write
+# * Default: `false`
+# * Description: `true` indicates XML 1.0 names (with prefixes) and attributes
+# (including `xmlns*` attributes) will be available.
+#
+# `resolve-dtd-uris`:
+#
+# * Access: read/write
+# * Default: `true`
+# * Description: `true` indicates that system IDs in declarations will be
+# absolutized (relative to their base URIs) before reporting. (That is the
+# default behavior for all SAX2 XML parsers.) A value of "false" indicates those
+# IDs will not be absolutized; parsers will provide the base URI from
+# `SAXLocator.system_id`. This applies to system IDs passed in
+# `DTDHandler.notation_decl`, DTDHandler.unparsed_entity_decl`, and
+# `DeclHandler.external_entity_decl`. It does not apply to
+# `EntityResolver.resolve_entity`, which is not used to report declarations, or
+# to `LexicalHandler.start_dtd`, which already provides the non-absolutized URI.
+#
+# `string-interning`:
+#
+# * Access: read-only
+# * Default: `false`
+# * Description: (Java-specific. Not supported in Nit.)
+#
+# `unicode-normalization-checking`:
+#
+# * Access: read/write
+# * Default: `false`
+# * Description: Controls whether the parser reports Unicode normalization
+# errors as described in section 2.13 and Appendix B of the XML 1.1
+# Recommendation. If `true`, Unicode normalization errors are reported using
+# the `ErrorHandler.error` callback. Such errors are not fatal in themselves
+# (though, obviously, other Unicode-related encoding errors may be).
+#
+# `use-attributes2`:
+#
+# * Access: read-only
+# * Default: not applicable
+# * Description: Returns `true` if the `Attributes` objects passed by this
+# parser in `ContentHandler.start_element` implement the
+# `sax::ext::Attributes2` interface. That interface exposes additional
+# DTD-related information, such as whether the attribute was specified in the
+# source text rather than defaulted.
+#
+# TODO: interface not yet available in Nit.
+#
+# `use-locator2`:
+#
+# * Access: read-only
+# * Default: not applicable
+# * Description: Returns `true` if the `SAXLocator` objects passed by this
+# parser in `ContentHandler.document_locator=` implement the
+# `sax::ext::SAXLocator2` interface. That interface exposes additional
+# entity information, such as the character encoding and XML version used.
+#
+# TODO: interface not yet available in Nit.
+#
+# `use-entity-resolver2`:
+#
+# * Access: read/write
+# * Default: true
+# * Description: Returns `true` if, when `entity_resolver` is given an object
+# implementing the `sax::ext::EntityResolver2` interface, those new methods
+# will be used. Returns `false` to indicate that those methods will not be used.
+#
+# `validation`:
+#
+# * Access: read/write
+# * Default: unspecified
+# * Description: controls whether the parser is reporting all validity errors;
+# if true, all external entities will be read.
+#
+# `xmlns-uris`:
+#
+# * Access: read/write
+# * Default: `false`
+# * Description: Controls whether, when the `namespace-prefixes` feature is set,
+# the parser treats namespace declaration attributes as being in the
+# `http://www.w3.org/2000/xmlns/` namespace. By default, SAX2 conforms to the
+# original "Namespaces in XML" Recommendation, which explicitly states that such
+# attributes are not in any namespace. Setting this optional flag to `true`
+# makes the SAX2 events conform to a later backwards-incompatible revision of
+# that recommendation, placing those attributes in a namespace.
+#
+# `xml-1.1`:
+#
+# * Access: read-only
+# * Default: not applicable
+# * Description: Returns `true` if the parser supports both XML 1.1 and XML 1.0.
+# Returns "false" if the parser supports only XML 1.0.
+#
+#
+# SAX2 Standard Handler and Property IDs:
+#
+# For parser interface characteristics that are described as objects, a
+# separate namespace is defined. The objects in this namespace are again
+# identified by URI, and the standard property URIs have the prefix
+# `http://xml.org/sax/properties/` before an identifier such as
+# `lexical-handler` or `dom-node`. All of these standard properties are
+# optional; `XMLReader` implementations need not support them. Manage those
+# properties using `property=`. Those identifiers are:
+#
+# `declaration-handler`:
+#
+# Used to see most DTD declarations except those treated as lexical (“document
+# element name is...”) or which are mandatory for all SAX parsers
+# (`DTDHandler`). The object must implement `sax::ext::DeclHandler`.
+#
+# `document-xml-version`:
+#
+# May be examined only during a parse, after the `start_document` callback
+# has been completed; read-only. This property is a literal string describing
+# the actual XML version of the document, such as `"1.0"` or `"1.1"`.
+#
+# `dom-node`:
+#
+# For “DOM Walker” style parsers, which ignore their `parser.parse` parameters,
+# this is used to specify the DOM (sub)tree being walked by the parser. The
+# object must implement the `xml.dom.Node` interface.
+#
+# TODO: interface not yet available in Nit.
+#
+# `lexical-handler`:
+#
+# Used to see some syntax events that are essential in some applications:
+# comments, `CDATA` delimeters, selected general entity inclusions, and the
+# start and end of the DTD (and declaration of document element name).
+# The object must implement `sax::ext::LexicalHandler`.
+#
+# `xml-string`:
+#
+# Readable only during a parser callback, this exposes a **TBS** chunk of
+# characters responsible for the current event.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+module sax
+
+import attributes
+import content_handler
+import dtd_handler
+import entity_resolver
+import error_handler
+import input_source
+import sax_locator
+import sax_parse_exception
+import xml_filter
+import xml_reader
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Interface for associating a SAX event with a document location.
+module sax::sax_locator
+
+# Interface for associating a SAX event with a document location.
+#
+# If a SAX parser provides location information to the SAX
+# application, it does so by implementing this interface and then
+# passing an instance to the application using the
+# `ContentHandler.document_locator=` method. The application can use
+# the object to obtain the location of any other SAX event
+# in the XML source document.
+#
+# Note that the results returned by the object will be valid only
+# during the scope of each callback method: the application
+# will receive unpredictable results if it attempts to use the
+# locator at any other time, or after parsing completes.
+#
+# SAX parsers are not required to supply a locator, but they are
+# very strongly encouraged to do so. If the parser supplies a
+# locator, it must do so before reporting any other document events.
+# If no locator has been set by the time the application receives
+# the `ContentHandler.start_document` event, the application should
+# assume that a locator is not available.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+#
+# SEE: `sax::ContentHandler.document_locator`
+public interface SAXLocator
+
+ # Return the public identifier for the current document event.
+ #
+ # Return the public identifier of the document
+ # entity or of the external parsed entity in which the markup
+ # triggering the event appears.
+ # Return `null` if no public identifier is available.
+ fun public_id: nullable String is abstract
+
+ # Return the system identifier for the current document event.
+ #
+ # Return the system identifier of the document
+ # entity or of the external parsed entity in which the markup
+ # triggering the event appears.
+ # Return `null` if no system identifier is available.
+ #
+ # If the system identifier is a URL, the parser must resolve it
+ # fully before passing it to the application. For example, a file
+ # name must always be provided as a `file:` URL, and other
+ # kinds of relative URI are also resolved against their bases.
+ fun system_id: nullable String is abstract
+
+ # Return the line number where the current document event ends.
+ #
+ # Lines are delimited by line ends, which are defined in
+ # the XML specification.
+ #
+ # **Warning:** The return value from this method
+ # is intended only as an approximation for the sake of diagnostics;
+ # it is not intended to provide sufficient information
+ # to edit the character content of the original XML document.
+ # In some cases, these "line" numbers match what would be displayed
+ # as columns, and in others they may not match the source text
+ # due to internal entity expansion.
+ #
+ # Return an approximation of the line number
+ # in the document entity or external parsed entity where the
+ # markup triggering the event appears.
+ #
+ # If possible, the SAX driver should provide the line position
+ # of the first character after the text associated with the document
+ # event. The first line is line 1.
+ #
+ # Return -1 in absence of line number.
+ fun line_number: Int is abstract
+
+ # Return the column number where the current document event ends.
+ #
+ # The number is one-based.
+ #
+ # **Warning:** The return value from this method
+ # is intended only as an approximation for the sake of diagnostics;
+ # it is not intended to provide sufficient information
+ # to edit the character content of the original XML document.
+ # For example, when lines contain combining character sequences, wide
+ # characters, surrogate pairs, or bi-directional text, the value may
+ # not correspond to the column in a text editor's display.
+ #
+ # The return value is an approximation of the column number
+ # in the document entity or external parsed entity where the
+ # markup triggering the event appears.
+ #
+ # If possible, the SAX driver should provide the line position
+ # of the first character after the text associated with the document
+ # event. The first column in each line is column 1.
+ #
+ # Return -1 in absence of column number.
+ fun column_number: Int is abstract
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Encapsulates an XML parse error or warning.
+module sax::sax_parse_exception
+
+import sax_locator
+
+# Encapsulates an XML parse error or warning.
+#
+# This exception may include information for locating the error
+# in the original XML document, as if it came from a `Locator`
+# object. Note that although the application
+# will receive a `SAXParseException` as the argument to the handlers
+# in the `ErrorHandler` interface,
+# the application is not actually required to throw the exception;
+# instead, it can simply read the information in it and take a
+# different action.
+#
+# Note: The original documentation comes, in part,
+# from [SAX 2.0](http://www.saxproject.org).
+#
+# SEE: `sax::SAXLocator`
+#
+# SEE: `sax::ErrorHandler`
+class SAXParseException
+ super Error
+
+ # The public identifer of the entity that generated
+ # the error or warning.
+ var public_id: nullable String = null
+
+ # The system identifer of the entity that generated
+ # the error or warning.
+ #
+ # If its an URL, it must be fully resolved.
+ var system_id: nullable String = null
+
+ # The line number of the end of the text that
+ # caused the error or warning, or -1.
+ var line_number: Int = -1
+
+ # The column number of the end of the text that
+ # caused the error or warning, or -1.
+ var column_number: Int = -1
+
+ # Create a new SAXParseException from a message and a Locator.
+ #
+ # This constructor is especially useful when an application is
+ # creating its own exception from within a `ContentHandler` callback.
+ #
+ # Parameters:
+ #
+ # * `message`: error or warning message.
+ # * `locator`: locator object for the error or warning.
+ init with_locator(message: String, locator: SAXLocator) do
+ init(message)
+ public_id = locator.public_id
+ system_id = locator.system_id
+ line_number = locator.line_number
+ column_number = locator.column_number
+ end
+
+ # Create a new SAXParseException.
+ #
+ # This constructor is most useful for parser writers.
+ #
+ # All parameters except the message are as if they were provided by a
+ # `Locator`. For example, if the system identifier is a URL (including
+ # relative filename), the caller must resolve it fully before creating the
+ # exception.
+ #
+ # Parameters:
+ #
+ # * `message`: error or warning message.
+ # * `public_id`: public identifer of the entity that generated
+ # the error or warning.
+ # * `system_id`: system identifer of the entity that generated
+ # the error or warning.
+ # * `line_number`: line number of the end of the text that
+ # caused the error or warning.
+ # * `column_number`: column number of the end of the text that
+ # caused the error or warning.
+ init with(message: String, public_id: nullable String,
+ system_id: nullable String, line_number: Int, column_number: Int) do
+ init(message)
+ self.public_id = public_id
+ self.system_id = system_id
+ self.line_number = line_number
+ self.column_number = column_number
+ end
+
+ # Generate a complete message from the exception’s attributes.
+ fun full_message: String do
+ var location = ""
+
+ if public_id != null then
+ location = "PUBLIC \"{public_id.as(not null)}\""
+ end
+ if system_id != null then
+ if location != "" then
+ location += " "
+ end
+ location += "SYSTEM \"{system_id.as(not null)}\""
+ end
+ if line_number >= 0 or column_number >= 0 then
+ if location != "" then
+ location += " at "
+ end
+ location += "{line_number};{column_number}"
+ end
+ if location == "" then
+ return "{message}"
+ else
+ return "[{location}] {message}"
+ end
+ end
+
+ redef fun to_s do
+ return "sax::SAXParseException: {full_message}"
+ end
+
+ # Display `full_message` with a stack trace, then abort.
+ fun throw do
+ assert sax_parse: false else
+ sys.stderr.write "{full_message}\n"
+ end
+ end
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Interface for an XML filter.
+module sax::xml_filter
+
+import xml_reader
+
+# Interface for an XML filter.
+#
+# An XML filter is like an XML reader, except that it obtains its
+# events from another XML reader rather than a primary source like
+# an XML document or database. Filters can modify a stream of
+# events as they pass on to the final application.
+#
+# The `XMLFilterImpl` helper class provides a convenient base
+# for creating SAX2 filters, by passing on all `EntityResolver`,
+# `DTDHandler`, `ContentHandler` and `ErrorHandler` events automatically.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+#
+# SEE: `sax::helpers::XMLFilterImpl`
+interface XMLFilter super XMLReader
+
+ # Set the parent reader.
+ #
+ # This method allows the application to link the filter to
+ # a parent reader (which may be another filter).
+ fun parent=(parent: nullable XMLReader) is abstract
+
+ # Get the parent reader.
+ #
+ # This method allows the application to query the parent
+ # reader (which may be another filter). It is generally a
+ # bad idea to perform any operations on the parent reader
+ # directly: they should all pass through this filter.
+ #
+ # Return null if no parent has been set.
+ fun parent: nullable XMLReader is abstract
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Interface for reading an XML document using callbacks.
+module sax::xml_reader
+
+import entity_resolver
+import dtd_handler
+import content_handler
+import error_handler
+
+# Interface for reading an XML document using callbacks.
+#
+# `XMLReader` is the interface that an XML parser's SAX2 driver must
+# implement. This interface allows an application to set and
+# query features and properties in the parser, to register
+# event handlers for document processing, and to initiate
+# a document parse.
+#
+# All SAX interfaces are assumed to be synchronous: the
+# `parse` methods must not return until parsing
+# is complete, and readers must wait for an event-handler callback
+# to return before reporting the next event.
+#
+# Note: The original documentation comes from [SAX 2.0](http://www.saxproject.org).
+interface XMLReader
+
+ # Is the specified feature flag recognized by this parser?
+ #
+ # Parameter:
+ #
+ # * `name`: feature name, which is a fully-qualified URI.
+ fun feature_recognized(name: String): Bool is abstract
+
+ # Is the retrieval of the specified feature flag supported given the current context?
+ #
+ # Parameter:
+ #
+ # * `name`: feature name, which is a fully-qualified URI.
+ fun feature_readable(name: String): Bool is abstract
+
+ # Is the modification of the specified feature flag supported given the current context?
+ #
+ # Parameter:
+ #
+ # * `name`: feature name, which is a fully-qualified URI.
+ fun feature_writable(name: String): Bool is abstract
+
+ # Look up the value of a feature flag.
+ #
+ # The feature name is any fully-qualified URI. It is
+ # possible for an `XMLReader` to recognize a feature name but
+ # temporarily be unable to return its value.
+ # Some feature values may be available only in specific
+ # contexts, such as before, during, or after a parse.
+ # Also, some feature values may not be programmatically accessible.
+ #
+ # All XMLReaders are required to recognize the
+ # `http://xml.org/sax/features/namespaces` and the
+ # `http://xml.org/sax/features/namespace-prefixes` feature names.
+ #
+ # Implementors are free (and encouraged) to invent their own features,
+ # using names built on their own URIs.
+ #
+ # Parameter:
+ #
+ # * `name`: feature name, which is a fully-qualified URI.
+ #
+ # Returns:
+ #
+ # The current value of the feature.
+ #
+ # SEE: `feature_recognized`
+ #
+ # SEE: `feature_readable`
+ fun feature(name: String): Bool is abstract
+
+ # Set the value of a feature flag.
+ #
+ # The feature name is any fully-qualified URI. It is
+ # possible for an XMLReader to expose a feature value but
+ # to be unable to change the current value.
+ # Some feature values may be immutable or mutable only
+ # in specific contexts, such as before, during, or after
+ # a parse.
+ #
+ # All XMLReaders are required to support setting
+ # http://xml.org/sax/features/namespaces to true and
+ # http://xml.org/sax/features/namespace-prefixes to false.
+ #
+ # Parameters:
+ #
+ # * `name`: feature name, which is a fully-qualified URI.
+ # * `value`: requested value of the feature.
+ #
+ # SEE: `feature_recognized`
+ #
+ # SEE: `feature_writable`
+ fun feature=(name: String, value: Bool) is abstract
+
+ # Is the specified property recognized by this parser?
+ #
+ # Parameter:
+ #
+ # * `name`: property name, which is a fully-qualified URI.
+ fun property_recognized(name: String): Bool is abstract
+
+ # Is the retrieval of the specified property supported given the current context?
+ #
+ # Parameter:
+ #
+ # * `name`: property name, which is a fully-qualified URI.
+ fun property_readable(name: String): Bool is abstract
+
+ # Is the modification of the specified property supported given the current context?
+ #
+ # Parameter:
+ #
+ # * `name`: property name, which is a fully-qualified URI.
+ fun property_writable(name: String): Bool is abstract
+
+ # Look up the value of a property.
+ #
+ # The property name is any fully-qualified URI. It is
+ # possible for an `XMLReader` to recognize a property name but
+ # temporarily be unable to return its value.
+ # Some property values may be available only in specific
+ # contexts, such as before, during, or after a parse.
+ #
+ # XMLReaders are not required to recognize any specific
+ # property names, though an initial core set is documented for
+ # SAX2.
+ #
+ # Implementors are free (and encouraged) to invent their own properties,
+ # using names built on their own URIs.
+ #
+ # Parameter:
+ #
+ # * `name`: property name, which is a fully-qualified URI.
+ #
+ # Returns:
+ #
+ # The current value of the property.
+ #
+ # SEE: `property_recognized`
+ #
+ # SEE: `property_supported`
+ fun property(name: String): nullable Object is abstract
+
+ # Set the value of a property.
+ #
+ # The property name is any fully-qualified URI. It is
+ # possible for an `XMLReader` to recognize a property name but
+ # to be unable to change the current value.
+ # Some property values may be immutable or mutable only
+ # in specific contexts, such as before, during, or after
+ # a parse.
+ #
+ # XMLReaders are not required to recognize setting
+ # any specific property names, though a core set is defined by
+ # SAX2.
+ #
+ # This method is also the standard mechanism for setting
+ # extended handlers.
+ #
+ # Parameters:
+ #
+ # * `name`: property name, which is a fully-qualified URI.
+ # * `value`: requested value for the property.
+ #
+ # SEE: `property_recognized`
+ #
+ # SEE: `property_writable`
+ fun property=(name: String, value: nullable Object) is abstract
+
+ # Allow an application to register an entity resolver.
+ #
+ # If the application does not register an entity resolver,
+ # the XMLReader will perform its own default resolution.
+ #
+ # Applications may register a new or different resolver in the
+ # middle of a parse, and the SAX parser must begin using the new
+ # resolver immediately.
+ fun entity_resolver=(resolver: nullable EntityResolver) is abstract
+
+ # Return the current entity resolver.
+ #
+ # Return `null` if none has been registered.
+ fun entity_resolver: nullable EntityResolver is abstract
+
+ # Allow an application to register a DTD event handler.
+ #
+ # If the application does not register a DTD handler, all DTD
+ # events reported by the SAX parser will be silently ignored.
+ #
+ # Applications may register a new or different handler in the
+ # middle of a parse, and the SAX parser must begin using the new
+ # handler immediately.
+ fun dtd_handler=(handler: nullable DTDHandler) is abstract
+
+ # Return the current DTD handler.
+ #
+ # Return `null` if none has been registered.
+ fun dtd_handler: nullable DTDHandler is abstract
+
+ # Allow an application to register a content event handler.
+ #
+ # If the application does not register a content handler, all
+ # content events reported by the SAX parser will be silently
+ # ignored.
+ #
+ # Applications may register a new or different handler in the
+ # middle of a parse, and the SAX parser must begin using the new
+ # handler immediately.
+ fun content_handler=(handler: nullable ContentHandler) is abstract
+
+ # Return the current content handler.
+ #
+ # Return `null` if none has been registered.
+ fun content_handler: nullable ContentHandler is abstract
+
+ # Allow an application to register an error event handler.
+ #
+ # If the application does not register an error handler, all
+ # error events reported by the SAX parser will be silently
+ # ignored; however, normal processing may not continue. It is
+ # highly recommended that all SAX applications implement an
+ # error handler to avoid unexpected bugs.
+ #
+ # Applications may register a new or different handler in the
+ # middle of a parse, and the SAX parser must begin using the new
+ # handler immediately.
+ fun error_handler=(handler: nullable ErrorHandler) is abstract
+
+ # Return the current error handler.
+ #
+ # Return `null` if none has been registered.
+ fun error_handler: nullable ErrorHandler is abstract
+
+ # Parse an XML document.
+ #
+ # The application can use this method to instruct the XML
+ # reader to begin parsing an XML document from any valid input
+ # source (a byte stream or an URI).
+ #
+ # Applications may not invoke this method while a parse is in
+ # progress (they should create a new `XMLReader` instead for each
+ # nested XML document). Once a parse is complete, an
+ # application may reuse the same `XMLReader` object, possibly with a
+ # different input source.
+ #
+ # During the parse, the `XMLReader` will provide information
+ # about the XML document through the registered event
+ # handlers.
+ #
+ # This method is synchronous: it will not return until parsing
+ # has ended. If a client application wants to terminate
+ # parsing early, it should throw an exception.
+ #
+ # Parameters:
+ #
+ # * `source`: input source for the top-level of the XML document.
+ fun parse(input: InputSource) is abstract
+
+ # Parse an XML document from a system identifier (URI).
+ #
+ # This method is a shortcut for the common case of reading a
+ # document from a system identifier. It is the exact
+ # equivalent of the following:
+ #
+ # var source = new InputSouce
+ # source.system_id = system_id
+ # parse(source)
+ #
+ # If the system identifier is a URL, it must be fully resolved
+ # by the application before it is passed to the parser.
+ #
+ # Parameters:
+ #
+ # * `systemId`: The system identifier (URI).
+ fun parse_file(system_id: String) is abstract
+end