00001
00002
00003
00004
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
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
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
00141 }
00142
00143
00144
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
00190 setCurrent(0);
00191
00192 if (_reader == 0) {
00193
00194
00195 ;
00196 }
00197 else {
00198
00199
00200 while ((status = xmlTextReaderRead(_reader))==1) {
00201 xmlNodePtr node = xmlTextReaderCurrentNode(_reader);
00202 if (isInterested(node)) {
00203
00204 _process(_reader);
00205
00206 status = xmlTextReaderNext(_reader);
00207 break;
00208 }
00209 }
00210 if (status == -1) {
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
00232
00233
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
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
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 }