This library is specially designed for reading xml configuration files and
to be as low on memory management as possible. Modifying or writing xml files
is not planned for the future. In most situations being able to gather data
by reading an xml file is more than enough and the read-only decision
provides a number of advantages over a one-size fits all approach. For isntance
the memory footprint can be kept low and the library can be kept simple.

To achieve these goals the mmap function is used to map the configuration file
to a memory region. The only places where memory is allocated is when creating
a new XML-id, when requesting a string from a node, when requestiong the node
name or when a request is made to copy a node into a new memory region.

Using this library should be pretty simple for most tasks; just open a file,
read every parameter one by one and close the id again.
{
   void *xid;

   xid = xmlOpen("/tmp/file.xml");
   xpos = xmlNodeGetDouble(xid, "/configuration/x-pos");
   ypos = xmlNodeGetDouble(xid, "/configuration/y-pos");
   zpos = xmlNodeGetDouble(xid, "/configuration/z-pos");
   xmlClose(xid);
}

While it is certainly possible to access every node directly by calling the
xmlNodeGet(Int/Double/String) functions, when more than one node need to be
gathered from a parent node it is advised to get the id of the parent node
and work from there since the XML-id holds the boundaries of the (parent)node
which limits the searching area resulting in improved searching speed.
{
   void *xnid;
   char *s;

   xnid = xmlNodeGet(id, "/configuration/setup/");
   version = xmlNodeGetDouble(xnid, "version");
   s = xmlNodeGetString(xnid, "author");
   if (s) author = s;
   free(s);
   free(xnid);
}

Overview of the available functions:
 ----------------------------------------------------------------------------- 
#
# Functions to Open and Close the XML file
# e.g.
#   id = xmlOpen("/tmp/file.xml");
#   xmlClose(id);
#
void *xmlOpen(const char *filename);
void *xmlInitBuffer(const char *buffer, size_t size);
void xmlClose(void *xid);

#
# Get the Id of a node at the specified path
# e.g.
#    xnid = xmlNodeGet(id, "/path/to/specified/node");
#
void *xmlNodeGet(const void *xid, const char *path);
void *xmlNodeCopy(const void *xid, const char *path);

#
# Functions to walk the node tree and process them one by one.
# e.g.
#   xmid = xmlMarkId(id);
#   num = xmlNodeGetNum(xmid, "node");
#   for (i=0; i<num; i++) {
#      if (xmlNodeGetPos(id, xmid, "element", i) != 0) {
#         if ((s = xmlGetString(xmid)) != 0) {
#            printf("%s\n", s);
#            free(s);
#         }
#      }
#   }
#   free(xmid);
#
void *xmlMarkId(const void *xid);
unsigned int xmlNodeGetNum(const void *xid, const char *path);
void *xmlNodeGetPos(const void *pid, void *xid, const char *element, int pos);

#
# Get the name of the current node
#
char *xmlNodeGetName(const void *xid);
size_t xmlNodeCopyName(const void *xid, const char *buffer, size_t size);

#
# These functions work on the current node.
# e.g.
#    xnid = xmlNodeGet(id, "/path/to/last/node");
#    i = xmlGetInt(xnid);
# or
#    xnid = xmlNodeGet(id, "/path/to/specified/node");
#    if (xmlCompareString(xnid, "value") == 0) printf("We have a match!\n");
#
long int xmlGetInt(const void *xid);
double xmlGetDouble(const void *xid);
char *xmlGetString(const void *xid);
size_t xmlCopyString(const void *xid, char *buffer, const size_t size);
int xmlCompareString(const void *xid, const char *str);

#
# These functions work on a specified node path
# e.g.
#    d = xmlNodeGetDouble(id, "/path/to/node");
# or
#    xnid = xmlNodeGet(id, "/path/to");
#    i = xmlNodeGetInt(xnid, "node");
#
long int xmlNodeGetInt(const void *xid, const char *path);
double xmlNodeGetDouble(const void *xid, const char *path);
char *xmlNodeGetString(const void *xid, const char *path);
size_t xmlNodeCopyString(const void *xid, const char *path,
                            char *buffer, const size_t size);
int xmlNodeCompareString(const void *xid, const char *path, const char *str);

#
# These functions work on a specified atribute
# e.g.
#    i = xmlAttributeGetInt(id, "n");
#
# or
#    s = xmlAttributeGetString(id, "type");
#    if (s) printf("node is of type '%s'\n", s);
#    free(s);
#
long int xmlAttributeGetInt(const void *xid, const char *attr);
double xmlAttributeGetDouble(const void *xid, const char *attr);
char *xmlAttributeGetString(const void *xid, const char *attr);
size_t xmlAttributeCopyString(const void *xid, const char *attr,
                                 const char *buffer, size_t size);
int xmlAttributeCompareString(const void *xid, const char *attr,
                                 const char *str);

#
# Error detection and reporting functions
#
# char *err_str = xmlErrorGetString(id, 0);
# size_t err_lineno = xmlErrorGetLineNo(id, 0);
# int err = xmlErrorGetNo(id, 1); /* clear last error */
# if (err) printf("Error #%i at line %u: '%s'\n", err, err_lineno, err_str);
#
int xmlErrorGetNo(const void *xid, int clear);
size_t xmlErrorGetLineNo(const void *xid, int clear);
size_t xmlErrorGetColumnNo(const void *xid, int clear);
const char *xmlErrorGetString(const void *xid, int clear);
