Added XML parser from liby2util
authorJiri Srain <jsrain@suse.cz>
Tue, 15 Nov 2005 09:31:14 +0000 (09:31 +0000)
committerJiri Srain <jsrain@suse.cz>
Tue, 15 Nov 2005 09:31:14 +0000 (09:31 +0000)
configure.ac
test/devel.jsrain/PatchRead.cc
zypp/Makefile.am
zypp/parser/LibXMLHelper.cc [new file with mode: 0644]
zypp/parser/LibXMLHelper.h [new file with mode: 0644]
zypp/parser/Makefile.am [new file with mode: 0644]
zypp/parser/XMLNodeIterator.cc [new file with mode: 0644]
zypp/parser/XMLNodeIterator.h [new file with mode: 0644]

index 63de336..8a23021 100644 (file)
@@ -105,7 +105,8 @@ AC_OUTPUT(  \
        zypp/Makefile           \
        zypp/base/Makefile      \
        zypp/detail/Makefile    \
-       zypp/capability/Makefile
+       zypp/capability/Makefile        \
+       zypp/parser/Makefile
 )
 dnl ==================================================
 
index 583e0d6..5fae299 100644 (file)
@@ -165,22 +165,21 @@ class MyPatchImpl : public detail::PatchImpl
 
       // FIXME mve this piece of code after solutions are selected
       // this orders the atoms of a patch
-      ResolvablePtr previous( new Patch( MyPatchImplPtr( this )));
+      ResolvablePtr previous;
+      bool first = true;
       for (atom_list::iterator it = atoms.begin();
            it != atoms.end();
           it++)
       {
-       DBG << previous->kind() << endl;
-       if ((string)(previous->kind()) != "patch")
+       if (! first)
        {
          Dependencies deps = (*it)->deps();
-         CapSet req = deps.requires();
-         req.insert( Capability( _f.parse( "foo", ResKind( "package" ))));
-         deps.setRequires( req );
-//       res->setDeps( deps );
-  
+         CapSet req = deps.prerequires();
+         req.insert( Capability( _f.parse( previous->name(), previous->kind())));
+         deps.setPrerequires( req );
+         (*it)->setDeps( deps );
        }
-
+       first = false;
        previous = *it;
       }
 
@@ -259,6 +258,14 @@ PatchPtr patch1 (new Patch (q));
 
 DBG << patch1 << endl;
 DBG << *patch1 << endl;
+atom_list at = patch1->atoms();
+for (atom_list::iterator it = at.begin();
+     it != at.end();
+     it++)
+{
+  DBG << **it << endl;
+  DBG << (**it).deps() << endl;
+}
 
   INT << "===[END]============================================" << endl;
   return 0;
index 9d97dfc..75589e1 100644 (file)
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 ## ##################################################
 
-SUBDIRS = base detail capability
+SUBDIRS = base detail capability parser
 
 ## ##################################################
 
@@ -50,5 +50,6 @@ lib@PACKAGE@_la_LDFLAGS =     @LIB_VERSION_INFO@
 lib@PACKAGE@_la_LIBADD =        base/lib@PACKAGE@_base.la      \
                                detail/lib@PACKAGE@_detail.la   \
                                capability/lib@PACKAGE@_capability.la
+                               parser/lib@PACKAGE@_parser.la
 
 ## ##################################################
