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 <stdio.h>
00029 #include <stdlib.h>
00030 #include <stdarg.h>
00031 
00032 #ifdef WIN32
00033 #define vsnprintf _vsnprintf
00034 #endif
00035 
00036 #include "AISDatabaseParser.h"
00037 #include "util.h"
00038 #include "debug.h"
00039 
00040 using namespace std;
00041 
00042 static const not_used char *states[] =
00043     {
00044         "START",
00045         "FINISH",
00046         "AIS",
00047         "ENTRY",
00048         "PRIMARY",
00049         "ANCILLARY",
00050         "UNKNOWN",
00051         "ERROR"
00052     };
00053 
00060 
00064 void
00065 AISDatabaseParser::aisStartDocument(AISParserState *state)
00066 {
00067     state->state = PARSER_START;
00068     state->unknown_depth = 0;
00069     state->prev_state = PARSER_UNKNOWN;
00070     state->error_msg = "";
00071 
00072     DBG2(cerr << "Parser state: " << states[state->state] << endl);
00073 }
00074 
00077 void
00078 AISDatabaseParser::aisEndDocument(AISParserState *state)
00079 {
00080     DBG2(cerr << "Ending state == " << states[state->state] << endl);
00081 
00082     if (state->unknown_depth != 0) {
00083         AISDatabaseParser::aisFatalError(state, "The document contained unbalanced tags.");
00084 
00085         DBG(cerr << "unknown_depth != 0 (" << state->unknown_depth << ")"
00086             << endl);
00087     }
00088 }
00089 
00098 void
00099 AISDatabaseParser::aisStartElement(AISParserState *state, const char *name,
00100                                    const char **attrs)
00101 {
00102     switch (state->state) {
00103     case PARSER_START:
00104         if (strcmp(name, "ais") != 0) {
00105             DBG(cerr << "Expecting ais.  Got " << name << endl);
00106         }
00107         state->state = AIS;
00108         break;
00109 
00110     case PARSER_FINISH:
00111         break;
00112 
00113     case AIS:
00114         if (strcmp(name, "entry") == 0) {
00115             state->prev_state = state->state;
00116             state->state = ENTRY;
00117         }
00118         else {
00119             state->prev_state = state->state;
00120             state->state = PARSER_UNKNOWN;
00121             state->unknown_depth++;
00122         }
00123         break;
00124 
00125     case ENTRY:
00126         if (strcmp(name, "primary") == 0) {
00127             state->prev_state = state->state;
00128             state->state = PRIMARY;
00129 
00130             if (attrs) {
00131                 if (strcmp(attrs[0], "url") == 0) {
00132                     state->regexp = false;
00133                     state->primary = attrs[1];
00134                 }
00135                 else if (strcmp(attrs[0], "regexp") == 0) {
00136                     state->regexp = true;
00137                     state->primary = attrs[1];
00138                 }
00139             }
00140             else {
00141                 AISDatabaseParser::aisFatalError(state, "Required attribute 'url' or 'regexp' missing from element 'primary'.");
00142                 break;
00143             }
00144         }
00145         else if (strcmp(name, "ancillary") == 0) {
00146             state->prev_state = state->state;
00147             state->state = ANCILLARY;
00148 
00149             string url = ""; // set defaults, MUST have url
00150             string rule = "overwrite";
00151             for (int i = 0; attrs && attrs[i] != 0; i = i + 2) {
00152                 if (strcmp(attrs[i], "url") == 0)
00153                     url = attrs[i+1];
00154                 else if (strcmp(attrs[i], "rule") == 0)
00155                     rule = attrs[i+1];
00156             }
00157 
00158             // If this parser validated the XML, these tests would be
00159             // unnecessary.
00160             if (url == "") {
00161                 AISDatabaseParser::aisFatalError(state, "Required attribute 'url' missing from element 'ancillary'.");
00162                 break;
00163             }
00164 
00165             if (rule != "overwrite" && rule != "replace" && rule != "fallback") {
00166                 string msg = string("Optional attribute 'rule' in element 'ancillary' has a bad value: ") + rule + "\nIt should be one of 'overwrite', 'replace' or 'fallback'.";
00167                 AISDatabaseParser::aisFatalError(state, msg.c_str());
00168                 break;
00169             }
00170 
00171             Resource r(url, rule);
00172             state->rv.push_back(r);
00173         }
00174         else {
00175             state->prev_state = state->state;
00176             state->state = PARSER_UNKNOWN;
00177             state->unknown_depth++;
00178         }
00179         break;
00180 
00181     case PRIMARY:
00182         break;
00183 
00184     case ANCILLARY:
00185         break;
00186 
00187     case PARSER_UNKNOWN:
00188         state->unknown_depth++;
00189         break;
00190 
00191     case PARSER_ERROR:
00192         break;
00193     }
00194 
00195     DBG2(cerr << "Start element " << name << " (state "
00196          << states[state->state] << ")" << endl);
00197 }
00198 
00203 void
00204 AISDatabaseParser::aisEndElement(AISParserState *state, const char *)
00205 {
00206     DBG2(cerr << "End element " << name << " (state " << states[state->state]
00207          << ")" << endl);
00208 
00209     switch (state->state) {
00210     case AIS:
00211         state->prev_state = state->state;
00212         state->state = PARSER_FINISH;
00213         break;
00214 
00215     case ENTRY:
00216         state->prev_state = state->state;
00217         state->state = AIS;
00218 
00219         // record 'primary' and 'rv'
00220         if (state->regexp)
00221             state->ais->add_regexp_resource(state->primary, state->rv);
00222         else
00223             state->ais->add_url_resource(state->primary, state->rv);
00224 
00225         // empty rv for the next set of ancillary resources.
00226         state->rv.erase(state->rv.begin(), state->rv.end());
00227         break;
00228 
00229     case PRIMARY:
00230         state->prev_state = state->state;
00231         state->state = ENTRY;
00232         break;
00233 
00234     case ANCILLARY:
00235         state->prev_state = state->state;
00236         state->state = ENTRY;
00237         break;
00238 
00239     case PARSER_UNKNOWN:
00240         // Leave the state and prev_state alone.
00241         state->unknown_depth--;
00242         break;
00243 
00244     case PARSER_ERROR:
00245         break;
00246 
00247     default:
00248         break;
00249     }
00250 }
00251 
00255 xmlEntityPtr
00256 AISDatabaseParser::aisGetEntity(AISParserState *, const xmlChar *name)
00257 {
00258     return xmlGetPredefinedEntity(name);
00259 }
00260 
00265 void
00266 AISDatabaseParser::aisWarning(AISParserState *state, const char *msg, ...)
00267 {
00268     va_list args;
00269 
00270     state->state = PARSER_ERROR;
00271 
00272     va_start(args, msg);
00273     char str[1024];
00274     vsnprintf(str, 1024, msg, args);
00275     va_end(args);
00276 
00277 #ifdef LIBXML2_6_16
00278     // Defined if libxml2 >= 2.6.16
00279     int line = xmlSAX2GetLineNumber(state->ctxt);
00280 #else
00281     int line = getLineNumber(state->ctxt);
00282 #endif
00283     state->error_msg += "At line: " + long_to_string(line) + ": ";
00284     state->error_msg += string(str) + string("\n");
00285 }
00286 
00291 void
00292 AISDatabaseParser::aisError(AISParserState *state, const char *msg, ...)
00293 {
00294     va_list args;
00295 
00296     state->state = PARSER_ERROR;
00297 
00298     va_start(args, msg);
00299     char str[1024];
00300     vsnprintf(str, 1024, msg, args);
00301     va_end(args);
00302 
00303 #ifdef LIBXML2_6_16
00304     // Defined if libxml2 >= 2.6.16
00305     int line = xmlSAX2GetLineNumber(state->ctxt);
00306 #else
00307     int line = getLineNumber(state->ctxt);
00308 #endif
00309     state->error_msg += "At line: " + long_to_string(line) + ": ";
00310     state->error_msg += string(str) + string("\n");
00311 }
00312 
00316 void
00317 AISDatabaseParser::aisFatalError(AISParserState *state, const char *msg, ...)
00318 {
00319     va_list args;
00320 
00321     state->state = PARSER_ERROR;
00322 
00323     va_start(args, msg);
00324     char str[1024];
00325     vsnprintf(str, 1024, msg, args);
00326     va_end(args);
00327 
00328 #ifdef LIBXML2_6_16
00329     // Defined if libxml2 >= 2.6.16
00330     int line = xmlSAX2GetLineNumber(state->ctxt);
00331 #else
00332     int line = getLineNumber(state->ctxt);
00333 #endif
00334     state->error_msg += "At line: " + long_to_string(line) + ": ";
00335     state->error_msg += string(str) + string("\n");
00336 }
00337 
00339 
00342 static xmlSAXHandler aisSAXParser =
00343     {
00344         0, // internalSubset
00345         0, // isStandalone
00346         0, // hasInternalSubset
00347         0, // hasExternalSubset
00348         0, // resolveEntity
00349         (getEntitySAXFunc)AISDatabaseParser::aisGetEntity, // getEntity
00350         0, // entityDecl
00351         0, // notationDecl
00352         0, // attributeDecl
00353         0, // elementDecl
00354         0, // unparsedEntityDecl
00355         0, // setDocumentLocator
00356         (startDocumentSAXFunc)AISDatabaseParser::aisStartDocument, // startDocument
00357         (endDocumentSAXFunc)AISDatabaseParser::aisEndDocument,  // endDocument
00358         (startElementSAXFunc)AISDatabaseParser::aisStartElement,  // startElement
00359         (endElementSAXFunc)AISDatabaseParser::aisEndElement,  // endElement
00360         0, // reference
00361         0, // (charactersSAXFunc)gladeCharacters,  characters
00362         0, // ignorableWhitespace
00363         0, // processingInstruction
00364         0, // (commentSAXFunc)gladeComment,  comment
00365         (warningSAXFunc)AISDatabaseParser::aisWarning, // warning
00366         (errorSAXFunc)AISDatabaseParser::aisError, // error
00367         (fatalErrorSAXFunc)AISDatabaseParser::aisFatalError, // fatalError
00368 #ifdef LIBXML2_5_10
00369         0, // getParameterEntity
00370         0, // cdataBlock
00371         0, // externalSubset
00372         0, // initialized
00373 #endif
00374 #ifdef LIBXML2_6_16
00375         0, // _private
00376         0, // endElementNs
00377         0, // serror
00378         0 // startElementNs
00379 #endif
00380     };
00381 
00388 void
00389 AISDatabaseParser::intern(const string &database, AISResources *ais)
00390 {
00391     xmlParserCtxtPtr ctxt;
00392     AISParserState state;
00393 
00394     ctxt = xmlCreateFileParserCtxt(database.c_str());
00395     if (!ctxt)
00396         return;
00397 
00398     state.ais = ais;  // dump values here
00399     state.ctxt = ctxt;  // need ctxt for error messages
00400 
00401     ctxt->sax = &aisSAXParser;
00402     ctxt->userData = &state;
00403     ctxt->validate = true;
00404 
00405     xmlParseDocument(ctxt);
00406 
00407     // use getLineNumber and getColumnNumber to make the error messages better.
00408     if (!ctxt->wellFormed) {
00409         ctxt->sax = NULL;
00410         xmlFreeParserCtxt(ctxt);
00411         throw AISDatabaseReadFailed(string("\nThe database is not a well formed XML document.\n") + state.error_msg);
00412     }
00413 
00414     if (!ctxt->valid) {
00415         ctxt->sax = NULL;
00416         xmlFreeParserCtxt(ctxt);
00417         throw AISDatabaseReadFailed(string("\nThe database is not a valid document.\n") + state.error_msg);
00418     }
00419 
00420     if (state.state == PARSER_ERROR) {
00421         ctxt->sax = NULL;
00422         xmlFreeParserCtxt(ctxt);
00423         throw AISDatabaseReadFailed(string("\nError parsing AIS resources.\n") + state.error_msg);
00424     }
00425 
00426     ctxt->sax = NULL;
00427     xmlFreeParserCtxt(ctxt);
00428 }

Generated on Wed Jun 27 12:56:38 2007 for libdap++ by  doxygen 1.4.7