AISDatabaseParser.cc

Go to the documentation of this file.
00001 
00002 // -*- mode: c++; c-basic-offset:4 -*-
00003 
00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00005 // Access Protocol.
00006 
00007 // Copyright (c) 2003 OPeNDAP, Inc.
00008 // Author: James Gallagher <jgallagher@opendap.org>
00009 //
00010 // This library is free software; you can redistribute it and/or
00011 // modify it under the terms of the GNU Lesser General Public
00012 // License as published by the Free Software Foundation; either
00013 // version 2.1 of the License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 //
00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00025 
00026 #include "config.h"
00027 
00028 #include <cstring>
00029 #include <stdarg.h>
00030 
00031 #ifdef WIN32
00032 #define vsnprintf _vsnprintf
00033 #endif
00034 
00035 #include "AISDatabaseParser.h"
00036 #include "util.h"
00037 #include "debug.h"
00038 
00039 using namespace std;
00040 
00041 namespace libdap {
00042 
00043 static const not_used char *states[] =
00044     {
00045         "START",
00046         "FINISH",
00047         "AIS",
00048         "ENTRY",
00049         "PRIMARY",
00050         "ANCILLARY",
00051         "UNKNOWN",
00052         "ERROR"
00053     };
00054 
00061 
00065 void
00066 AISDatabaseParser::aisStartDocument(AISParserState *state)
00067 {
00068     state->state = PARSER_START;
00069     state->unknown_depth = 0;
00070     state->prev_state = PARSER_UNKNOWN;
00071     state->error_msg = "";
00072 
00073     DBG2(cerr << "Parser state: " << states[state->state] << endl);
00074 }
00075 
00078 void
00079 AISDatabaseParser::aisEndDocument(AISParserState *state)
00080 {
00081     DBG2(cerr << "Ending state == " << states[state->state] << endl);
00082 
00083     if (state->unknown_depth != 0) {
00084         AISDatabaseParser::aisFatalError(state, "The document contained unbalanced tags.");
00085 
00086         DBG(cerr << "unknown_depth != 0 (" << state->unknown_depth << ")"
00087             << endl);
00088     }
00089 }
00090 
00099 void
00100 AISDatabaseParser::aisStartElement(AISParserState *state, const char *name,
00101                                    const char **attrs)
00102 {
00103     switch (state->state) {
00104     case PARSER_START:
00105         if (strcmp(name, "ais") != 0) {
00106             DBG(cerr << "Expecting ais.  Got " << name << endl);
00107         }
00108         state->state = AIS;
00109         break;
00110 
00111     case PARSER_FINISH:
00112         break;
00113 
00114     case AIS:
00115         if (strcmp(name, "entry") == 0) {
00116             state->prev_state = state->state;
00117             state->state = ENTRY;
00118         }
00119         else {
00120             state->prev_state = state->state;
00121             state->state = PARSER_UNKNOWN;
00122             state->unknown_depth++;
00123         }
00124         break;
00125 
00126     case ENTRY:
00127         if (strcmp(name, "primary") == 0) {
00128             state->prev_state = state->state;
00129             state->state = PRIMARY;
00130 
00131             if (attrs) {
00132                 if (strcmp(attrs[0], "url") == 0) {
00133                     state->regexp = false;
00134                     state->primary = attrs[1];
00135                 }
00136                 else if (strcmp(attrs[0], "regexp") == 0) {
00137                     state->regexp = true;
00138                     state->primary = attrs[1];
00139                 }
00140             }
00141             else {
00142                 AISDatabaseParser::aisFatalError(state, "Required attribute 'url' or 'regexp' missing from element 'primary'.");
00143                 break;
00144             }
00145         }
00146         else if (strcmp(name, "ancillary") == 0) {
00147             state->prev_state = state->state;
00148             state->state = ANCILLARY;
00149 
00150             string url = ""; // set defaults, MUST have url
00151             string rule = "overwrite";
00152             for (int i = 0; attrs && attrs[i] != 0; i = i + 2) {
00153                 if (strcmp(attrs[i], "url") == 0)
00154                     url = attrs[i+1];
00155                 else if (strcmp(attrs[i], "rule") == 0)
00156                     rule = attrs[i+1];
00157             }
00158 
00159             // If this parser validated the XML, these tests would be
00160             // unnecessary.
00161             if (url == "") {
00162                 AISDatabaseParser::aisFatalError(state, "Required attribute 'url' missing from element 'ancillary'.");
00163                 break;
00164             }
00165 
00166             if (rule != "overwrite" && rule != "replace" && rule != "fallback") {
00167                 string msg = string("Optional attribute 'rule' in element 'ancillary' has a bad value: ") + rule + "\nIt should be one of 'overwrite', 'replace' or 'fallback'.";
00168                 AISDatabaseParser::aisFatalError(state, msg.c_str());
00169                 break;
00170             }
00171 
00172             Resource r(url, rule);
00173             state->rv.push_back(r);
00174         }
00175         else {
00176             state->prev_state = state->state;
00177             state->state = PARSER_UNKNOWN;
00178             state->unknown_depth++;
00179         }
00180         break;
00181 
00182     case PRIMARY:
00183         break;
00184 
00185     case ANCILLARY:
00186         break;
00187 
00188     case PARSER_UNKNOWN:
00189         state->unknown_depth++;
00190         break;
00191 
00192     case PARSER_ERROR:
00193         break;
00194     }
00195 
00196     DBG2(cerr << "Start element " << name << " (state "
00197          << states[state->state] << ")" << endl);
00198 }
00199 
00204 void
00205 AISDatabaseParser::aisEndElement(AISParserState *state, const char *)
00206 {
00207     DBG2(cerr << "End element " << name << " (state " << states[state->state]
00208          << ")" << endl);
00209 
00210     switch (state->state) {
00211     case AIS:
00212         state->prev_state = state->state;
00213         state->state = PARSER_FINISH;
00214         break;
00215 
00216     case ENTRY:
00217         state->prev_state = state->state;
00218         state->state = AIS;
00219 
00220         // record 'primary' and 'rv'
00221         if (state->regexp)
00222             state->ais->add_regexp_resource(state->primary, state->rv);
00223         else
00224             state->ais->add_url_resource(state->primary, state->rv);
00225 
00226         // empty rv for the next set of ancillary resources.
00227         state->rv.erase(state->rv.begin(), state->rv.end());
00228         break;
00229 
00230     case PRIMARY:
00231         state->prev_state = state->state;
00232         state->state = ENTRY;
00233         break;
00234 
00235     case ANCILLARY:
00236         state->prev_state = state->state;
00237         state->state = ENTRY;
00238         break;
00239 
00240     case PARSER_UNKNOWN:
00241         // Leave the state and prev_state alone.
00242         state->unknown_depth--;
00243         break;
00244 
00245     case PARSER_ERROR:
00246         break;
00247 
00248     default:
00249         break;
00250     }
00251 }
00252 
00256 xmlEntityPtr
00257 AISDatabaseParser::aisGetEntity(AISParserState *, const xmlChar *name)
00258 {
00259     return xmlGetPredefinedEntity(name);
00260 }
00261 
00266 void
00267 AISDatabaseParser::aisWarning(AISParserState *state, const char *msg, ...)
00268 {
00269     va_list args;
00270 
00271     state->state = PARSER_ERROR;
00272 
00273     va_start(args, msg);
00274     char str[1024];
00275     vsnprintf(str, 1024, msg, args);
00276     va_end(args);
00277 
00278 #ifdef LIBXML2_6_16
00279     // Defined if libxml2 >= 2.6.16
00280     int line = xmlSAX2GetLineNumber(state->ctxt);
00281 #else
00282     int line = getLineNumber(state->ctxt);
00283 #endif
00284     state->error_msg += "At line: " + long_to_string(line) + ": ";
00285     state->error_msg += string(str) + string("\n");
00286 }
00287 
00292 void
00293 AISDatabaseParser::aisError(AISParserState *state, const char *msg, ...)
00294 {
00295     va_list args;
00296 
00297     state->state = PARSER_ERROR;
00298 
00299     va_start(args, msg);
00300     char str[1024];
00301     vsnprintf(str, 1024, msg, args);
00302     va_end(args);
00303 
00304 #ifdef LIBXML2_6_16
00305     // Defined if libxml2 >= 2.6.16
00306     int line = xmlSAX2GetLineNumber(state->ctxt);
00307 #else
00308     int line = getLineNumber(state->ctxt);
00309 #endif
00310     state->error_msg += "At line: " + long_to_string(line) + ": ";
00311     state->error_msg += string(str) + string("\n");
00312 }
00313 
00317 void
00318 AISDatabaseParser::aisFatalError(AISParserState *state, const char *msg, ...)
00319 {
00320     va_list args;
00321 
00322     state->state = PARSER_ERROR;
00323 
00324     va_start(args, msg);
00325     char str[1024];
00326     vsnprintf(str, 1024, msg, args);
00327     va_end(args);
00328 
00329 #ifdef LIBXML2_6_16
00330     // Defined if libxml2 >= 2.6.16
00331     int line = xmlSAX2GetLineNumber(state->ctxt);
00332 #else
00333     int line = getLineNumber(state->ctxt);
00334 #endif
00335     state->error_msg += "At line: " + long_to_string(line) + ": ";
00336     state->error_msg += string(str) + string("\n");
00337 }
00338 
00340 
00343 static xmlSAXHandler aisSAXParser =
00344     {
00345         0, // internalSubset
00346         0, // isStandalone
00347         0, // hasInternalSubset
00348         0, // hasExternalSubset
00349         0, // resolveEntity
00350         (getEntitySAXFunc)AISDatabaseParser::aisGetEntity, // getEntity
00351         0, // entityDecl
00352         0, // notationDecl
00353         0, // attributeDecl
00354         0, // elementDecl
00355         0, // unparsedEntityDecl
00356         0, // setDocumentLocator
00357         (startDocumentSAXFunc)AISDatabaseParser::aisStartDocument, // startDocument
00358         (endDocumentSAXFunc)AISDatabaseParser::aisEndDocument,  // endDocument
00359         (startElementSAXFunc)AISDatabaseParser::aisStartElement,  // startElement
00360         (endElementSAXFunc)AISDatabaseParser::aisEndElement,  // endElement
00361         0, // reference
00362         0, // (charactersSAXFunc)gladeCharacters,  characters
00363         0, // ignorableWhitespace
00364         0, // processingInstruction
00365         0, // (commentSAXFunc)gladeComment,  comment
00366         (warningSAXFunc)AISDatabaseParser::aisWarning, // warning
00367         (errorSAXFunc)AISDatabaseParser::aisError, // error
00368         (fatalErrorSAXFunc)AISDatabaseParser::aisFatalError, // fatalError
00369 #ifdef LIBXML2_5_10
00370         0, // getParameterEntity
00371         0, // cdataBlock
00372         0, // externalSubset
00373         0, // initialized
00374 #endif
00375 #ifdef LIBXML2_6_16
00376         0, // _private
00377         0, // endElementNs
00378         0, // serror
00379         0 // startElementNs
00380 #endif
00381     };
00382 
00389 void
00390 AISDatabaseParser::intern(const string &database, AISResources *ais)
00391 {
00392     xmlParserCtxtPtr ctxt;
00393     AISParserState state;
00394 
00395     ctxt = xmlCreateFileParserCtxt(database.c_str());
00396     if (!ctxt)
00397         return;
00398 
00399     state.ais = ais;  // dump values here
00400     state.ctxt = ctxt;  // need ctxt for error messages
00401 
00402     ctxt->sax = &aisSAXParser;
00403     ctxt->userData = &state;
00404     ctxt->validate = true;
00405 
00406     xmlParseDocument(ctxt);
00407 
00408     // use getLineNumber and getColumnNumber to make the error messages better.
00409     if (!ctxt->wellFormed) {
00410         ctxt->sax = NULL;
00411         xmlFreeParserCtxt(ctxt);
00412         throw AISDatabaseReadFailed(string("\nThe database is not a well formed XML document.\n") + state.error_msg);
00413     }
00414 
00415     if (!ctxt->valid) {
00416         ctxt->sax = NULL;
00417         xmlFreeParserCtxt(ctxt);
00418         throw AISDatabaseReadFailed(string("\nThe database is not a valid document.\n") + state.error_msg);
00419     }
00420 
00421     if (state.state == PARSER_ERROR) {
00422         ctxt->sax = NULL;
00423         xmlFreeParserCtxt(ctxt);
00424         throw AISDatabaseReadFailed(string("\nError parsing AIS resources.\n") + state.error_msg);
00425     }
00426 
00427     ctxt->sax = NULL;
00428     xmlFreeParserCtxt(ctxt);
00429 }
00430 
00431 } // namespace libdap

Generated on Wed Mar 5 15:27:10 2008 for libdap++ by  doxygen 1.5.4