50#include "DDXParserSAX2.h"
58#if defined(DODS_DEBUG) || defined(DODS_DEUG2)
59static const char *states[] =
65 "attribute_container",
68 "other_xml_attribute",
92BaseType *DDXParser::factory(
Type t,
const string & name)
96 return d_factory->NewByte(name);
99 return d_factory->NewInt16(name);
102 return d_factory->NewUInt16(name);
105 return d_factory->NewInt32(name);
108 return d_factory->NewUInt32(name);
111 return d_factory->NewFloat32(name);
114 return d_factory->NewFloat64(name);
117 return d_factory->NewStr(name);
120 return d_factory->NewUrl(name);
123 return d_factory->NewArray(name);
125 case dods_structure_c:
126 return d_factory->NewStructure(name);
128 case dods_sequence_c:
129 return d_factory->NewSequence(name);
132 return d_factory->NewGrid(name);
139static bool is_not(
const char *name,
const char *tag)
141 return strcmp(name, tag) != 0;
144void DDXParser::set_state(DDXParser::ParseState state)
149DDXParser::ParseState DDXParser::get_state()
const
154void DDXParser::pop_state()
162void DDXParser::transfer_xml_attrs(
const xmlChar **attributes,
int nb_attributes)
164 if (!attribute_table.empty())
165 attribute_table.clear();
167 unsigned int index = 0;
168 for (
int i = 0; i < nb_attributes; ++i, index += 5) {
171 attribute_table.insert(map<string, XMLAttribute>::value_type(
172 string((
const char *)attributes[index]),
173 XMLAttribute(attributes + index + 1)));
175 DBG(cerr <<
"Attribute '" << (
const char *)attributes[index] <<
"': "
176 << attribute_table[(
const char *)attributes[index]].value << endl);
180void DDXParser::transfer_xml_ns(
const xmlChar **namespaces,
int nb_namespaces)
182 for (
int i = 0; i < nb_namespaces; ++i ) {
185 namespace_table.insert(map<string,string>::value_type(
186 namespaces[i*2] != 0 ? (
const char *)namespaces[i*2] :
"",
187 (const char *)namespaces[i*2+1]));
195bool DDXParser::check_required_attribute(
const string & attr)
197 map < string, XMLAttribute >::iterator i = attribute_table.find(attr);
198 if (i == attribute_table.end())
209bool DDXParser::check_attribute(
const string & attr)
211 return (attribute_table.find(attr) != attribute_table.end());
222void DDXParser::process_attribute_element(
const xmlChar **attrs,
int nb_attributes)
225 transfer_xml_attrs(attrs, nb_attributes);
227 bool error = !(check_required_attribute(
string(
"name"))
228 && check_required_attribute(
string(
"type")));
232 if (attribute_table[
"type"].value ==
"Container") {
233 set_state(inside_attribute_container);
236 AttrTable *parent = at_stack.top();
238 child = parent->append_container(attribute_table[
"name"].value);
239 at_stack.push(child);
240 DBG2(cerr <<
"Pushing at" << endl);
242 else if (attribute_table[
"type"].value ==
"OtherXML") {
243 set_state(inside_other_xml_attribute);
245 dods_attr_name = attribute_table[
"name"].value;
246 dods_attr_type = attribute_table[
"type"].value;
249 set_state(inside_attribute);
253 dods_attr_name = attribute_table[
"name"].value;
254 dods_attr_type = attribute_table[
"type"].value;
261void DDXParser::process_attribute_alias(
const xmlChar **attrs,
int nb_attributes)
263 transfer_xml_attrs(attrs, nb_attributes);
264 if (check_required_attribute(
string(
"name"))
265 && check_required_attribute(
string(
"attribute"))) {
266 set_state(inside_alias);
267 at_stack.top()->attr_alias(attribute_table[
"name"].value,
268 attribute_table[
"attribute"].value);
279void DDXParser::process_variable(
Type t, ParseState s,
const xmlChar **attrs,
282 transfer_xml_attrs(attrs, nb_attributes);
286 if (bt_stack.top()->type() == dods_array_c
287 || check_required_attribute(
"name")) {
288 BaseType *btp = factory(t, attribute_table[
"name"].value);
290 ddx_fatal_error(
this,
"Internal parser error; could not instantiate the variable '%s'.",
291 attribute_table[
"name"].value.c_str());
300 at_stack.push(&btp->get_attr_table());
308void DDXParser::process_dimension(
const xmlChar **attrs,
int nb_attributes)
310 transfer_xml_attrs(attrs, nb_attributes);
311 if (check_required_attribute(
string(
"size"))) {
312 set_state(inside_dimension);
313 Array *ap =
dynamic_cast < Array *
>(bt_stack.top());
319 ap->append_dim(atoi(attribute_table[
"size"].value.c_str()),
320 attribute_table[
"name"].value);
326void DDXParser::process_blob(
const xmlChar **attrs,
int nb_attributes)
328 transfer_xml_attrs(attrs, nb_attributes);
329 if (check_required_attribute(
string(
"href"))) {
330 set_state(inside_blob_href);
331 *blob_href = attribute_table[
"href"].value;
342DDXParser::is_attribute_or_alias(
const char *name,
const xmlChar **attrs,
345 if (strcmp(name,
"Attribute") == 0) {
346 process_attribute_element(attrs, nb_attributes);
350 else if (strcmp(name,
"Alias") == 0) {
351 process_attribute_alias(attrs, nb_attributes);
364inline bool DDXParser::is_variable(
const char *name,
const xmlChar **attrs,
370 process_variable(t, inside_simple_type, attrs, nb_attributes);
373 else if (strcmp(name,
"Array") == 0) {
374 process_variable(dods_array_c, inside_array, attrs, nb_attributes);
377 else if (strcmp(name,
"Structure") == 0) {
378 process_variable(dods_structure_c, inside_structure, attrs, nb_attributes);
381 else if (strcmp(name,
"Sequence") == 0) {
382 process_variable(dods_sequence_c, inside_sequence, attrs, nb_attributes);
385 else if (strcmp(name,
"Grid") == 0) {
386 process_variable(dods_grid_c, inside_grid, attrs, nb_attributes);
393void DDXParser::finish_variable(
const char *tag,
Type t,
const char *expected)
395 if (strcmp(tag, expected) != 0) {
397 "Expected an end tag for a %s; found '%s' instead.",
404 BaseType *btp = bt_stack.top();
409 if (btp->type() != t) {
411 "Internal error: Expected a %s variable.",
417 if (t == dods_array_c
418 &&
static_cast<Array*
>(btp)->dimensions() == 0) {
420 "No dimension element included in the Array '%s'.",
421 btp->name().c_str());
426 BaseType *parent = bt_stack.top();
428 if (!(parent->is_vector_type() || parent->is_constructor_type())) {
430 "Tried to add the array variable '%s' to a non-constructor type (%s %s).",
432 bt_stack.top()->type_name().c_str(),
433 bt_stack.top()->name().c_str());
438 parent->add_var_nocopy(btp);
455 parser->error_msg =
"";
456 parser->char_data =
"";
464 parser->bt_stack.push(
new Structure(
"dummy_dds"));
466 parser->set_state(parser_start);
468 DBG2(cerr <<
"Parser state: " << states[parser->get_state()] << endl);
476 DBG2(cerr <<
"Ending state == " << states[parser->get_state()] <<
479 if (parser->get_state() != parser_start)
484 if (parser->get_state() == parser_error) {
492 delete parser->bt_stack.top();
493 parser->bt_stack.pop();
494 ddx_fatal_error(parser,
"Parse error: Expected a Structure, Sequence or Grid variable.");
503 delete parser->bt_stack.top();
504 parser->bt_stack.pop();
507void DDXParser::ddx_sax2_start_element(
void *p,
508 const xmlChar *l,
const xmlChar *prefix,
const xmlChar *URI,
509 int nb_namespaces,
const xmlChar **namespaces,
510 int nb_attributes,
int ,
const xmlChar **attributes)
513 const char *localname = (
const char *)l;
515 DBG2(cerr <<
"start element: " << localname <<
", states: "
516 << states[parser->get_state()]);
518 switch (parser->get_state()) {
520 if (strcmp(localname,
"Dataset") == 0) {
521 parser->set_state(inside_dataset);
522 parser->root_ns = URI != 0 ? (
const char *)URI:
"";
523 parser->transfer_xml_attrs(attributes, nb_attributes);
525 if (parser->check_required_attribute(
string(
"name")))
528 if (parser->check_attribute(
"dapVersion"))
529 parser->dds->
set_dap_version(parser->attribute_table[
"dapVersion"].value);
533 "Expected response to start with a Dataset element; found '%s' instead.",
538 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
540 else if (parser->is_variable(localname, attributes, nb_attributes))
542 else if (strcmp(localname,
"blob") == 0 || strcmp(localname,
"dataBLOB") == 0) {
543 parser->process_blob(attributes, nb_attributes);
548 "Expected an Attribute, Alias or variable element; found '%s' instead.",
552 case inside_attribute_container:
553 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
557 "Expected an Attribute or Alias element; found '%s' instead.",
561 case inside_attribute:
562 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
564 else if (strcmp(localname,
"value") == 0)
565 parser->set_state(inside_attribute_value);
568 "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
572 case inside_attribute_value:
574 "Internal parser error; unexpected state, inside value while processing element '%s'.",
578 case inside_other_xml_attribute:
579 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname << endl);
581 parser->other_xml_depth++;
585 parser->other_xml.append(
"<");
587 parser->other_xml.append((
const char *)prefix);
588 parser->other_xml.append(
":");
590 parser->other_xml.append(localname);
592 if (nb_namespaces != 0) {
593 parser->transfer_xml_ns(namespaces, nb_namespaces);
595 for (map<string,string>::iterator i = parser->namespace_table.begin();
596 i != parser->namespace_table.end();
598 parser->other_xml.append(
" xmlns");
599 if (!i->first.empty()) {
600 parser->other_xml.append(
":");
601 parser->other_xml.append(i->first);
603 parser->other_xml.append(
"=\"");
604 parser->other_xml.append(i->second);
605 parser->other_xml.append(
"\"");
609 if (nb_attributes != 0) {
610 parser->transfer_xml_attrs(attributes, nb_attributes);
611 for (XMLAttrMap::iterator i = parser->attr_table_begin();
612 i != parser->attr_table_end();
614 parser->other_xml.append(
" ");
615 if (!i->second.prefix.empty()) {
616 parser->other_xml.append(i->second.prefix);
617 parser->other_xml.append(
":");
619 parser->other_xml.append(i->first);
620 parser->other_xml.append(
"=\"");
621 parser->other_xml.append(i->second.value);
622 parser->other_xml.append(
"\"");
626 parser->other_xml.append(
">");
631 "Internal parser error; unexpected state, inside alias while processing element '%s'.",
635 case inside_simple_type:
636 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
640 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
645 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
647 else if (is_not(localname,
"Array")
648 && parser->is_variable(localname, attributes, nb_attributes))
650 else if (strcmp(localname,
"dimension") == 0) {
651 parser->process_dimension(attributes, nb_attributes);
656 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
660 case inside_dimension:
662 "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
666 case inside_structure:
667 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
669 else if (parser->is_variable(localname, attributes, nb_attributes))
673 "Expected an Attribute, Alias or variable element; found '%s' instead.",
677 case inside_sequence:
678 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
680 else if (parser->is_variable(localname, attributes, nb_attributes))
684 "Expected an Attribute, Alias or variable element; found '%s' instead.",
689 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
691 else if (strcmp(localname,
"Array") == 0)
692 parser->process_variable(dods_array_c, inside_array, attributes, nb_attributes);
693 else if (strcmp(localname,
"Map") == 0)
694 parser->process_variable(dods_array_c, inside_map, attributes, nb_attributes);
697 "Expected an Attribute, Alias or variable element; found '%s' instead.",
702 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
704 else if (is_not(localname,
"Array") && is_not(localname,
"Sequence")
705 && is_not(localname,
"Grid")
706 && parser->is_variable(localname, attributes, nb_attributes))
708 else if (strcmp(localname,
"dimension") == 0) {
709 parser->process_dimension(attributes, nb_attributes);
714 "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
718 case inside_blob_href:
720 "Internal parser error; unexpected state, inside blob href while processing element '%s'.",
726 parser->set_state(parser_unknown);
733 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
736void DDXParser::ddx_sax2_end_element(
void *p,
const xmlChar *l,
737 const xmlChar *prefix,
const xmlChar *URI)
739 DDXParser *parser =
static_cast<DDXParser*
>(p);
740 const char *localname = (
const char *)l;
742 DBG2(cerr <<
"End element " << localname <<
" (state "
743 << states[parser->get_state()] <<
")" << endl);
745 switch (parser->get_state()) {
748 "Internal parser error; unexpected state, inside start state while processing element '%s'.",
753 if (strcmp(localname,
"Dataset") == 0)
757 "Expected an end Dataset tag; found '%s' instead.",
761 case inside_attribute_container:
762 if (strcmp(localname,
"Attribute") == 0) {
764 parser->at_stack.pop();
768 "Expected an end Attribute tag; found '%s' instead.",
772 case inside_attribute:
773 if (strcmp(localname,
"Attribute") == 0)
777 "Expected an end Attribute tag; found '%s' instead.",
781 case inside_attribute_value:
782 if (strcmp(localname,
"value") == 0) {
784 AttrTable *atp = parser->at_stack.top();
785 atp->append_attr(parser->dods_attr_name,
786 parser->dods_attr_type, parser->char_data);
787 parser->char_data =
"";
791 "Expected an end value tag; found '%s' instead.",
796 case inside_other_xml_attribute: {
797 if (strcmp(localname,
"Attribute") == 0
798 && parser->root_ns == (
const char *)URI) {
800 DBGN(cerr << endl <<
"\t Popping the 'inside_other_xml_attribute' state"
805 AttrTable *atp = parser->at_stack.top();
806 atp->append_attr(parser->dods_attr_name,
807 parser->dods_attr_type, parser->other_xml);
809 parser->other_xml =
"";
812 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname
813 <<
", depth: " << parser->other_xml_depth << endl);
814 if (parser->other_xml_depth == 0)
816 "Expected an OtherXML attribute to end! Instead I found '%s'",
818 parser->other_xml_depth--;
820 parser->other_xml.append(
"</");
822 parser->other_xml.append((
const char *)prefix);
823 parser->other_xml.append(
":");
825 parser->other_xml.append(localname);
826 parser->other_xml.append(
">");
835 case inside_simple_type: {
839 BaseType *btp = parser->bt_stack.top();
840 parser->bt_stack.pop();
841 parser->at_stack.pop();
843 BaseType *parent = parser->bt_stack.top();
845 if (parent->is_vector_type() || parent->is_constructor_type()) {
846 parent->add_var(btp);
851 "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).",
853 parser->bt_stack.top()->
855 parser->bt_stack.top()->name().
862 "Expected an end tag for a simple type; found '%s' instead.",
869 parser->finish_variable(localname, dods_array_c,
"Array");
872 case inside_dimension:
873 if (strcmp(localname,
"dimension") == 0)
877 "Expected an end dimension tag; found '%s' instead.",
881 case inside_structure:
882 parser->finish_variable(localname, dods_structure_c,
"Structure");
885 case inside_sequence:
886 parser->finish_variable(localname, dods_sequence_c,
"Sequence");
890 parser->finish_variable(localname, dods_grid_c,
"Grid");
894 parser->finish_variable(localname, dods_array_c,
"Map");
897 case inside_blob_href:
898 if (strcmp(localname,
"blob") == 0 || strcmp(localname,
"dataBLOB") == 0)
902 "Expected an end dataBLOB/blob tag; found '%s' instead.",
915 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
925 switch (parser->get_state()) {
926 case inside_attribute_value:
927 parser->char_data.append((
const char *)(ch), len);
928 DBG2(cerr <<
"Characters: '" << parser->char_data <<
"'" << endl);
931 case inside_other_xml_attribute:
932 parser->other_xml.append((
const char *)(ch), len);
933 DBG2(cerr <<
"Other XML Characters: '" << parser->other_xml <<
"'" << endl);
950 switch (parser->get_state()) {
951 case inside_other_xml_attribute:
952 parser->other_xml.append((
const char *)(ch), len);
969 switch (parser->get_state()) {
970 case inside_other_xml_attribute:
971 parser->other_xml.append((
const char *)(value), len);
979 "Found a CData block but none are allowed by DAP.");
991 return xmlGetPredefinedEntity(name);
1006 parser->set_state(parser_error);
1008 va_start(args, msg);
1010 vsnprintf(str, 1024, msg, args);
1013 int line = xmlSAX2GetLineNumber(parser->ctxt);
1015 parser->error_msg +=
"At line " + long_to_string(line) +
": ";
1016 parser->error_msg += string(str) + string(
"\n");
1021void DDXParser::cleanup_parse()
1023 bool wellFormed = ctxt->wellFormed;
1024 bool valid = ctxt->valid;
1026 xmlFreeParserCtxt(ctxt);
1030 while (!bt_stack.empty()) {
1031 delete bt_stack.top();
1036 throw DDXParseFailed(
string(
"The DDX is not a well formed XML document.\n") + error_msg);
1040 throw DDXParseFailed(
string(
"The DDX is not a valid document.\n") + error_msg);
1043 if (get_state() == parser_error) {
1044 throw DDXParseFailed(
string(
"Error parsing DDX response.\n") + error_msg);
1058 if (!in || in.eof())
1059 throw InternalErr(__FILE__, __LINE__,
"Input stream not open or read error");
1061 const int size = 1024;
1062 char chars[size + 1];
1066 int res = in.gcount();
1069 ctxt = xmlCreatePushParserCtxt(&ddx_sax_parser,
this, chars, res,
"stream");
1072 throw DDXParseFailed(
"Error parsing DDX response: Input does not look like XML");
1077 ctxt->validate =
true;
1079 in.getline(chars, size);
1081 chars[res-1] =
'\n';
1083 while (res > 0 && !
is_boundary(chars, boundary)) {
1084 DBG(cerr <<
"line (" << res <<
"): " << chars << endl);
1085 xmlParseChunk(ctxt, chars, res, 0);
1087 in.getline(chars, size);
1090 chars[res-1] =
'\n';
1097 xmlParseChunk(ctxt, chars, 0, 1);
1102 throw DDXParseFailed(
"Error parsing DDX response: Could not read from input stream.");
1112 if (!in || feof(in) || ferror(in))
1113 throw InternalErr(__FILE__, __LINE__,
"Input stream not open or read error");
1115 const int size = 1024;
1118 int res = fread(chars, 1, 4, in);
1121 ctxt = xmlCreatePushParserCtxt(&ddx_sax_parser,
this, chars, res,
"stream");
1124 throw DDXParseFailed(
"Error parsing DDX response: Input does not look like XML");
1129 ctxt->validate =
true;
1132 while ((fgets(chars, size, in) != 0) && !
is_boundary(chars, boundary)) {
1133 DBG(cerr <<
"line (" << strlen(chars) <<
"): " << chars << endl);
1134 xmlParseChunk(ctxt, chars, strlen(chars), 0);
1138 xmlParseChunk(ctxt, chars, 0, 1);
1143 throw DDXParseFailed(
"Error parsing DDX response: Could not read from input file.");
1180 ctxt = xmlCreateFileParserCtxt(document.c_str());
1184 (
"Could not initialize the parser with the file: '")
1185 + document +
string(
"'."));
1190 ctxt->validate =
false;
1192 xmlParseDocument(ctxt);
void set_dataset_name(const string &n)
virtual AttrTable & get_attr_table()
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 ...
static void ddx_fatal_error(void *parser, const char *msg,...)
static void ddx_ignoreable_whitespace(void *parser, const xmlChar *ch, int len)
static void ddx_get_characters(void *parser, const xmlChar *ch, int len)
static void ddx_start_document(void *parser)
void intern_stream(FILE *in, DDS *dds, string &cid, const string &boundary="")
Read the DDX from a stream instead of a file.
void intern(const string &document, DDS *dest_dds, string &cid)
static void ddx_end_document(void *parser)
static void ddx_get_cdata(void *parser, const xmlChar *value, int len)
static xmlEntityPtr ddx_get_entity(void *parser, const xmlChar *name)
A class for software fault reporting.
Holds a structure (aggregate) type.
top level DAP object to house generic methods
Type
Identifies the data type.
bool is_simple_type(Type t)
Returns true if the instance is a numeric, string or URL type variable.
ObjectType get_type(const string &value)
bool is_boundary(const char *line, const string &boundary)