zypp/Makefile \
zypp/base/Makefile \
zypp/detail/Makefile \
- zypp/capability/Makefile
+ zypp/capability/Makefile \
+ zypp/parser/Makefile
)
dnl ==================================================
// 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;
}
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;
## Process this file with automake to produce Makefile.in
## ##################################################
-SUBDIRS = base detail capability
+SUBDIRS = base detail capability parser
## ##################################################
lib@PACKAGE@_la_LIBADD = base/lib@PACKAGE@_base.la \
detail/lib@PACKAGE@_detail.la \
capability/lib@PACKAGE@_capability.la
+ parser/lib@PACKAGE@_parser.la
## ##################################################
--- /dev/null
+#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();
+ }
+ }
+}
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ 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
--- /dev/null
+## 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
+
+## ##################################################
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ 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));
+ }
+ }
+
+ }
+}
--- /dev/null
+/*---------------------------------------------------------------------\
+| |
+| __ __ ____ _____ ____ |
+| \ \ / /_ _/ ___|_ _|___ \ |
+| \ 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