XMLNodeIterator.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00013 #include <zypp/parser/XMLNodeIterator.h>
00014 #include <zypp/base/Logger.h>
00015 #include <libxml2/libxml/xmlreader.h>
00016 #include <libxml2/libxml/xmlerror.h>
00017 
00018 namespace zypp {
00019 
00020   namespace parser {
00021 
00022     using namespace std;
00023 
00024     namespace{
00033       int ioread(void *context,
00034                 char *buffer,
00035                 int bufferLen)
00036       {
00037         xml_assert(buffer);
00038         std::istream *streamPtr = (std::istream *) context;
00039         xml_assert(streamPtr);
00040         streamPtr->read(buffer,bufferLen);
00041         return streamPtr->gcount();
00042       }
00043 
00052       int ioclose(void * context)
00053       {
00054         /* don't close. destructor will take care. */
00055         return 0;
00056       }
00057     }
00058 
00059     XMLParserError::XMLParserError(const char *msg,
00060                                        int severity,
00061                                        xmlTextReaderLocatorPtr locator,
00062                                        int docLine,
00063                                        int docColumn)
00064     throw()
00065     : _msg(msg), _severity(severity), _locator(locator),
00066     _docLine(docLine), _docColumn(docColumn)
00067     { }
00068 
00069     XMLParserError::~XMLParserError() throw()
00070     { }
00071 
00072     std::string XMLParserError::msg() const throw()
00073     {
00074       return _msg;
00075     }
00076 
00077     int XMLParserError::severity() const throw()
00078     {
00079       return _severity;
00080     }
00081 
00082     xmlTextReaderLocatorPtr XMLParserError::locator() const throw()
00083     {
00084       return _locator;
00085     }
00086 
00087     int XMLParserError::docLine() const throw()
00088     {
00089       return _docLine;
00090     }
00091 
00092     int XMLParserError::docColumn() const throw()
00093     {
00094       return _docColumn;
00095     }
00096 
00097     std::string XMLParserError::position() const throw()
00098     {
00099       if (_docLine!=-1 && _docLine!=-1) {
00100         std::stringstream strm;
00101         strm << "at line " << _docLine
00102           <<", column " << _docColumn;
00103         return strm.str();
00104       }
00105       else
00106         return "";
00107     }
00108 
00109     std::ostream& operator<<(std::ostream &out, const XMLParserError& error)
00110     {
00111       const char *errOrWarn = (error.severity() & XML_PARSER_SEVERITY_ERROR) ? "error" : "warning";
00112     out << "XML syntax " << errOrWarn << ": " << error.msg();
00113       if (error.docLine()!=-1) {
00114         out  << "at line " << error.docLine()
00115           << ", column " << error.docColumn();
00116       }
00117       out << std::endl;
00118       return out;
00119     }
00120 
00121 
00122     XMLNodeIteratorBase::XMLNodeIteratorBase(std::istream &input,
00123                                              const std::string &baseUrl,
00124                                              const char *validationPath)
00125       : _error(0),
00126       _input(& input),
00127       _reader(xmlReaderForIO(ioread, ioclose, _input, baseUrl.c_str(), "utf-8",
00128                              XML_PARSE_PEDANTIC)),
00129       _baseUrl(baseUrl)
00130     {
00131       xmlTextReaderSetErrorHandler(_reader, (xmlTextReaderErrorFunc) errorHandler, this);
00132       // xmlTextReaderSetStructuredErrorHandler(_reader, structuredErrorHandler, this);
00133       if (_reader )
00134       {
00135         if ( validationPath )
00136         {
00137             if (xmlTextReaderRelaxNGValidate(_reader,validationPath)==-1)
00138               WAR << "Could not enable validation of document using " << validationPath << std::endl;
00139         }
00140         // otherwise validation is disabled.
00141       }
00142         /* Derived classes must call fetchNext() in their constructors themselves,
00143            XMLNodeIterator has no access to their virtual functions during
00144            construction */
00145     }
00146 
00147     XMLNodeIteratorBase::XMLNodeIteratorBase()
00148     : _error(0), _input(0), _reader(0)
00149     { }
00150 
00151 
00152 
00153     XMLNodeIteratorBase::~XMLNodeIteratorBase()
00154     {
00155       if (_reader != 0)
00156         xmlFreeTextReader(_reader);
00157     }
00158 
00159 
00160     bool
00161     XMLNodeIteratorBase::atEnd() const
00162     {
00163       return (_error.get() != 0
00164               || getCurrent() == 0);
00165     }
00166 
00167 
00168     bool
00169     XMLNodeIteratorBase::operator==(const XMLNodeIteratorBase &other) const
00170     {
00171       if (atEnd())
00172         return other.atEnd();
00173       else
00174         return this == & other;
00175     }
00176 
00177 
00178     const XMLParserError *
00179     XMLNodeIteratorBase::errorStatus() const
00180     {
00181       return _error.get();
00182     }
00183 
00184 
00185     void XMLNodeIteratorBase::fetchNext()
00186     {
00187       xml_assert(_reader);
00188       int status;
00189       /* throw away the old entry */
00190       setCurrent(0);
00191 
00192       if (_reader == 0) {
00193           /* this is a trivial iterator over (max) only one element,
00194              and we reach the end now. */
00195         ;
00196       }
00197       else {
00198           /* repeat as long as we successfully read nodes
00199              breaks out when an interesting node has been found */
00200         while ((status = xmlTextReaderRead(_reader))==1) {
00201           xmlNodePtr node = xmlTextReaderCurrentNode(_reader);
00202           if (isInterested(node)) {
00203               // xmlDebugDumpNode(stdout,node,5);
00204             _process(_reader);
00205               // _currentDataPtr.reset(new ENTRYTYPE(process(_reader)));
00206             status = xmlTextReaderNext(_reader);
00207             break;
00208           }
00209         }
00210         if (status == -1) {  // error occured
00211           if (_error.get() == 0) {
00212             errorHandler(this, "Unknown error while parsing xml file\n",
00213                          XML_PARSER_SEVERITY_ERROR, 0);
00214           }
00215         }
00216       }
00217     }
00218 
00219 
00220     void
00221     XMLNodeIteratorBase::errorHandler(void * arg,
00222                                       const char * msg,
00223                                       int severity,
00224                                       xmlTextReaderLocatorPtr locator)
00225     {
00226       XMLNodeIteratorBase *obj;
00227       obj = (XMLNodeIteratorBase*) arg;
00228       xml_assert(obj);
00229       xmlTextReaderPtr reader = obj->_reader;
00230       if (strcmp("%s",msg) == 0) {
00231           /* This works around a buglet in libxml2, you often get "%s" as message
00232              and the message is in "severity". Does this work for other
00233              architectures??? FIXME */
00234         WAR << "libxml2 error reporting defect, got '%s' as message" << endl;
00235         msg = (char *) severity;
00236         severity = XML_PARSER_SEVERITY_WARNING;
00237       }
00238       const char *errOrWarn = (severity & XML_PARSER_SEVERITY_ERROR) ? "error" : "warning";
00239 
00240 #if 0
00241       std::ostream& out = (severity & XML_PARSER_SEVERITY_ERROR) ? ERR : WAR;
00242 
00243         /* Log it */
00244     out << "XML syntax " << errOrWarn << ": " << msg;
00245       if (obj->_error.get()) {
00246         out << "(encountered during error recovery!)" << std::endl;
00247       }
00248       if (reader && msg[0] != 0) {
00249         out  << "at ";
00250         if (! obj->_baseUrl.empty())
00251           out << obj->_baseUrl << ", ";
00252         out << "line " << xmlTextReaderGetParserLineNumber(reader)
00253         << ", column " << xmlTextReaderGetParserColumnNumber(reader);
00254       }
00255       out << std::endl;
00256 #endif
00257         /* save it */
00258       if ((severity & XML_PARSER_SEVERITY_ERROR)
00259           && ! obj->_error.get()) {
00260             if (reader)
00261               obj->_error.reset(new XMLParserError
00262                                 (msg, severity,locator,
00263                                  xmlTextReaderLocatorLineNumber(locator),
00264                                  xmlTextReaderGetParserColumnNumber(reader)));
00265             else
00266               obj->_error.reset(new XMLParserError
00267                                 (msg, severity, locator,
00268                                  -1, -1));
00269           }
00270     }
00271 
00272   }
00273 }

Generated on Thu Jul 6 00:07:21 2006 for zypp by  doxygen 1.4.6