diff --git a/zypp/parser/LibXMLHelper.cc b/zypp/parser/LibXMLHelper.cc
new file mode 100644 (file)
index 0000000..b01338b
--- /dev/null
@@ -0,0 +1,67 @@
+#include <LibXMLHelper.h>
+#include <libxml/tree.h>
+#include <libxml/xmlstring.h>
+#include <cassert>
+#include <sstream>
+
+namespace zypp {
+
+  namespace parser {
+
+    using namespace std;
+    
+    LibXMLHelper::LibXMLHelper()
+    { }
+    
+    LibXMLHelper::~LibXMLHelper()
+    { }
+    
+    std::string LibXMLHelper::attribute(xmlNode * nodePtr, 
+                                        const string &name, 
+                                        const string &defaultValue) const
+    {
+      assert(nodePtr);
+      xmlChar *xmlRes = xmlGetProp(nodePtr, BAD_CAST(name.c_str()));
+      if (xmlRes == 0)
+        return defaultValue;
+      else {
+        string res((const char *)xmlRes);
+        xmlFree(xmlRes);
+        return res;
+      }
+    }
+    
+    
+    std::string LibXMLHelper::content(xmlNode * nodePtr) const
+    {
+      assert(nodePtr);
+      xmlChar *xmlRes = xmlNodeGetContent(nodePtr);
+      if (xmlRes == 0)
+        return string();
+      else {
+        string res((const char*) xmlRes);
+        xmlFree(xmlRes);
+        return res;
+      }
+    }
+    
+    std::string LibXMLHelper::name(const xmlNode * nodePtr) const
+    {
+      assert(nodePtr);
+      return string((const char*) nodePtr->name);
+    }
+    
+    
+    bool LibXMLHelper::isElement(const xmlNode * nodePtr) const
+    {
+      return nodePtr->type == XML_ELEMENT_NODE;
+    }
+    
+    std::string LibXMLHelper::positionInfo(const xmlNode * nodePtr) const
+    {
+      stringstream strm;
+      strm << nodePtr->line;
+      return string("at line ") + strm.str();
+    }
+  }
+}
diff --git a/zypp/parser/LibXMLHelper.h b/zypp/parser/LibXMLHelper.h
new file mode 100644 (file)
index 0000000..d277203
--- /dev/null
@@ -0,0 +1,101 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ V / _` \___ \ | |   __) |                    |
+|                        | | (_| |___) || |  / __/                     |
+|                        |_|\__,_|____/ |_| |_____|                    |
+|                                                                      |
+|                               core system                            |
+|                                                        (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+File:       LibXMLHelper.h
+
+Author:     Michael Radziej <mir@suse.de>
+Maintainer: Michael Radziej <mir@suse.de>
+
+Purpose:    Helper class to deal with libxml2 with C++
+
+/-*/
+#ifndef LibXMLHelper_h
+#define LibXMLHelper_h
+#include <string>
+
+extern "C" {
+  struct _xmlNode;
+  typedef _xmlNode xmlNode;
+}
+
+ namespace zypp {
+
+  namespace parser {
+
+    /**
+     * @short Easy access to xmlNodes for C++
+     */
+    
+    class LibXMLHelper {
+    public:
+      /**
+       * The default constructor will return an object that does not
+       * look into the namespace properties of the nodes. Later, another
+       * constructor will be added that takes a list of namespaces as parameters
+       * (and maybe also character encoding information), and all nodes of different
+       * namespaces will be ignored (i.e., attributes will not be used, and for elements
+       * in different namespaces isElement() will return false).
+       */
+      LibXMLHelper();
+    
+      /**
+       * Destructor
+       */
+      virtual ~LibXMLHelper();
+    
+      /**
+       * Fetch an attribute
+       * @param node the xmlNode
+       * @param name name of the attribute
+       * @param defaultValue the value to return if this attribute does not exist
+       * @return the value of the attribute
+       */
+      std::string attribute(xmlNode * node, 
+                            const std::string &name, 
+                            const std::string &defaultValue = std::string()) const;
+    
+      /**
+       * @short The TEXT content of the node and all child nodes
+       * Read the value of a node, this can be either the text carried directly by this node if
+       * it's a TEXT node or the aggregate string of the values carried by this node child's
+       * (TEXT and ENTITY_REF). Entity references are substituted.
+       * @param nodePtr the xmlNode
+       * @return the content
+       */
+      std::string content(xmlNode * nodePtr) const;
+    
+      /**
+       * The name of the node
+       * @param nodePtr the xmlNode
+       * @return the name
+       */
+      std::string name(const xmlNode * nodePtr) const;
+    
+      /**
+       * returns whether this is an element node (and not, e.g., a attribute or namespace node)
+       * @param nodePtr the xmlNode
+       * @return true if it is an element node
+       */
+      bool isElement(const xmlNode * nodePtr) const;
+    
+      /**
+       * returns a string that identifies the position of an element nodes
+       * e.g. for error messages
+       * @param nodePtr the xmlNode
+       * @return the position information
+       */
+      std::string positionInfo(const xmlNode * nodePtr) const;
+    };
+  }
+}
+
+#endif
diff --git a/zypp/parser/Makefile.am b/zypp/parser/Makefile.am
new file mode 100644 (file)
index 0000000..df1349d
--- /dev/null
@@ -0,0 +1,23 @@
+## Process this file with automake to produce Makefile.in
+## ##################################################
+
+SUBDIRS =
+
+INCLUDES = -I$(oldincludedir)/libxml2
+
+## ##################################################
+
+include_HEADERS = \
+       XMLNodeIterator.h       \
+       LibXMLHelper.h
+
+
+noinst_LTLIBRARIES =   lib@PACKAGE@_parser.la
+
+## ##################################################
+
+lib@PACKAGE@_parser_la_SOURCES = \
+       XMLNodeIterator.cc      \
+       LibXMLHelper.cc
+
+## ##################################################
diff --git a/zypp/parser/XMLNodeIterator.cc b/zypp/parser/XMLNodeIterator.cc
new file mode 100644 (file)
index 0000000..2b46b63
--- /dev/null
@@ -0,0 +1,276 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ V / _` \___ \ | |   __) |                    |
+|                        | | (_| |___) || |  / __/                     |
+|                        |_|\__,_|____/ |_| |_____|                    |
+|                                                                      |
+|                               core system                            |
+|                                                        (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+  File:       XMLNodeIterator.cc
+
+  Author:     Michael Radziej <mir@suse.de>
+  Maintainer: Michael Radziej <mir@suse.de>
+
+  Purpose: Provides an iterator interface for XML files
+
+*/
+
+#include <XMLNodeIterator.h>
+#include <../base/Logger.h>
+#include <libxml2/libxml/xmlreader.h>
+#include <libxml2/libxml/xmlerror.h>
+
+namespace zypp {
+
+  namespace parser {
+
+    using namespace std;
+    
+    namespace{
+      /**
+       * Internal function to read from the input stream.
+       * This feeds the xmlTextReader used in the XMLNodeIterator.
+       * @param context points to the istream to read from
+       * @param buffer is to be filled with what's been read
+       * @param bufferLen max memory bytes to read
+       * @return
+       */
+      int ioread(void *context,
+                char *buffer,
+                int bufferLen)
+      {
+        assert(buffer);
+        std::istream *streamPtr = (std::istream *) context;
+        assert(streamPtr);
+        streamPtr->read(buffer,bufferLen);
+        return streamPtr->gcount();
+      }
+    
+      /**
+       * Internal function to finish reading.
+       * This is required by the xmlTextReader API, but
+       * not needed since the stream will be created when
+       * the istream object vanishes.
+       * @param context points to the istream to read from
+       * @return 0 on success.
+       */
+      int ioclose(void * context)
+      {
+        /* don't close. destructor will take care. */
+        return 0;
+      }
+    }
+    
+    XMLParserError::XMLParserError(const char *msg,
+                                       int severity,
+                                       xmlTextReaderLocatorPtr locator,
+                                       int docLine,
+                                       int docColumn)
+    throw()
+    : _msg(msg), _severity(severity), _locator(locator),
+    _docLine(docLine), _docColumn(docColumn)
+    { }
+    
+    XMLParserError::~XMLParserError() throw()
+    { }
+    
+    std::string XMLParserError::msg() const throw()
+    {
+      return _msg;
+    }
+    
+    int XMLParserError::severity() const throw()
+    {
+      return _severity;
+    }
+    
+    xmlTextReaderLocatorPtr XMLParserError::locator() const throw()
+    {
+      return _locator;
+    }
+    
+    int XMLParserError::docLine() const throw()
+    {
+      return _docLine;
+    }
+    
+    int XMLParserError::docColumn() const throw()
+    {
+      return _docColumn;
+    }
+    
+    std::string XMLParserError::position() const throw()
+    {
+      if (_docLine!=-1 && _docLine!=-1) {
+        std::stringstream strm;
+        strm << "at line " << _docLine
+          <<", column " << _docColumn;
+        return strm.str();
+      }
+      else
+        return "";
+    }
+    
+    std::ostream& operator<<(std::ostream &out, const XMLParserError& error)
+    {
+      const char *errOrWarn = (error.severity() & XML_PARSER_SEVERITY_ERROR) ? "error" : "warning";
+    out << "XML syntax " << errOrWarn << ": " << error.msg();
+      if (error.docLine()!=-1) {
+        out  << "at line " << error.docLine()
+          << ", column " << error.docColumn();
+      }
+      out << std::endl;
+      return out;
+    }
+    
+    
+    XMLNodeIteratorBase::XMLNodeIteratorBase(std::istream &input,
+                                             const std::string &baseUrl,
+                                             const char *validationPath)
+      : _error(0),
+      _input(& input),
+      _reader(xmlReaderForIO(ioread, ioclose, _input, baseUrl.c_str(), "utf-8",
+                             XML_PARSE_PEDANTIC)),
+      _baseUrl(baseUrl)
+    {
+      xmlTextReaderSetErrorHandler(_reader, (xmlTextReaderErrorFunc) errorHandler, this);
+      // xmlTextReaderSetStructuredErrorHandler(_reader, structuredErrorHandler, this);
+      if (_reader && validationPath)
+        if (xmlTextReaderRelaxNGValidate
+            (_reader,validationPath)==-1)
+          WAR << "Could not enable validation of repomd document" << std::endl;
+      
+        /* Derived classes must call fetchNext() in their constructors themselves,
+           XMLNodeIterator has no access to their virtual functions during
+           construction */
+    }
+    
+    XMLNodeIteratorBase::XMLNodeIteratorBase()
+    : _error(0), _input(0), _reader(0)
+    { }
+    
+    
+    
+    XMLNodeIteratorBase::~XMLNodeIteratorBase()
+    {
+      if (_reader != 0)
+        xmlFreeTextReader(_reader);
+    }
+    
+    
+    bool
+    XMLNodeIteratorBase::atEnd() const
+    {
+      return (_error.get() != 0
+              || getCurrent() == 0);
+    }
+    
+    
+    bool
+    XMLNodeIteratorBase::operator==(const XMLNodeIteratorBase &other) const
+    {
+      if (atEnd())
+        return other.atEnd();
+      else
+        return this != & other;
+    }
+    
+    
+    const XMLParserError *
+    XMLNodeIteratorBase::errorStatus() const
+    {
+      return _error.get();
+    }
+    
+    
+    void XMLNodeIteratorBase::fetchNext()
+    {
+      assert(_reader);
+      int status;
+      /* throw away the old entry */
+      setCurrent(0);
+      
+      if (_reader == 0) {
+          /* this is a trivial iterator over (max) only one element,
+             and we reach the end now. */
+        ;
+      }
+      else {
+          /* repeat as long as we successfully read nodes
+             breaks out when an interesting node has been found */
+        while ((status = xmlTextReaderRead(_reader))==1) {
+          xmlNodePtr node = xmlTextReaderCurrentNode(_reader);
+          if (isInterested(node)) {
+              // xmlDebugDumpNode(stdout,node,5);
+            _process(_reader);
+              // _currentDataPtr.reset(new ENTRYTYPE(process(_reader)));
+            status = xmlTextReaderNext(_reader);
+            break;
+          }
+        }
+        if (status == -1) {  // error occured
+          if (_error.get() == 0) {
+            errorHandler(this, "Unknown error while parsing xml file\n",
+                         XML_PARSER_SEVERITY_ERROR, 0);
+          }
+        }
+      }
+    }
+    
+    
+    void
+    XMLNodeIteratorBase::errorHandler(void * arg,
+                                      const char * msg,
+                                      int severity,
+                                      xmlTextReaderLocatorPtr locator)
+    {
+      XMLNodeIteratorBase *obj;
+      obj = (XMLNodeIteratorBase*) arg;
+      assert(obj);
+      xmlTextReaderPtr reader = obj->_reader;
+      if (strcmp("%s",msg) == 0) {
+          /* This works around a buglet in libxml2, you often get "%s" as message
+             and the message is in "severity". Does this work for other
+             architectures??? FIXME */
+        WAR << "libxml2 error reporting defect, got '%s' as message" << endl;
+        msg = (char *) severity;
+        severity = XML_PARSER_SEVERITY_WARNING;
+      }
+      const char *errOrWarn = (severity & XML_PARSER_SEVERITY_ERROR) ? "error" : "warning";
+      std::ostream& out = (severity & XML_PARSER_SEVERITY_ERROR) ? ERR : WAR;
+    
+        /* Log it */
+    out << "XML syntax " << errOrWarn << ": " << msg;
+      if (obj->_error.get()) {
+        out << "(encountered during error recovery!)" << std::endl;
+      }
+      if (reader && msg[0] != 0) {
+        out  << "at ";
+        if (! obj->_baseUrl.empty())
+          out << obj->_baseUrl << ", ";
+        out << "line " << xmlTextReaderGetParserLineNumber(reader)
+        << ", column " << xmlTextReaderGetParserColumnNumber(reader);
+      }
+      out << std::endl;
+      
+        /* save it */
+      if ((severity & XML_PARSER_SEVERITY_ERROR)
+          && ! obj->_error.get()) {
+            if (reader)
+              obj->_error.reset(new XMLParserError
+                                (msg, severity,locator,
+                                 xmlTextReaderLocatorLineNumber(locator),
+                                 xmlTextReaderGetParserColumnNumber(reader)));
+            else
+              obj->_error.reset(new XMLParserError
+                                (msg, severity, locator,
+                                 -1, -1));
+          }
+    }
+
+  }
+}
diff --git a/zypp/parser/XMLNodeIterator.h b/zypp/parser/XMLNodeIterator.h
new file mode 100644 (file)
index 0000000..14a7af1
--- /dev/null
@@ -0,0 +1,480 @@
+/*---------------------------------------------------------------------\
+|                                                                      |
+|                      __   __    ____ _____ ____                      |
+|                      \ \ / /_ _/ ___|_   _|___ \                     |
+|                       \ V / _` \___ \ | |   __) |                    |
+|                        | | (_| |___) || |  / __/                     |
+|                        |_|\__,_|____/ |_| |_____|                    |
+|                                                                      |
+|                               core system                            |
+|                                                        (C) SuSE GmbH |
+\----------------------------------------------------------------------/
+
+  File:       XMLNodeIterator.h
+
+  Author:     Michael Radziej <mir@suse.de>
+  Maintainer: Michael Radziej <mir@suse.de>
+
+  Purpose: Provides an iterator interface for XML files
+
+*/
+
+#ifndef XMLNodeIterator_h
+#define XMLNodeIterator_h
+
+#include <LibXMLHelper.h>
+#include <iostream>
+#include <ostream>
+#include <sstream>
+#include <cassert>
+#include <iterator>
+
+extern "C" {
+  typedef void * xmlTextReaderLocatorPtr;
+  struct _xmlNode;
+  typedef struct _xmlNode xmlNode;
+  typedef xmlNode *xmlNodePtr;
+
+  struct _xmlTextReader;
+  typedef _xmlTextReader xmlTextReader;
+  typedef xmlTextReader *xmlTextReaderPtr;
+
+  struct _xmlError;
+  typedef _xmlError xmlError;
+  typedef xmlError *xmlErrorPtr;
+}
+
+namespace zypp {
+
+  namespace parser {
+   
+    
+    /**
+     * @short class for reporting syntax errors in XMLNodeIterator.
+     */
+    class XMLParserError {
+    public:
+      /**
+       * Constructor
+       */
+      XMLParserError(const char *msg,
+                     int severity,
+                     xmlTextReaderLocatorPtr locator,
+                     int docLine,
+                     int docColumn) throw();
+    
+      ~XMLParserError() throw();
+    
+      /**
+       * The message of the errors
+       */
+      std::string msg() const throw();
+    
+      /**
+       * The severity of this error
+       */
+      int severity() const throw();
+    
+      /**
+       * See libxml2 documentation
+       */
+      xmlTextReaderLocatorPtr locator() const throw();
+    
+      /**
+       * The line number in the xml document where the error occurred.
+       */
+      int docLine() const throw();
+    
+      /**
+       * The column number in the xml document where the error occurred.
+       */
+      int docColumn() const throw();
+    
+      /**
+       * Gives a string describing the position in the xml document.
+       * (either empty, or "at line ..., column ...")
+       **/
+      std::string position() const throw();
+    
+    private:
+    
+      std::string _msg;
+      int _severity;
+      xmlTextReaderLocatorPtr _locator;
+      int _docLine;
+      int _docColumn;
+    };
+    
+    
+    std::ostream& operator<<(std::ostream &out, const XMLParserError& error);
+    
+    
+    
+    /**
+     *
+     * @short Abstract class to iterate over an xml stream
+     *
+     * Derive from XMLNodeIterator<ENTRYTYPE> to get an iterator
+     * that returns ENTRYTYPE objects. A derived class must provide
+     * isInterested() and process(). It should also provide a
+     * Constructor Derived(std::stream,std::string baseUrl) which
+     * must call fetchNext().
+     *
+     * The derived iterator class should be compatible with an stl
+     * input iterator. Use like this:
+     *
+     * for (Iterator iter(anIstream, baseUrl),
+     *      iter != Iterator.end(),     // or: iter() != 0, or ! iter.atEnd()
+     *      ++iter) {
+     *    doSomething(*iter)
+     * }
+     *
+     * The iterator owns the pointer (i.e., caller must not delete it)
+     * until the next ++ operator is called. At this time, it will be
+     * destroyed (and a new ENTRYTYPE is created.)
+     *
+     * If the input is fundamentally flawed so that it makes no sense to
+     * continue parsing, XMLNodeIterator will log it and consider the input as finished.
+     * You can query the exit status with errorStatus().
+     */
+    
+     
+    class XMLNodeIteratorBase {
+    public:
+      /**
+       * Constructor. Derived classes must call fetchNext() here.
+       * @param input is the input stream (contains the xml stuff)
+       * @param baseUrl is the base URL of the xml document
+       * FIXME: use XMLParserError::operator<< instead of doing it on my own.
+       */
+      XMLNodeIteratorBase(std::istream &input, 
+                          const std::string &baseUrl,
+                          const char *validationPath = 0);
+    
+      /**
+       * Constructor for an empty iterator.
+       * An empty iterator is already at its end.
+       * This is what end() returns ...
+       */
+      XMLNodeIteratorBase();
+    
+      /**
+       * Destructor
+       */
+      virtual ~XMLNodeIteratorBase();
+    
+      /**
+       * Have we reached the end?
+       * A parser error also means "end reached"
+       * @return whether the end has been reached.
+       */
+      bool atEnd() const;
+    
+      /**
+       * Two iterators are equal if both are at the end
+       * or if they are identical.
+       * Since you cannot copy an XMLNodeIterator, everything
+       * else is not equal.
+       * @param other the other iterator
+       * @return true if equal
+       */
+      bool 
+      operator==(const XMLNodeIteratorBase &other) const;
+    
+      /**
+       * Opposit of operator==
+       * @param other the other iterator
+       * @return true if not equal
+       */
+      bool 
+      operator!=(const XMLNodeIteratorBase &otherNode) const
+      {
+        return ! operator==(otherNode);
+      }
+    
+      /**
+       * returns the error status or 0 if no error
+       * the returned pointer is not-owning,
+       * it will be deleted upon destruction of the XMLNodeIterator.
+       * @return pointer to error status (if exists)
+       */
+      const XMLParserError *
+      errorStatus() const;
+    
+    protected:
+    
+      /**
+       * filter for the xml nodes
+       * The derived class decides which xml nodes it is actually interested in.
+       * For each that is selected, process() will be called an the resulting ENTRYTYPE
+       * object used as the next value for the iterator.
+       * Documentation for the node structure can be found in the libxml2 documentation.
+       * Have a look at LibXMLHelper to access node attributes and contents.
+       * @param nodePtr points to the xml node in question. Only the node is available, not the subtree.
+       *                See libxml2 documentation.
+       * @return true if interested
+       */
+      virtual bool
+      isInterested(const xmlNodePtr nodePtr) = 0;
+      
+      /**
+       * process an xml node and set it as next element
+       * The derived class has to produce the ENTRYTYPE object here.
+       * Details about the xml reader is in the libxml2 documentation.
+       * You'll most probably want to use xmlTextReaderExpand(reader) to
+       * request the full subtree, and then use the links in the resulting 
+       * node structure to traverse, and class LibXMLHelper to access the 
+       * attributes and element contents.
+       * fetchNext() cannot throw an error since it will be called in the constructor.
+       * Instead, in case of a fundamental syntax error the error is saved
+       * and will be thrown with the next checkError().
+       * @param readerPtr points to the xmlTextReader that reads the xml stream.
+       */
+      virtual void
+      _process(const xmlTextReaderPtr readerPtr) = 0;
+      
+      /**
+       * Fetch the next element and save it as next element
+       */
+      void fetchNext();
+    
+      /**
+       * Internal function to set the _error variable
+       * in case of a parser error. It logs the message
+       * and saves errors in _error, so that they will
+       * be thrown by checkError().
+       * @param arg set to this with xmlReaderSetErrorHandler()
+       * @param msg the error message
+       * @param severity the severity
+       * @param locator as defined by libxml2
+       */
+      static void
+      errorHandler(void * arg,
+                   const char * msg,
+                   int severity,
+                   xmlTextReaderLocatorPtr locator);
+    
+      
+      virtual void setCurrent(const void *data) = 0;
+      virtual void* getCurrent() const = 0;
+    
+    private:
+    
+      /**
+       * assignment is forbidden.
+       * Reason: We can't copy an xmlTextReader
+       */
+      XMLNodeIteratorBase & operator=(const XMLNodeIteratorBase& otherNode);
+    
+      /**
+       * copy constructor is forbidden.
+       * Reason: We can't copy an xmlTextReader
+       * FIXME: This prevents implementing the end() method for derived classes.
+       * 
+       * @param otherNode 
+       * @return 
+       */
+      XMLNodeIteratorBase(const XMLNodeIteratorBase& otherNode);
+    
+      /**
+       * if an error occured, this contains the error.
+       */
+      std::auto_ptr<XMLParserError> _error;
+    
+      /**
+       * contains the istream to read the xml file from.
+       * Can be 0 if at end or if the current element is the only element left.
+       **/
+      std::istream* _input;
+      
+      /**
+       * contains the xmlTextReader used to parse the xml file.
+       **/
+      xmlTextReaderPtr _reader;
+    
+      /**
+       * contains the base URL of the xml documentation
+       */
+      std::string _baseUrl;
+    }; /* end class XMLNodeIteratorBase */
+    
+    
+    
+    /* --------------------------------------------------------------------------- */
+    
+    template <class ENTRYTYPE>
+    class XMLNodeIterator : public XMLNodeIteratorBase,
+                            public std::iterator<std::input_iterator_tag, ENTRYTYPE>  {
+    public:
+      /**
+       * Constructor. Derived classes must call fetchNext() here.
+       * @param input is the input stream (contains the xml stuff)
+       * @param baseUrl is the base URL of the xml document
+       * FIXME: use XMLParserError::operator<< instead of doing it on my own.
+       */
+      XMLNodeIterator(std::istream &input,
+                      const std::string &baseUrl,
+                      const char *validationPath = 0)
+        : XMLNodeIteratorBase(input, baseUrl, validationPath), _current(0)
+      {
+        /* Derived classes must call fetchNext() in their constructors themselves,
+           XMLNodeIterator has no access to their virtual functions during
+           construction */
+      }
+      
+      
+      /**
+       * Constructor for a trivial iterator.
+       * A trivial iterator contains only one element.
+       * This is at least needed internally for the
+       * postinc (iter++) operator
+       * @param entry is the one and only element of this iterator.
+       */
+      XMLNodeIterator(ENTRYTYPE &entry)
+        : XMLNodeIteratorBase()
+      { 
+        setCurrent((void *)& entry);
+      }
+      
+      /**
+       * Constructor for an empty iterator.
+       * An empty iterator is already at its end.
+       * This is what end() returns ...
+       */
+      XMLNodeIterator()
+        : XMLNodeIteratorBase(), _current(0)
+      { }
+      
+      /**
+       * Destructor
+       */
+      virtual ~XMLNodeIterator()
+      { }
+      
+      /**
+       * Fetch a pointer to the current element
+       * @return pointer to the current element.
+       */
+      ENTRYTYPE &
+        operator*() const
+      {
+        assert (! atEnd());
+        return * (ENTRYTYPE *) getCurrent();
+      }
+      
+      /**
+       * Fetch the current element
+       * @return the current element
+       */
+      ENTRYTYPE *
+        operator()() const
+      {
+        if (_error)
+          return 0;
+        else
+          return getCurrent();
+      }
+      
+      /**
+       * Go to the next element and return it
+       * @return the next element
+       */
+      XMLNodeIterator<ENTRYTYPE> &  /* ++iter */
+      operator++() {
+        fetchNext();
+        return *this;
+      }
+      
+      /**
+       * remember the current element, go to next and return remembered one.
+       * avoid this, usually you need the preinc operator (++iter)
+       * This function may throw ParserError if something is fundamentally wrong
+       * with the input.
+       * @return the current element
+       */
+      XMLNodeIterator operator++(int)   /* iter++ */
+      {
+        assert (!atEnd());
+        XMLNodeIterator<ENTRYTYPE> tmp(operator()());
+        fetchNext();
+        return tmp;
+      }
+      
+      /**
+       * similar to operator*, allows direct member access
+       * @return pointer to current element
+       */
+      const ENTRYTYPE *
+        operator->()
+      {
+        assert(! atEnd());
+        return getCurrent();
+      }
+      
+    protected:
+      
+      /**
+       * filter for the xml nodes
+       * The derived class decides which xml nodes it is actually interested in.
+       * For each that is selected, process() will be called an the resulting ENTRYTYPE
+       * object used as the next value for the iterator.
+       * Documentation for the node structure can be found in the libxml2 documentation.
+       * Have a look at LibXMLHelper to access node attributes and contents.
+       * @param nodePtr points to the xml node in question. Only the node is available, not the subtree.
+       *                See libxml2 documentation.
+       * @return true if interested
+       */
+      virtual bool
+        isInterested(const xmlNodePtr nodePtr) = 0;
+      
+      /**
+       * process an xml node
+       * The derived class has to produce the ENTRYTYPE object here.
+       * Details about the xml reader is in the libxml2 documentation.
+       * You'll most probably want to use xmlTextReaderExpand(reader) to
+       * request the full subtree, and then use the links in the resulting
+       * node structure to traverse, and class LibXMLHelper to access the
+       * attributes and element contents.
+       * fetchNext() cannot throw an error since it will be called in the constructor.
+       * Instead, in case of a fundamental syntax error the error is saved
+       * and will be thrown with the next checkError().
+       * @param readerPtr points to the xmlTextReader that reads the xml stream.
+       * @return
+       */
+      virtual ENTRYTYPE
+      process(const xmlTextReaderPtr readerPtr) = 0;
+    
+      void
+      _process(const xmlTextReaderPtr readerPtr)
+      {
+        setCurrent(new ENTRYTYPE(process(readerPtr)));
+      }
+    
+    private:
+    
+      void setCurrent(const void *data)
+      {
+        if (data)
+          _current.reset(new ENTRYTYPE(* (ENTRYTYPE *) data));
+        else
+          _current.reset(0);
+      }
+    
+      void *getCurrent() const
+      {
+        return _current.get();
+      }
+      
+      /**
+       * contains the current element of the iterator.
+       * a pointer is used to be able to handle non-assigneable ENTRYTYPEs.
+       * The iterator owns the element until the next ++ operation.
+       * It can be 0 when the end has been reached.
+       **/
+      std::auto_ptr<ENTRYTYPE> _current;
+    }; /* end class XMLNodeIterator */
+    
+  }
+}
+
+#endif