45 #include "Structure.h" 49 #include "DDXParserSAX2.h" 52 #include "mime_util.h" 57 #if defined(DODS_DEBUG) || defined(DODS_DEUG2) 58 static const char *states[] =
64 "attribute_container",
67 "other_xml_attribute",
91 BaseType *DDXParser::factory(
Type t,
const string & name)
95 return d_factory->NewByte(name);
99 return d_factory->NewInt16(name);
103 return d_factory->NewUInt16(name);
107 return d_factory->NewInt32(name);
111 return d_factory->NewUInt32(name);
115 return d_factory->NewFloat32(name);
119 return d_factory->NewFloat64(name);
123 return d_factory->NewStr(name);
127 return d_factory->NewUrl(name);
131 return d_factory->NewArray(name);
134 case dods_structure_c:
135 return d_factory->NewStructure(name);
138 case dods_sequence_c:
139 return d_factory->NewSequence(name);
143 return d_factory->NewGrid(name);
155 if (strcmp(name,
"Byte") == 0)
158 if (strcmp(name,
"Int16") == 0)
161 if (strcmp(name,
"UInt16") == 0)
162 return dods_uint16_c;
164 if (strcmp(name,
"Int32") == 0)
167 if (strcmp(name,
"UInt32") == 0)
168 return dods_uint32_c;
170 if (strcmp(name,
"Float32") == 0)
171 return dods_float32_c;
173 if (strcmp(name,
"Float64") == 0)
174 return dods_float64_c;
176 if (strcmp(name,
"String") == 0)
179 if (strcmp(name,
"Url") == 0)
182 if (strcmp(name,
"Array") == 0)
185 if (strcmp(name,
"Structure") == 0)
186 return dods_structure_c;
188 if (strcmp(name,
"Sequence") == 0)
189 return dods_sequence_c;
191 if (strcmp(name,
"Grid") == 0)
220 static bool is_not(
const char *name,
const char *tag)
222 return strcmp(name, tag) != 0;
225 void DDXParser::set_state(DDXParser::ParseState state)
230 DDXParser::ParseState DDXParser::get_state()
const 235 void DDXParser::pop_state()
243 void DDXParser::transfer_xml_attrs(
const xmlChar **attributes,
int nb_attributes)
245 if (!attribute_table.empty())
246 attribute_table.clear();
248 unsigned int index = 0;
249 for (
int i = 0; i < nb_attributes; ++i, index += 5) {
252 attribute_table.insert(map<string, XMLAttribute>::value_type(
253 string((
const char *)attributes[index]),
254 XMLAttribute(attributes + index + 1)));
256 DBG(cerr <<
"Attribute '" << (
const char *)attributes[index] <<
"': " 257 << attribute_table[(
const char *)attributes[index]].value << endl);
261 void DDXParser::transfer_xml_ns(
const xmlChar **namespaces,
int nb_namespaces)
263 for (
int i = 0; i < nb_namespaces; ++i ) {
266 namespace_table.insert(map<string,string>::value_type(
267 namespaces[i*2] != 0 ? (
const char *)namespaces[i*2] :
"",
268 (
const char *)namespaces[i*2+1]));
276 bool DDXParser::check_required_attribute(
const string & attr)
278 map < string, XMLAttribute >::iterator i = attribute_table.find(attr);
279 if (i == attribute_table.end())
290 bool DDXParser::check_attribute(
const string & attr)
292 return (attribute_table.find(attr) != attribute_table.end());
303 void DDXParser::process_attribute_element(
const xmlChar **attrs,
int nb_attributes)
306 transfer_xml_attrs(attrs, nb_attributes);
308 bool error = !(check_required_attribute(
string(
"name"))
309 && check_required_attribute(
string(
"type")));
313 if (attribute_table[
"type"].value ==
"Container") {
314 set_state(inside_attribute_container);
317 AttrTable *parent = at_stack.top();
319 child = parent->append_container(attribute_table[
"name"].value);
320 at_stack.push(child);
321 DBG2(cerr <<
"Pushing at" << endl);
323 else if (attribute_table[
"type"].value ==
"OtherXML") {
324 set_state(inside_other_xml_attribute);
326 dods_attr_name = attribute_table[
"name"].value;
327 dods_attr_type = attribute_table[
"type"].value;
330 set_state(inside_attribute);
334 dods_attr_name = attribute_table[
"name"].value;
335 dods_attr_type = attribute_table[
"type"].value;
342 void DDXParser::process_attribute_alias(
const xmlChar **attrs,
int nb_attributes)
344 transfer_xml_attrs(attrs, nb_attributes);
345 if (check_required_attribute(
string(
"name"))
346 && check_required_attribute(
string(
"attribute"))) {
347 set_state(inside_alias);
348 at_stack.top()->attr_alias(attribute_table[
"name"].value,
349 attribute_table[
"attribute"].value);
360 void DDXParser::process_variable(
Type t, ParseState s,
const xmlChar **attrs,
363 transfer_xml_attrs(attrs, nb_attributes);
367 if (bt_stack.top()->type() == dods_array_c
368 || check_required_attribute(
"name")) {
369 BaseType *btp = factory(t, attribute_table[
"name"].value);
371 ddx_fatal_error(
this,
"Internal parser error; could not instantiate the variable '%s'.",
372 attribute_table[
"name"].value.c_str());
381 at_stack.push(&btp->get_attr_table());
389 void DDXParser::process_dimension(
const xmlChar **attrs,
int nb_attributes)
391 transfer_xml_attrs(attrs, nb_attributes);
392 if (check_required_attribute(
string(
"size"))) {
393 set_state(inside_dimension);
394 Array *ap = dynamic_cast < Array * >(bt_stack.top());
400 ap->append_dim(atoi(attribute_table[
"size"].value.c_str()),
401 attribute_table[
"name"].value);
407 void DDXParser::process_blob(
const xmlChar **attrs,
int nb_attributes)
409 transfer_xml_attrs(attrs, nb_attributes);
410 if (check_required_attribute(
string(
"href"))) {
411 set_state(inside_blob_href);
412 *blob_href = attribute_table[
"href"].value;
423 DDXParser::is_attribute_or_alias(
const char *name,
const xmlChar **attrs,
426 if (strcmp(name,
"Attribute") == 0) {
427 process_attribute_element(attrs, nb_attributes);
431 else if (strcmp(name,
"Alias") == 0) {
432 process_attribute_alias(attrs, nb_attributes);
445 inline bool DDXParser::is_variable(
const char *name,
const xmlChar **attrs,
451 process_variable(t, inside_simple_type, attrs, nb_attributes);
454 else if (strcmp(name,
"Array") == 0) {
455 process_variable(dods_array_c, inside_array, attrs, nb_attributes);
458 else if (strcmp(name,
"Structure") == 0) {
459 process_variable(dods_structure_c, inside_structure, attrs, nb_attributes);
462 else if (strcmp(name,
"Sequence") == 0) {
463 process_variable(dods_sequence_c, inside_sequence, attrs, nb_attributes);
466 else if (strcmp(name,
"Grid") == 0) {
467 process_variable(dods_grid_c, inside_grid, attrs, nb_attributes);
474 void DDXParser::finish_variable(
const char *tag,
Type t,
const char *expected)
476 if (strcmp(tag, expected) != 0) {
478 "Expected an end tag for a %s; found '%s' instead.",
485 BaseType *btp = bt_stack.top();
490 if (btp->type() != t) {
492 "Internal error: Expected a %s variable.",
498 if (t == dods_array_c
499 && static_cast<Array*>(btp)->dimensions() == 0) {
501 "No dimension element included in the Array '%s'.",
502 btp->name().c_str());
507 BaseType *parent = bt_stack.top();
509 if (!(parent->is_vector_type() || parent->is_constructor_type())) {
511 "Tried to add the array variable '%s' to a non-constructor type (%s %s).",
513 bt_stack.top()->type_name().c_str(),
514 bt_stack.top()->name().c_str());
519 parent->add_var_nocopy(btp);
536 parser->error_msg =
"";
537 parser->char_data =
"";
545 parser->bt_stack.push(
new Structure(
"dummy_dds"));
547 parser->set_state(parser_start);
549 DBG2(cerr <<
"Parser state: " << states[parser->get_state()] << endl);
557 DBG2(cerr <<
"Ending state == " << states[parser->get_state()] <<
560 if (parser->get_state() != parser_start)
565 if (parser->get_state() == parser_error) {
573 delete parser->bt_stack.top();
574 parser->bt_stack.pop();
575 ddx_fatal_error(parser,
"Parse error: Expected a Structure, Sequence or Grid variable.");
584 delete parser->bt_stack.top();
585 parser->bt_stack.pop();
588 void DDXParser::ddx_sax2_start_element(
void *p,
589 const xmlChar *l,
const xmlChar *prefix,
const xmlChar *URI,
590 int nb_namespaces,
const xmlChar **namespaces,
591 int nb_attributes,
int ,
const xmlChar **attributes)
594 const char *localname = (
const char *)l;
596 DBG2(cerr <<
"start element: " << localname <<
", states: " 597 << states[parser->get_state()]);
599 switch (parser->get_state()) {
601 if (strcmp(localname,
"Dataset") == 0) {
602 parser->set_state(inside_dataset);
603 parser->root_ns = URI != 0 ? (
const char *)URI:
"";
604 parser->transfer_xml_attrs(attributes, nb_attributes);
606 if (parser->check_required_attribute(
string(
"name")))
609 if (parser->check_attribute(
"dapVersion"))
610 parser->dds->
set_dap_version(parser->attribute_table[
"dapVersion"].value);
614 "Expected response to start with a Dataset element; found '%s' instead.",
619 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
621 else if (parser->is_variable(localname, attributes, nb_attributes))
623 else if (strcmp(localname,
"blob") == 0 || strcmp(localname,
"dataBLOB") == 0) {
624 parser->process_blob(attributes, nb_attributes);
629 "Expected an Attribute, Alias or variable element; found '%s' instead.",
633 case inside_attribute_container:
634 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
638 "Expected an Attribute or Alias element; found '%s' instead.",
642 case inside_attribute:
643 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
645 else if (strcmp(localname,
"value") == 0)
646 parser->set_state(inside_attribute_value);
649 "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
653 case inside_attribute_value:
655 "Internal parser error; unexpected state, inside value while processing element '%s'.",
659 case inside_other_xml_attribute:
660 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname << endl);
662 parser->other_xml_depth++;
666 parser->other_xml.append(
"<");
668 parser->other_xml.append((
const char *)prefix);
669 parser->other_xml.append(
":");
671 parser->other_xml.append(localname);
673 if (nb_namespaces != 0) {
674 parser->transfer_xml_ns(namespaces, nb_namespaces);
676 for (map<string,string>::iterator i = parser->namespace_table.begin();
677 i != parser->namespace_table.end();
679 parser->other_xml.append(
" xmlns");
680 if (!i->first.empty()) {
681 parser->other_xml.append(
":");
682 parser->other_xml.append(i->first);
684 parser->other_xml.append(
"=\"");
685 parser->other_xml.append(i->second);
686 parser->other_xml.append(
"\"");
690 if (nb_attributes != 0) {
691 parser->transfer_xml_attrs(attributes, nb_attributes);
692 for (XMLAttrMap::iterator i = parser->attr_table_begin();
693 i != parser->attr_table_end();
695 parser->other_xml.append(
" ");
696 if (!i->second.prefix.empty()) {
697 parser->other_xml.append(i->second.prefix);
698 parser->other_xml.append(
":");
700 parser->other_xml.append(i->first);
701 parser->other_xml.append(
"=\"");
702 parser->other_xml.append(i->second.value);
703 parser->other_xml.append(
"\"");
707 parser->other_xml.append(
">");
712 "Internal parser error; unexpected state, inside alias while processing element '%s'.",
716 case inside_simple_type:
717 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
721 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
726 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
728 else if (is_not(localname,
"Array")
729 && parser->is_variable(localname, attributes, nb_attributes))
731 else if (strcmp(localname,
"dimension") == 0) {
732 parser->process_dimension(attributes, nb_attributes);
737 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
741 case inside_dimension:
743 "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
747 case inside_structure:
748 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
750 else if (parser->is_variable(localname, attributes, nb_attributes))
754 "Expected an Attribute, Alias or variable element; found '%s' instead.",
758 case inside_sequence:
759 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
761 else if (parser->is_variable(localname, attributes, nb_attributes))
765 "Expected an Attribute, Alias or variable element; found '%s' instead.",
770 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
772 else if (strcmp(localname,
"Array") == 0)
773 parser->process_variable(dods_array_c, inside_array, attributes, nb_attributes);
774 else if (strcmp(localname,
"Map") == 0)
775 parser->process_variable(dods_array_c, inside_map, attributes, nb_attributes);
778 "Expected an Attribute, Alias or variable element; found '%s' instead.",
783 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
785 else if (is_not(localname,
"Array") && is_not(localname,
"Sequence")
786 && is_not(localname,
"Grid")
787 && parser->is_variable(localname, attributes, nb_attributes))
789 else if (strcmp(localname,
"dimension") == 0) {
790 parser->process_dimension(attributes, nb_attributes);
795 "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
799 case inside_blob_href:
801 "Internal parser error; unexpected state, inside blob href while processing element '%s'.",
807 parser->set_state(parser_unknown);
814 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
817 void DDXParser::ddx_sax2_end_element(
void *p,
const xmlChar *l,
818 const xmlChar *prefix,
const xmlChar *URI)
821 const char *localname = (
const char *)l;
823 DBG2(cerr <<
"End element " << localname <<
" (state " 824 << states[parser->get_state()] <<
")" << endl);
826 switch (parser->get_state()) {
829 "Internal parser error; unexpected state, inside start state while processing element '%s'.",
834 if (strcmp(localname,
"Dataset") == 0)
838 "Expected an end Dataset tag; found '%s' instead.",
842 case inside_attribute_container:
843 if (strcmp(localname,
"Attribute") == 0) {
845 parser->at_stack.pop();
849 "Expected an end Attribute tag; found '%s' instead.",
853 case inside_attribute:
854 if (strcmp(localname,
"Attribute") == 0)
858 "Expected an end Attribute tag; found '%s' instead.",
862 case inside_attribute_value:
863 if (strcmp(localname,
"value") == 0) {
867 parser->dods_attr_type, parser->char_data);
868 parser->char_data =
"";
872 "Expected an end value tag; found '%s' instead.",
877 case inside_other_xml_attribute: {
878 if (strcmp(localname,
"Attribute") == 0
879 && parser->root_ns == (
const char *)URI) {
881 DBGN(cerr << endl <<
"\t Popping the 'inside_other_xml_attribute' state" 888 parser->dods_attr_type, parser->other_xml);
890 parser->other_xml =
"";
893 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname
894 <<
", depth: " << parser->other_xml_depth << endl);
895 if (parser->other_xml_depth == 0)
897 "Expected an OtherXML attribute to end! Instead I found '%s'",
899 parser->other_xml_depth--;
901 parser->other_xml.append(
"</");
903 parser->other_xml.append((
const char *)prefix);
904 parser->other_xml.append(
":");
906 parser->other_xml.append(localname);
907 parser->other_xml.append(
">");
916 case inside_simple_type: {
920 BaseType *btp = parser->bt_stack.top();
921 parser->bt_stack.pop();
922 parser->at_stack.pop();
924 BaseType *parent = parser->bt_stack.top();
932 "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).",
934 parser->bt_stack.top()->
936 parser->bt_stack.top()->name().
943 "Expected an end tag for a simple type; found '%s' instead.",
950 parser->finish_variable(localname, dods_array_c,
"Array");
953 case inside_dimension:
954 if (strcmp(localname,
"dimension") == 0)
958 "Expected an end dimension tag; found '%s' instead.",
962 case inside_structure:
963 parser->finish_variable(localname, dods_structure_c,
"Structure");
966 case inside_sequence:
967 parser->finish_variable(localname, dods_sequence_c,
"Sequence");
971 parser->finish_variable(localname, dods_grid_c,
"Grid");
975 parser->finish_variable(localname, dods_array_c,
"Map");
978 case inside_blob_href:
979 if (strcmp(localname,
"blob") == 0 || strcmp(localname,
"dataBLOB") == 0)
983 "Expected an end dataBLOB/blob tag; found '%s' instead.",
996 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
1006 switch (parser->get_state()) {
1007 case inside_attribute_value:
1008 parser->char_data.append((
const char *)(ch), len);
1009 DBG2(cerr <<
"Characters: '" << parser->char_data <<
"'" << endl);
1012 case inside_other_xml_attribute:
1013 parser->other_xml.append((
const char *)(ch), len);
1014 DBG2(cerr <<
"Other XML Characters: '" << parser->other_xml <<
"'" << endl);
1031 switch (parser->get_state()) {
1032 case inside_other_xml_attribute:
1033 parser->other_xml.append((
const char *)(ch), len);
1050 switch (parser->get_state()) {
1051 case inside_other_xml_attribute:
1052 parser->other_xml.append((
const char *)(value), len);
1055 case parser_unknown:
1060 "Found a CData block but none are allowed by DAP.");
1072 return xmlGetPredefinedEntity(name);
1087 parser->set_state(parser_error);
1089 va_start(args, msg);
1091 vsnprintf(str, 1024, msg, args);
1094 int line = xmlSAX2GetLineNumber(parser->ctxt);
1096 parser->error_msg +=
"At line " + long_to_string(line) +
": ";
1097 parser->error_msg += string(str) + string(
"\n");
1102 void DDXParser::cleanup_parse(xmlParserCtxtPtr & context)
1104 bool wellFormed = context->wellFormed;
1105 bool valid = context->valid;
1107 context->sax = NULL;
1108 xmlFreeParserCtxt(context);
1112 while (!bt_stack.empty()) {
1113 delete bt_stack.top();
1118 throw DDXParseFailed(
string(
"\nThe DDX is not a well formed XML document.\n") + error_msg);
1122 throw DDXParseFailed(
string(
"\nThe DDX is not a valid document.\n") + error_msg);
1125 if (get_state() == parser_error) {
1126 throw DDXParseFailed(
string(
"\nError parsing DDX response.\n") + error_msg);
1140 if (!in || in.eof())
1141 throw InternalErr(__FILE__, __LINE__,
"Input stream not open or read error");
1143 const int size = 1024;
1144 char chars[size + 1];
1147 in.readsome(chars, 4);
1148 int res = in.gcount();
1151 xmlParserCtxtPtr context = xmlCreatePushParserCtxt(NULL, NULL, chars, res,
"stream");
1157 xmlSAXHandler ddx_sax_parser;
1158 memset( &ddx_sax_parser, 0,
sizeof(xmlSAXHandler) );
1169 ddx_sax_parser.initialized = XML_SAX2_MAGIC;
1170 ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element;
1171 ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element;
1173 context->sax = &ddx_sax_parser;
1174 context->userData =
this;
1175 context->validate =
true;
1177 in.getline(chars, size);
1179 chars[res-1] =
'\n';
1181 while (res > 0 && !
is_boundary(chars, boundary)) {
1182 DBG(cerr <<
"line (" << res <<
"): " << chars << endl);
1183 xmlParseChunk(ctxt, chars, res, 0);
1185 in.getline(chars, size);
1188 chars[res-1] =
'\n';
1195 xmlParseChunk(ctxt, chars, 0, 1);
1197 cleanup_parse(context);
1206 if (!in || feof(in) || ferror(in))
1208 "Input stream not open or read error");
1210 const int size = 1024;
1213 int res = fread(chars, 1, 4, in);
1216 xmlParserCtxtPtr context =
1217 xmlCreatePushParserCtxt(NULL, NULL, chars, res,
"stream");
1223 xmlSAXHandler ddx_sax_parser;
1224 memset( &ddx_sax_parser, 0,
sizeof(xmlSAXHandler) );
1235 ddx_sax_parser.initialized = XML_SAX2_MAGIC;
1236 ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element;
1237 ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element;
1239 context->sax = &ddx_sax_parser;
1240 context->userData =
this;
1241 context->validate =
true;
1244 while ((fgets(chars, size, in) != 0) && !
is_boundary(chars, boundary)) {
1245 DBG(cerr <<
"line (" << strlen(chars) <<
"): " << chars << endl);
1246 xmlParseChunk(ctxt, chars, strlen(chars), 0);
1250 xmlParseChunk(ctxt, chars, 0, 1);
1252 cleanup_parse(context);
1277 xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str());
1281 (
"Could not initialize the parser with the file: '")
1282 + document +
string(
"'."));
1288 xmlSAXHandler ddx_sax_parser;
1289 memset( &ddx_sax_parser, 0,
sizeof(xmlSAXHandler) );
1300 ddx_sax_parser.initialized = XML_SAX2_MAGIC;
1301 ddx_sax_parser.startElementNs = &DDXParser::ddx_sax2_start_element;
1302 ddx_sax_parser.endElementNs = &DDXParser::ddx_sax2_end_element;
1304 context->sax = &ddx_sax_parser;
1305 context->userData =
this;
1306 context->validate =
false;
1308 xmlParseDocument(context);
1310 cleanup_parse(context);
void intern_stream(FILE *in, DDS *dds, string &cid, const string &boundary="")
Read the DDX from a stream instead of a file.
Contains the attributes for a dataset.
static void ddx_start_document(void *parser)
static void ddx_get_cdata(void *parser, const xmlChar *value, int len)
Holds a structure (aggregate) type.
virtual void add_var(BaseType *bt, Part part=nil)
Add a variable.
Type
Identifies the data type.
A class for software fault reporting.
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable...
static void ddx_fatal_error(void *parser, const char *msg,...)
ObjectType get_type(const string &value)
virtual bool is_vector_type() const
Returns true if the instance is a vector (i.e., array) type variable.
static void ddx_end_document(void *parser)
static xmlEntityPtr ddx_get_entity(void *parser, const xmlChar *name)
static void ddx_get_characters(void *parser, const xmlChar *ch, int len)
bool is_simple_type(Type t)
Returns true if the instance is a numeric, string or URL type variable.
virtual AttrTable & get_attr_table()
bool is_boundary(const char *line, const string &boundary)
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
void set_dataset_name(const string &n)
The basic data type for the DODS DAP types.
static void ddx_ignoreable_whitespace(void *parser, const xmlChar *ch, int len)
void intern(const string &document, DDS *dest_dds, string &cid)
void set_dap_version(const string &version_string="2.0")
void add_var(BaseType *bt)
Adds a copy of the variable to the DDS. Using the ptr_duplicate() method, perform a deep copy on the ...