DDXParserSAX2.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 //#define DODS_DEBUG 1
00029 //#define DODS_DEBUG2 1
00030 
00031 #include <cstring>
00032 
00033 #include "BaseType.h"
00034 #include "Byte.h"
00035 #include "Int16.h"
00036 #include "UInt16.h"
00037 #include "Int32.h"
00038 #include "UInt32.h"
00039 #include "Float32.h"
00040 #include "Float64.h"
00041 #include "Str.h"
00042 #include "Url.h"
00043 #include "Array.h"
00044 #include "Structure.h"
00045 #include "Sequence.h"
00046 #include "Grid.h"
00047 
00048 #include "DDXParserSAX2.h"
00049 
00050 #include "util.h"
00051 #include "mime_util.h"
00052 #include "debug.h"
00053 
00054 namespace libdap {
00055 
00056 static const not_used char *states[] =
00057     {
00058         "start",
00059 
00060         "dataset",
00061 
00062         "attribute_container",
00063         "attribute",
00064         "attribute_value",
00065         "other_xml_attribute",
00066 
00067         "alias",
00068 
00069         "simple_type",
00070 
00071         "array",
00072         "dimension",
00073 
00074         "grid",
00075         "map",
00076 
00077         "structure",
00078         "sequence",
00079 
00080         "blob href",
00081 
00082         "unknown",
00083         "error"
00084     };
00085 
00086 // Glue the BaseTypeFactory to the enum-based factory defined statically
00087 // here.
00088 
00089 BaseType *DDXParser::factory(Type t, const string & name)
00090 {
00091     switch (t) {
00092     case dods_byte_c:
00093         return d_factory->NewByte(name);
00094         break;
00095 
00096     case dods_int16_c:
00097         return d_factory->NewInt16(name);
00098         break;
00099 
00100     case dods_uint16_c:
00101         return d_factory->NewUInt16(name);
00102         break;
00103 
00104     case dods_int32_c:
00105         return d_factory->NewInt32(name);
00106         break;
00107 
00108     case dods_uint32_c:
00109         return d_factory->NewUInt32(name);
00110         break;
00111 
00112     case dods_float32_c:
00113         return d_factory->NewFloat32(name);
00114         break;
00115 
00116     case dods_float64_c:
00117         return d_factory->NewFloat64(name);
00118         break;
00119 
00120     case dods_str_c:
00121         return d_factory->NewStr(name);
00122         break;
00123 
00124     case dods_url_c:
00125         return d_factory->NewUrl(name);
00126         break;
00127 
00128     case dods_array_c:
00129         return d_factory->NewArray(name);
00130         break;
00131 
00132     case dods_structure_c:
00133         return d_factory->NewStructure(name);
00134         break;
00135 
00136     case dods_sequence_c:
00137         return d_factory->NewSequence(name);
00138         break;
00139 
00140     case dods_grid_c:
00141         return d_factory->NewGrid(name);
00142         break;
00143 
00144     default:
00145         return 0;
00146     }
00147 }
00148 
00150 static Type get_type(const char *name)
00151 {
00152     if (strcmp(name, "Byte") == 0)
00153         return dods_byte_c;
00154 
00155     if (strcmp(name, "Int16") == 0)
00156         return dods_int16_c;
00157 
00158     if (strcmp(name, "UInt16") == 0)
00159         return dods_uint16_c;
00160 
00161     if (strcmp(name, "Int32") == 0)
00162         return dods_int32_c;
00163 
00164     if (strcmp(name, "UInt32") == 0)
00165         return dods_uint32_c;
00166 
00167     if (strcmp(name, "Float32") == 0)
00168         return dods_float32_c;
00169 
00170     if (strcmp(name, "Float64") == 0)
00171         return dods_float64_c;
00172 
00173     if (strcmp(name, "String") == 0)
00174         return dods_str_c;
00175 
00176     if (strcmp(name, "Url") == 0)
00177         return dods_url_c;
00178 
00179     if (strcmp(name, "Array") == 0)
00180         return dods_array_c;
00181 
00182     if (strcmp(name, "Structure") == 0)
00183         return dods_structure_c;
00184 
00185     if (strcmp(name, "Sequence") == 0)
00186         return dods_sequence_c;
00187 
00188     if (strcmp(name, "Grid") == 0)
00189         return dods_grid_c;
00190 
00191     return dods_null_c;
00192 }
00193 
00194 static Type is_simple_type(const char *name)
00195 {
00196     Type t = get_type(name);
00197     switch (t) {
00198     case dods_byte_c:
00199     case dods_int16_c:
00200     case dods_uint16_c:
00201     case dods_int32_c:
00202     case dods_uint32_c:
00203     case dods_float32_c:
00204     case dods_float64_c:
00205     case dods_str_c:
00206     case dods_url_c:
00207         return t;
00208     default:
00209         return dods_null_c;
00210     }
00211 }
00212 
00213 static bool is_not(const char *name, const char *tag)
00214 {
00215     return strcmp(name, tag) != 0;
00216 }
00217 
00218 void DDXParser::set_state(DDXParser::ParseState state)
00219 {
00220     s.push(state);
00221 }
00222 
00223 DDXParser::ParseState DDXParser::get_state() const
00224 {
00225     return s.top();
00226 }
00227 
00228 void DDXParser::pop_state()
00229 {
00230     s.pop();
00231 }
00232 
00236 void DDXParser::transfer_xml_attrs(const xmlChar **attributes, int nb_attributes)
00237 {
00238     if (!attribute_table.empty())
00239         attribute_table.clear(); // erase old attributes
00240 
00241     unsigned int index = 0;
00242     for (int i = 0; i < nb_attributes; ++i, index += 5) {
00243         // Make a value using the attribute name and the prefix, namespace URI
00244         // and the value. The prefix might be null.
00245         attribute_table.insert(map<string, XMLAttribute>::value_type(
00246                 string((const char *)attributes[index]),
00247                 XMLAttribute(attributes + index + 1)));
00248 
00249         DBG(cerr << "Attribute '" << (const char *)attributes[index] << "': "
00250                 << attribute_table[(const char *)attributes[index]].value << endl);
00251     }
00252 }
00253 
00254 void DDXParser::transfer_xml_ns(const xmlChar **namespaces, int nb_namespaces)
00255 {
00256     for (int i = 0; i < nb_namespaces; ++i ) {
00257         // make a value with the prefix and namespace URI. The prefix might be
00258         // null.
00259         namespace_table.insert(map<string,string>::value_type(
00260                 namespaces[i*2] != 0 ? (const char *)namespaces[i*2] : "",
00261                 (const char *)namespaces[i*2+1]));
00262     }
00263 }
00264 
00269 bool DDXParser::check_required_attribute(const string & attr)
00270 {
00271     map < string, XMLAttribute >::iterator i = attribute_table.find(attr);
00272     if (i == attribute_table.end())
00273         ddx_fatal_error(this, "Required attribute '%s' not found.",
00274                         attr.c_str());
00275     return true;
00276 }
00277 
00283 bool DDXParser::check_attribute(const string & attr)
00284 {
00285     return (attribute_table.find(attr) != attribute_table.end());
00286 }
00287 
00296 void DDXParser::process_attribute_element(const xmlChar **attrs, int nb_attributes)
00297 {
00298     // These methods set the state to parser_error if a problem is found.
00299     transfer_xml_attrs(attrs, nb_attributes);
00300 
00301     bool error = !(check_required_attribute(string("name"))
00302                    && check_required_attribute(string("type")));
00303     if (error)
00304         return;
00305 
00306     if (attribute_table["type"].value == "Container") {
00307         set_state(inside_attribute_container);
00308 
00309         AttrTable *child;
00310         AttrTable *parent = at_stack.top();
00311 
00312         child = parent->append_container(attribute_table["name"].value);
00313         at_stack.push(child);   // save.
00314         DBG2(cerr << "Pushing at" << endl);
00315     }
00316     else if (attribute_table["type"].value == "OtherXML") {
00317         set_state(inside_other_xml_attribute);
00318 
00319         dods_attr_name = attribute_table["name"].value;
00320         dods_attr_type = attribute_table["type"].value;
00321     }
00322     else {
00323         set_state(inside_attribute);
00324         // *** Modify parser. Add a special state for inside OtherXML since it
00325         // does not use the <value> element.
00326 
00327         dods_attr_name = attribute_table["name"].value;
00328         dods_attr_type = attribute_table["type"].value;
00329     }
00330 }
00331 
00335 void DDXParser::process_attribute_alias(const xmlChar **attrs, int nb_attributes)
00336 {
00337     transfer_xml_attrs(attrs, nb_attributes);
00338     if (check_required_attribute(string("name"))
00339         && check_required_attribute(string("attribute"))) {
00340         set_state(inside_alias);
00341         at_stack.top()->attr_alias(attribute_table["name"].value,
00342                                    attribute_table["attribute"].value);
00343     }
00344 }
00345 
00353 void DDXParser::process_variable(Type t, ParseState s, const xmlChar **attrs,
00354         int nb_attributes)
00355 {
00356     transfer_xml_attrs(attrs, nb_attributes);
00357 
00358     set_state(s);
00359     if (bt_stack.top()->type() == dods_array_c
00360             || check_required_attribute("name")) { // throws on error/false
00361         BaseType *btp = factory(t, attribute_table["name"].value);
00362         if (!btp)
00363             ddx_fatal_error(
00364                     this,
00365                     "Internal parser error; could not instantiate the variable '%s'.",
00366                     attribute_table["name"].value.c_str());
00367 
00368         // Once we make the new variable, we not only load it on to the
00369         // BaseType stack, we also load its AttrTable on the AttrTable stack.
00370         // The attribute processing software always operates on the AttrTable
00371         // at the top of the AttrTable stack (at_stack).
00372         bt_stack.push(btp);
00373         at_stack.push(&btp->get_attr_table());
00374     }
00375 }
00376 
00380 void DDXParser::process_dimension(const xmlChar **attrs, int nb_attributes)
00381 {
00382     transfer_xml_attrs(attrs, nb_attributes);
00383     if (check_required_attribute(string("size"))) {
00384         set_state(inside_dimension);
00385         Array *ap = dynamic_cast < Array * >(bt_stack.top());
00386                 if (!ap)
00387                         ddx_fatal_error(this, "Parse error: Expected an array variable.");
00388 
00389         ap->append_dim(atoi(attribute_table["size"].value.c_str()),
00390                        attribute_table["name"].value);
00391     }
00392 }
00393 
00396 void DDXParser::process_blob(const xmlChar **attrs, int nb_attributes)
00397 {
00398     transfer_xml_attrs(attrs, nb_attributes);
00399     if (check_required_attribute(string("href"))) {
00400         set_state(inside_blob_href);
00401         *blob_href = attribute_table["href"].value;
00402     }
00403 }
00404 
00411 inline bool
00412 DDXParser::is_attribute_or_alias(const char *name, const xmlChar **attrs,
00413         int nb_attributes)
00414 {
00415     if (strcmp(name, "Attribute") == 0) {
00416         process_attribute_element(attrs, nb_attributes);
00417         // next state: inside_attribtue or inside_attribute_container
00418         return true;
00419     }
00420     else if (strcmp(name, "Alias") == 0) {
00421         process_attribute_alias(attrs, nb_attributes);
00422         // next state: inside_alias
00423         return true;
00424     }
00425 
00426     return false;
00427 }
00428 
00434 inline bool DDXParser::is_variable(const char *name, const xmlChar **attrs,
00435         int nb_attributes)
00436 {
00437     Type t;
00438     if ((t = is_simple_type(name)) != dods_null_c) {
00439         process_variable(t, inside_simple_type, attrs, nb_attributes);
00440         return true;
00441     }
00442     else if (strcmp(name, "Array") == 0) {
00443         process_variable(dods_array_c, inside_array, attrs, nb_attributes);
00444         return true;
00445     }
00446     else if (strcmp(name, "Structure") == 0) {
00447         process_variable(dods_structure_c, inside_structure, attrs, nb_attributes);
00448         return true;
00449     }
00450     else if (strcmp(name, "Sequence") == 0) {
00451         process_variable(dods_sequence_c, inside_sequence, attrs, nb_attributes);
00452         return true;
00453     }
00454     else if (strcmp(name, "Grid") == 0) {
00455         process_variable(dods_grid_c, inside_grid, attrs, nb_attributes);
00456         return true;
00457     }
00458 
00459     return false;
00460 }
00461 
00462 void DDXParser::finish_variable(const char *tag, Type t, const char *expected)
00463 {
00464     if (strcmp(tag, expected) != 0) {
00465         DDXParser::ddx_fatal_error(this,
00466                                    "Expected an end tag for a %s; found '%s' instead.",
00467                                    expected, tag);
00468         return;
00469     }
00470 
00471     pop_state();
00472 
00473     BaseType *btp = bt_stack.top();
00474 
00475     bt_stack.pop();
00476     at_stack.pop();
00477 
00478     if (btp->type() != t) {
00479         DDXParser::ddx_fatal_error(this,
00480                                    "Internal error: Expected a %s variable.",
00481                                    expected);
00482         return;
00483     }
00484     // Once libxml2 validates, this can go away. 05/30/03 jhrg
00485     if (t == dods_array_c
00486         && dynamic_cast < Array * >(btp)->dimensions() == 0) {
00487         DDXParser::ddx_fatal_error(this,
00488                                    "No dimension element included in the Array '%s'.",
00489                                    btp->name().c_str());
00490         return;
00491     }
00492 
00493     BaseType *parent = bt_stack.top();
00494 
00495     if (!(parent->is_vector_type() || parent->is_constructor_type())) {
00496         DDXParser::ddx_fatal_error(this,
00497                                    "Tried to add the array variable '%s' to a non-constructor type (%s %s).",
00498                                    tag,
00499                                    bt_stack.top()->type_name().c_str(),
00500                                    bt_stack.top()->name().c_str());
00501         return;
00502     }
00503 
00504     parent->add_var(btp);
00505 }
00506 
00513 
00518 void DDXParser::ddx_start_document(void * p)
00519 {
00520     DDXParser *parser = static_cast<DDXParser*>(p);
00521     parser->error_msg = "";
00522     parser->char_data = "";
00523 
00524     // init attr table stack.
00525     parser->at_stack.push(&parser->dds->get_attr_table());
00526 
00527     // Trick; DDS *should* be a child of Structure. To simplify parsing,
00528     // stuff a Structure on the bt_stack and dump the top level variables
00529     // there. Once we're done, transfer the variables to the DDS.
00530     parser->bt_stack.push(new Structure("dummy_dds"));
00531 
00532     parser->set_state(parser_start);
00533 
00534     DBG2(cerr << "Parser state: " << states[parser->get_state()] << endl);
00535 }
00536 
00539 void DDXParser::ddx_end_document(void * p)
00540 {
00541     DDXParser *parser = static_cast<DDXParser*>(p);
00542     DBG2(cerr << "Ending state == " << states[parser->get_state()] <<
00543          endl);
00544 
00545     if (parser->get_state() != parser_start)
00546         DDXParser::ddx_fatal_error(parser,
00547                                    "The document contained unbalanced tags.");
00548 
00549     // If we've found any sort of error, don't make the DDX; intern() will
00550     // take care of the error.
00551     if (parser->get_state() == parser_error)
00552         return;
00553 
00554     // Pop the temporary Structure off the stack and transfer its variables
00555     // to the DDS.
00556     Constructor *cp = dynamic_cast < Constructor * >(parser->bt_stack.top());
00557     if (!cp)
00558         ddx_fatal_error(parser, "Parse error: Expected a Structure, Sequence or Grid variable.");
00559 
00560     for (Constructor::Vars_iter i = cp->var_begin(); i != cp->var_end();
00561          ++i)
00562         parser->dds->add_var(*i);
00563 
00564     parser->bt_stack.pop();
00565     delete cp;
00566 }
00567 
00568 void DDXParser::ddx_sax2_start_element(void *p,
00569         const xmlChar *l, const xmlChar *prefix, const xmlChar *URI,
00570         int nb_namespaces, const xmlChar **namespaces,
00571         int nb_attributes, int /*nb_defaulted*/, const xmlChar **attributes)
00572 {
00573     DDXParser *parser = static_cast<DDXParser*>(p);
00574     const char *localname = (const char *)l;
00575 
00576     DBG2(cerr << "start element: " << localname << ", states: "
00577          << states[parser->get_state()]);
00578 
00579     switch (parser->get_state()) {
00580     case parser_start:
00581         if (strcmp(localname, "Dataset") == 0) {
00582             parser->set_state(inside_dataset);
00583             parser->root_ns = URI != 0 ? (const char *)URI: "";
00584             parser->transfer_xml_attrs(attributes, nb_attributes);
00585 
00586             if (parser->check_required_attribute(string("name")))
00587                 parser->dds->set_dataset_name(parser->attribute_table["name"].value);
00588 
00589             if (parser->check_attribute("dapVersion"))
00590                 parser->dds->set_dap_version(parser->attribute_table["dapVersion"].value);
00591         }
00592         else
00593             DDXParser::ddx_fatal_error(parser,
00594                                        "Expected response to start with a Dataset element; found '%s' instead.",
00595                                        localname);
00596         break;
00597 
00598     case inside_dataset:
00599         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00600             break;
00601         else if (parser->is_variable(localname, attributes, nb_attributes))
00602             break;
00603         else if (strcmp(localname, "blob") == 0 || strcmp(localname, "dataBLOB") == 0) {
00604             parser->process_blob(attributes, nb_attributes);
00605             // next state: inside_data_blob
00606         }
00607         else
00608             DDXParser::ddx_fatal_error(parser,
00609                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00610                                        localname);
00611         break;
00612 
00613     case inside_attribute_container:
00614         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00615             break;
00616         else
00617             DDXParser::ddx_fatal_error(parser,
00618                                        "Expected an Attribute or Alias element; found '%s' instead.",
00619                                        localname);
00620         break;
00621 
00622     case inside_attribute:
00623         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00624             break;
00625         else if (strcmp(localname, "value") == 0)
00626             parser->set_state(inside_attribute_value);
00627         else
00628             ddx_fatal_error(parser,
00629                             "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
00630                             localname);
00631         break;
00632 
00633     case inside_attribute_value:
00634         ddx_fatal_error(parser,
00635                         "Internal parser error; unexpected state, inside value while processing element '%s'.",
00636                         localname);
00637         break;
00638 
00639     case inside_other_xml_attribute:
00640         DBGN(cerr << endl << "\t inside_other_xml_attribute: " << localname << endl);
00641 
00642         parser->other_xml_depth++;
00643 
00644         // Accumulate the elements here
00645 
00646         parser->other_xml.append("<");
00647         if (prefix) {
00648             parser->other_xml.append((const char *)prefix);
00649             parser->other_xml.append(":");
00650         }
00651         parser->other_xml.append(localname);
00652 
00653         if (nb_namespaces != 0) {
00654             parser->transfer_xml_ns(namespaces, nb_namespaces);
00655 
00656             for (map<string,string>::iterator i = parser->namespace_table.begin();
00657                 i != parser->namespace_table.end();
00658                 ++i) {
00659                 parser->other_xml.append(" xmlns");
00660                 if (!i->first.empty()) {
00661                     parser->other_xml.append(":");
00662                     parser->other_xml.append(i->first);
00663                 }
00664                 parser->other_xml.append("=\"");
00665                 parser->other_xml.append(i->second);
00666                 parser->other_xml.append("\"");
00667             }
00668         }
00669 
00670         if (nb_attributes != 0) {
00671             parser->transfer_xml_attrs(attributes, nb_attributes);
00672             for (XMLAttrMap::iterator i = parser->attr_table_begin();
00673                 i != parser->attr_table_end();
00674                 ++i) {
00675                 parser->other_xml.append(" ");
00676                 if (!i->second.prefix.empty()) {
00677                     parser->other_xml.append(i->second.prefix);
00678                     parser->other_xml.append(":");
00679                 }
00680                 parser->other_xml.append(i->first);
00681                 parser->other_xml.append("=\"");
00682                 parser->other_xml.append(i->second.value);
00683                 parser->other_xml.append("\"");
00684             }
00685         }
00686 
00687         parser->other_xml.append(">");
00688         break;
00689 
00690     case inside_alias:
00691         ddx_fatal_error(parser,
00692                         "Internal parser error; unexpected state, inside alias while processing element '%s'.",
00693                         localname);
00694         break;
00695 
00696     case inside_simple_type:
00697         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00698             break;
00699         else
00700             ddx_fatal_error(parser,
00701                             "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
00702                             localname);
00703         break;
00704 
00705     case inside_array:
00706         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00707             break;
00708         else if (is_not(localname, "Array")
00709                 && parser->is_variable(localname, attributes, nb_attributes))
00710             break;
00711         else if (strcmp(localname, "dimension") == 0) {
00712             parser->process_dimension(attributes, nb_attributes);
00713             // next state: inside_dimension
00714         }
00715         else
00716             ddx_fatal_error(parser,
00717                             "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
00718                             localname);
00719         break;
00720 
00721     case inside_dimension:
00722         ddx_fatal_error(parser,
00723                         "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
00724                         localname);
00725         break;
00726 
00727     case inside_structure:
00728         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00729             break;
00730         else if (parser->is_variable(localname, attributes, nb_attributes))
00731             break;
00732         else
00733             DDXParser::ddx_fatal_error(parser,
00734                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00735                                        localname);
00736         break;
00737 
00738     case inside_sequence:
00739         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00740             break;
00741         else if (parser->is_variable(localname, attributes, nb_attributes))
00742             break;
00743         else
00744             DDXParser::ddx_fatal_error(parser,
00745                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00746                                        localname);
00747         break;
00748 
00749     case inside_grid:
00750         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00751             break;
00752         else if (strcmp(localname, "Array") == 0)
00753             parser->process_variable(dods_array_c, inside_array, attributes, nb_attributes);
00754         else if (strcmp(localname, "Map") == 0)
00755             parser->process_variable(dods_array_c, inside_map, attributes, nb_attributes);
00756         else
00757             DDXParser::ddx_fatal_error(parser,
00758                                        "Expected an Attribute, Alias or variable element; found '%s' instead.",
00759                                        localname);
00760         break;
00761 
00762     case inside_map:
00763         if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
00764             break;
00765         else if (is_not(localname, "Array") && is_not(localname, "Sequence")
00766                  && is_not(localname, "Grid")
00767                  && parser->is_variable(localname, attributes, nb_attributes))
00768             break;
00769         else if (strcmp(localname, "dimension") == 0) {
00770             parser->process_dimension(attributes, nb_attributes);
00771             // next state: inside_dimension
00772         }
00773         else
00774             ddx_fatal_error(parser,
00775                             "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
00776                             localname);
00777         break;
00778 
00779     case inside_blob_href:
00780         ddx_fatal_error(parser,
00781                         "Internal parser error; unexpected state, inside blob href while processing element '%s'.",
00782                         localname);
00783         break;
00784 
00785     case parser_unknown:
00786         // *** Never used? If so remove/error
00787         parser->set_state(parser_unknown);
00788         break;
00789 
00790     case parser_error:
00791         break;
00792     }
00793 
00794     DBGN(cerr << " ... " << states[parser->get_state()] << endl);
00795 }
00796 
00797 void DDXParser::ddx_sax2_end_element(void *p, const xmlChar *l,
00798         const xmlChar *prefix, const xmlChar *URI)
00799 {
00800     DDXParser *parser = static_cast<DDXParser*>(p);
00801     const char *localname = (const char *)l;
00802 
00803     DBG2(cerr << "End element " << localname << " (state "
00804          << states[parser->get_state()] << ")" << endl);
00805 
00806     switch (parser->get_state()) {
00807     case parser_start:
00808         ddx_fatal_error(parser,
00809                         "Internal parser error; unexpected state, inside start state while processing element '%s'.",
00810                         localname);
00811         break;
00812 
00813     case inside_dataset:
00814         if (strcmp(localname, "Dataset") == 0)
00815             parser->pop_state();
00816         else
00817             DDXParser::ddx_fatal_error(parser,
00818                                        "Expected an end Dataset tag; found '%s' instead.",
00819                                        localname);
00820         break;
00821 
00822     case inside_attribute_container:
00823         if (strcmp(localname, "Attribute") == 0) {
00824             parser->pop_state();
00825             parser->at_stack.pop();     // pop when leaving a container.
00826         }
00827         else
00828             DDXParser::ddx_fatal_error(parser,
00829                                        "Expected an end Attribute tag; found '%s' instead.",
00830                                        localname);
00831         break;
00832 
00833     case inside_attribute:
00834         if (strcmp(localname, "Attribute") == 0)
00835             parser->pop_state();
00836         else
00837             DDXParser::ddx_fatal_error(parser,
00838                                        "Expected an end Attribute tag; found '%s' instead.",
00839                                        localname);
00840         break;
00841 
00842     case inside_attribute_value:
00843         if (strcmp(localname, "value") == 0) {
00844             parser->pop_state();
00845             AttrTable *atp = parser->at_stack.top();
00846             atp->append_attr(parser->dods_attr_name,
00847                              parser->dods_attr_type, parser->char_data);
00848             parser->char_data = "";     // Null this after use.
00849         }
00850         else
00851             DDXParser::ddx_fatal_error(parser,
00852                                        "Expected an end value tag; found '%s' instead.",
00853                                        localname);
00854 
00855         break;
00856 
00857     case inside_other_xml_attribute: {
00858             if (strcmp(localname, "Attribute") == 0
00859                     && parser->root_ns == (const char *)URI) {
00860 
00861                 DBGN(cerr << endl << "\t Popping the 'inside_other_xml_attribute' state"
00862                         << endl);
00863 
00864                 parser->pop_state();
00865 
00866                 AttrTable *atp = parser->at_stack.top();
00867                 atp->append_attr(parser->dods_attr_name,
00868                         parser->dods_attr_type, parser->other_xml);
00869 
00870                 parser->other_xml = ""; // Null this after use.
00871             }
00872             else {
00873                 DBGN(cerr << endl << "\t inside_other_xml_attribute: " << localname
00874                         << ", depth: " << parser->other_xml_depth << endl);
00875                 if (parser->other_xml_depth == 0)
00876                     DDXParser::ddx_fatal_error(parser,
00877                                                "Expected an OtherXML attribute to end! Instead I found '%s'",
00878                                                localname);
00879                 parser->other_xml_depth--;
00880 
00881                 parser->other_xml.append("</");
00882                 if (prefix) {
00883                     parser->other_xml.append((const char *)prefix);
00884                     parser->other_xml.append(":");
00885                 }
00886                 parser->other_xml.append(localname);
00887                 parser->other_xml.append(">");
00888             }
00889             break;
00890         }
00891         // Alias is busted in libdap++ 05/29/03 jhrg
00892     case inside_alias:
00893         parser->pop_state();
00894         break;
00895 
00896     case inside_simple_type:
00897         if (is_simple_type(localname) != dods_null_c) {
00898             parser->pop_state();
00899             BaseType *btp = parser->bt_stack.top();
00900             parser->bt_stack.pop();
00901             parser->at_stack.pop();
00902 
00903             BaseType *parent = parser->bt_stack.top();
00904 
00905             if (parent->is_vector_type() || parent->is_constructor_type())
00906                 parent->add_var(btp);
00907             else
00908                 DDXParser::ddx_fatal_error(parser,
00909                                            "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).",
00910                                            localname,
00911                                            parser->bt_stack.top()->
00912                                            type_name().c_str(),
00913                                            parser->bt_stack.top()->name().
00914                                            c_str());
00915         }
00916         else
00917             DDXParser::ddx_fatal_error(parser,
00918                                        "Expected an end tag for a simple type; found '%s' instead.",
00919                                        localname);
00920         break;
00921 
00922     case inside_array:
00923         parser->finish_variable(localname, dods_array_c, "Array");
00924         break;
00925 
00926     case inside_dimension:
00927         if (strcmp(localname, "dimension") == 0)
00928             parser->pop_state();
00929         else
00930             DDXParser::ddx_fatal_error(parser,
00931                                        "Expected an end dimension tag; found '%s' instead.",
00932                                        localname);
00933         break;
00934 
00935     case inside_structure:
00936         parser->finish_variable(localname, dods_structure_c, "Structure");
00937         break;
00938 
00939     case inside_sequence:
00940         parser->finish_variable(localname, dods_sequence_c, "Sequence");
00941         break;
00942 
00943     case inside_grid:
00944         parser->finish_variable(localname, dods_grid_c, "Grid");
00945         break;
00946 
00947     case inside_map:
00948         parser->finish_variable(localname, dods_array_c, "Map");
00949         break;
00950 
00951     case inside_blob_href:
00952         if (strcmp(localname, "blob") == 0 || strcmp(localname, "dataBLOB") == 0)
00953             parser->pop_state();
00954         else
00955             DDXParser::ddx_fatal_error(parser,
00956                                        "Expected an end dataBLOB/blob tag; found '%s' instead.",
00957                                        localname);
00958         break;
00959 
00960     case parser_unknown:
00961         parser->pop_state();
00962         break;
00963 
00964     case parser_error:
00965         break;
00966     }
00967 
00968 
00969     DBGN(cerr << " ... " << states[parser->get_state()] << endl);
00970 }
00971 
00975 void DDXParser::ddx_get_characters(void * p, const xmlChar * ch, int len)
00976 {
00977     DDXParser *parser = static_cast<DDXParser*>(p);
00978 
00979     switch (parser->get_state()) {
00980         case inside_attribute_value:
00981             parser->char_data.append((const char *)(ch), len);
00982             DBG2(cerr << "Characters: '" << parser->char_data << "'" << endl);
00983             break;
00984 
00985         case inside_other_xml_attribute:
00986             parser->other_xml.append((const char *)(ch), len);
00987             DBG2(cerr << "Other XML Characters: '" << parser->other_xml << "'" << endl);
00988             break;
00989 
00990         default:
00991             break;
00992     }
00993 }
00994 
00999 void DDXParser::ddx_ignoreable_whitespace(void *p, const xmlChar *ch,
01000         int len)
01001 {
01002     DDXParser *parser = static_cast<DDXParser*>(p);
01003 
01004     switch (parser->get_state()) {
01005          case inside_other_xml_attribute:
01006              parser->other_xml.append((const char *)(ch), len);
01007              break;
01008 
01009          default:
01010              break;
01011     }
01012 }
01013 
01019 void DDXParser::ddx_get_cdata(void *p, const xmlChar *value, int len)
01020 {
01021     DDXParser *parser = static_cast<DDXParser*>(p);
01022 
01023     switch (parser->get_state()) {
01024          case inside_other_xml_attribute:
01025              parser->other_xml.append((const char *)(value), len);
01026              break;
01027 
01028          case parser_unknown:
01029              break;
01030 
01031          default:
01032              DDXParser::ddx_fatal_error(parser,
01033                                         "Found a CData block but none are allowed by DAP.");
01034 
01035              break;
01036     }
01037 }
01038 
01043 xmlEntityPtr DDXParser::ddx_get_entity(void *, const xmlChar * name)
01044 {
01045     return xmlGetPredefinedEntity(name);
01046 }
01047 
01055 void DDXParser::ddx_fatal_error(void * p, const char *msg, ...)
01056 {
01057     va_list args;
01058     DDXParser *parser = static_cast<DDXParser*>(p);
01059 
01060     parser->set_state(parser_error);
01061 
01062     va_start(args, msg);
01063     char str[1024];
01064     vsnprintf(str, 1024, msg, args);
01065     va_end(args);
01066 
01067     int line = xmlSAX2GetLineNumber(parser->ctxt);
01068 
01069     parser->error_msg += "At line " + long_to_string(line) + ": ";
01070     parser->error_msg += string(str) + string("\n");
01071 }
01072 
01074 
01075 void DDXParser::cleanup_parse(xmlParserCtxtPtr & context) const
01076 {
01077     if (!context->wellFormed) {
01078         context->sax = NULL;
01079         xmlFreeParserCtxt(context);
01080         throw
01081         DDXParseFailed(string
01082                        ("\nThe DDX is not a well formed XML document.\n")
01083                        + error_msg);
01084     }
01085 
01086     if (!context->valid) {
01087         context->sax = NULL;
01088         xmlFreeParserCtxt(context);
01089         throw DDXParseFailed(string("\nThe DDX is not a valid document.\n")
01090                              + error_msg);
01091     }
01092 
01093     if (get_state() == parser_error) {
01094         context->sax = NULL;
01095         xmlFreeParserCtxt(context);
01096         throw DDXParseFailed(string("\nError parsing DDX response.\n") +
01097                              error_msg);
01098     }
01099 
01100     context->sax = NULL;
01101     xmlFreeParserCtxt(context);
01102 }
01103 
01106 void DDXParser::intern_stream(FILE *in, DDS *dest_dds, string &cid,
01107         const string &boundary)
01108 {
01109     // Code example from libxml2 docs re: read from a stream.
01110 
01111     if (!in || feof(in) || ferror(in))
01112         throw InternalErr(__FILE__, __LINE__,
01113                           "Input stream not open or read error");
01114 
01115     const int size = 1024;
01116     char chars[size];
01117 
01118     int res = fread(chars, 1, 4, in);
01119     if (res > 0) {
01120         xmlParserCtxtPtr context =
01121             xmlCreatePushParserCtxt(NULL, NULL, chars, res, "stream");
01122 
01123         ctxt = context;         // need ctxt for error messages
01124         dds = dest_dds;         // dump values here
01125         blob_href = &cid;       // cid goes here
01126 
01127         xmlSAXHandler ddx_sax_parser;
01128         memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) );
01129 
01130         ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity;
01131         ddx_sax_parser.startDocument = &DDXParser::ddx_start_document;
01132         ddx_sax_parser.endDocument = &DDXParser::ddx_end_document;
01133         ddx_sax_parser.characters = &DDXParser::ddx_get_characters;
01134         ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace;
01135         ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata;
01136         ddx_sax_parser.warning = &DDXParser::ddx_fatal_error;
01137         ddx_sax_parser.error = &DDXParser::ddx_fatal_error;
01138         ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error;
01139         ddx_sax_parser.initialized = XML_SAX2_MAGIC;
01140         ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element;
01141         ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element;
01142 
01143         context->sax = &ddx_sax_parser;
01144         context->userData = this;
01145         context->validate = true;
01146 
01147         while ((fgets(chars, size, in) > 0) && !is_boundary(chars, boundary)) {
01148             DBG(cerr << "line: " << chars << endl);
01149             xmlParseChunk(ctxt, chars, strlen(chars), 0);
01150         }
01151         // This call ends the parse: The fourth argument of xmlParseChunk is
01152         // the bool 'terminate.'
01153         xmlParseChunk(ctxt, chars, 0, 1);
01154 
01155         cleanup_parse(context);
01156     }
01157 }
01158 
01159 
01171 void DDXParser::intern(const string & document, DDS * dest_dds, string &cid)
01172 {
01173     // Create the context pointer explicitly so that we can store a pointer
01174     // to it in the DDXParser instance. This provides a way to generate our
01175     // own error messages *with* line numbers. The messages are pretty
01176     // meaningless otherwise. This means that we use an interface from the
01177     // 'parser internals' header, and not the 'parser' header. However, this
01178     // interface is also used in one of the documented examples, so it's
01179     // probably pretty stable. 06/02/03 jhrg
01180     xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str());
01181     if (!context)
01182         throw
01183         DDXParseFailed(string
01184                        ("Could not initialize the parser with the file: '")
01185                        + document + string("'."));
01186 
01187     dds = dest_dds;             // dump values here
01188     blob_href = &cid;
01189     ctxt = context;             // need ctxt for error messages
01190 
01191     xmlSAXHandler ddx_sax_parser;
01192     memset( &ddx_sax_parser, 0, sizeof(xmlSAXHandler) );
01193 
01194     ddx_sax_parser.getEntity = &DDXParser::ddx_get_entity;
01195     ddx_sax_parser.startDocument = &DDXParser::ddx_start_document;
01196     ddx_sax_parser.endDocument = &DDXParser::ddx_end_document;
01197     ddx_sax_parser.characters = &DDXParser::ddx_get_characters;
01198     ddx_sax_parser.ignorableWhitespace = &DDXParser::ddx_ignoreable_whitespace;
01199     ddx_sax_parser.cdataBlock = &DDXParser::ddx_get_cdata;
01200     ddx_sax_parser.warning = &DDXParser::ddx_fatal_error;
01201     ddx_sax_parser.error = &DDXParser::ddx_fatal_error;
01202     ddx_sax_parser.fatalError = &DDXParser::ddx_fatal_error;
01203     ddx_sax_parser.initialized = XML_SAX2_MAGIC;
01204     ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element;
01205     ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element;
01206 
01207     context->sax = &ddx_sax_parser;
01208     context->userData = this;
01209     context->validate = false;
01210 
01211     xmlParseDocument(context);
01212 
01213     cleanup_parse(context);
01214 }
01215 
01216 } // namespace libdap

Generated on Wed Feb 10 16:08:02 2010 for libdap++ by  doxygen 1.4.7