Resolving identifiers and associating resources
Purpose of this module: The Pxp_reader module allows you to exactly
specify how external identifiers (SYSTEM or PUBLIC) are mapped to
files or channels. This is normally only necessary for advanced
configurations, as the built-in functions Pxp_types.from_file,
Pxp_types.from_channel, and Pxp_types.from_string often suffice.

There are two ways to use this module. First, you can compose the
desired behaviour by combining several predefined resolver objects
or functions. See the example section at the end of the file.
Second, you can inherit from the classes (or define a resolver class
from scratch). I hope this is seldom necessary as this way is much
more complicated; however it allows you to implement any required magic.

Types and exceptions

exceptionNot_competent

Raised by the open_in method if the object does not know how to
handle the passed external ID.

exceptionNot_resolvable ofexn

Indicates that the resolver was competent, but there was an error
while resolving the external ID. The passed exception explains the
reason.
Not_resolvable(Not_found) serves as indicator for an unknown reason.

typelexer_source = {

lsrc_lexbuf : Lexing.lexbuf Lazy.t;

lsrc_unicode_lexbuf : Netulex.ULB.unicode_lexbuf Lazy.t;

}

The parser chooses one of these ways of lexing the input into tokens.

The resolver class type

The class type resolver is the official type of all "resolvers".
Resolvers take file names (or better, external identifiers) and
return lexbufs, scanning the file for tokens. Resolvers may be
cloned, and clones can interpret relative file names relative to
their creator.

Example of cloning:

Given resolver r reads from file:/dir/f1.xml this text:

<tag>some XML text &e; </tag>

The task is to switch to a resolver for reading from the entity
e (which is referenced by &e;), and to switch back to the original
resolver when the parser is done with e. Let us assume that e
has the SYSTEM ID subdir/f2.xml. Our approach is to first create
a clone of the original resolver so that we can do the switch to e
in a copy. That means switching back is easy: We give up the cloned
resolver, and continue with the original, unmodified resolver.
This gives us the freedom to modify the clone in order to switch
to e. We do this by changing the input file:

Step 1: let r' = <create clone of r>

Step 2: <direct r' to open the file subdir/f2.xml>

r' must still know the directory of the file r is reading, otherwise
it would not be able to resolve subdir/f2.xml, which expands to
file:/dir/subdir/f2.xml.

When a resolver accepts an ID, this triple specifies how to proceed.
The in_obj_channel is the channel to read data from, the encoding option
may enforce a certain character encoding, and the resolver_id option
may detail the ID (this ID will be returned by active_id).

If None is passed as encoding option, the standard autodetection of
the encoding is performed.

If None is passed as resolver_id option, the original ID is taken
unchanged.

This is a convenience function to create a file URL (for localhost).
The argument is the file name encoded in the character set enc.
Relative file names are automatically converted to absolute names
by prepending Sys.getcwd() to the passed file name.

system_encoding: Specifies the encoding of file names of
the local file system. Default: UTF-8. (This argument is
necessary to interpret Sys.getcwd() correctly.)

enc: The encoding of the passed string. Defaults to `Enc_utf8

Note: To get a string representation of the URL, apply
Neturl.string_of_url to the result.