58#if defined(DODS_DEBUG) || defined(DODS_DEUG2)
59static const char *states[] = {
"start",
63 "attribute_container",
66 "other_xml_attribute",
89BaseType *DDXParser::factory(
Type t,
const string &name) {
92 return d_factory->NewByte(name);
95 return d_factory->NewInt16(name);
98 return d_factory->NewUInt16(name);
101 return d_factory->NewInt32(name);
104 return d_factory->NewUInt32(name);
107 return d_factory->NewFloat32(name);
110 return d_factory->NewFloat64(name);
113 return d_factory->NewStr(name);
116 return d_factory->NewUrl(name);
119 return d_factory->NewArray(name);
122 return d_factory->NewStructure(name);
125 return d_factory->NewSequence(name);
128 return d_factory->NewGrid(name);
135static bool is_not(
const char *name,
const char *tag) {
return strcmp(name, tag) != 0; }
137void DDXParser::set_state(DDXParser::ParseState state) { s.push(state); }
139DDXParser::ParseState DDXParser::get_state()
const {
return s.top(); }
141void DDXParser::pop_state() { s.pop(); }
146void DDXParser::transfer_xml_attrs(
const xmlChar **attributes,
int nb_attributes) {
147 if (!attribute_table.empty())
148 attribute_table.clear();
150 unsigned int index = 0;
151 for (
int i = 0; i < nb_attributes; ++i, index += 5) {
154 attribute_table.insert(map<string, XMLAttribute>::value_type(
string((
const char *)attributes[index]),
155 XMLAttribute(attributes + index + 1)));
157 DBG(cerr <<
"Attribute '" << (
const char *)attributes[index]
158 <<
"': " << attribute_table[(
const char *)attributes[index]].value << endl);
162void DDXParser::transfer_xml_ns(
const xmlChar **namespaces,
int nb_namespaces) {
163 for (
int i = 0; i < nb_namespaces; ++i) {
166 namespace_table.insert(map<string, string>::value_type(
167 namespaces[i * 2] != 0 ? (
const char *)namespaces[i * 2] :
"", (
const char *)namespaces[i * 2 + 1]));
175bool DDXParser::check_required_attribute(
const string &attr) {
176 map<string, XMLAttribute>::iterator i = attribute_table.find(attr);
177 if (i == attribute_table.end())
178 ddx_fatal_error(
this,
"Required attribute '%s' not found.", attr.c_str());
187bool DDXParser::check_attribute(
const string &attr) {
return (attribute_table.find(attr) != attribute_table.end()); }
197void DDXParser::process_attribute_element(
const xmlChar **attrs,
int nb_attributes) {
199 transfer_xml_attrs(attrs, nb_attributes);
201 bool error = !(check_required_attribute(
string(
"name")) && check_required_attribute(
string(
"type")));
205 if (attribute_table[
"type"].value ==
"Container") {
206 set_state(inside_attribute_container);
209 AttrTable *parent = at_stack.top();
211 child = parent->append_container(attribute_table[
"name"].value);
212 at_stack.push(child);
213 DBG2(cerr <<
"Pushing at" << endl);
214 }
else if (attribute_table[
"type"].value ==
"OtherXML") {
215 set_state(inside_other_xml_attribute);
217 dods_attr_name = attribute_table[
"name"].value;
218 dods_attr_type = attribute_table[
"type"].value;
220 set_state(inside_attribute);
224 dods_attr_name = attribute_table[
"name"].value;
225 dods_attr_type = attribute_table[
"type"].value;
232void DDXParser::process_attribute_alias(
const xmlChar **attrs,
int nb_attributes) {
233 transfer_xml_attrs(attrs, nb_attributes);
234 if (check_required_attribute(
string(
"name")) && check_required_attribute(
string(
"attribute"))) {
235 set_state(inside_alias);
236 at_stack.top()->attr_alias(attribute_table[
"name"].value, attribute_table[
"attribute"].value);
247void DDXParser::process_variable(
Type t, ParseState s,
const xmlChar **attrs,
int nb_attributes) {
248 transfer_xml_attrs(attrs, nb_attributes);
252 if (bt_stack.top()->type() ==
dods_array_c || check_required_attribute(
"name")) {
253 BaseType *btp = factory(t, attribute_table[
"name"].value);
255 ddx_fatal_error(
this,
"Internal parser error; could not instantiate the variable '%s'.",
256 attribute_table[
"name"].value.c_str());
264 at_stack.push(&btp->get_attr_table());
272void DDXParser::process_dimension(
const xmlChar **attrs,
int nb_attributes) {
273 transfer_xml_attrs(attrs, nb_attributes);
274 if (check_required_attribute(
string(
"size"))) {
275 set_state(inside_dimension);
276 Array *ap =
dynamic_cast<Array *
>(bt_stack.top());
282 ap->append_dim(atoi(attribute_table[
"size"].value.c_str()), attribute_table[
"name"].value);
288void DDXParser::process_blob(
const xmlChar **attrs,
int nb_attributes) {
289 transfer_xml_attrs(attrs, nb_attributes);
290 if (check_required_attribute(
string(
"href"))) {
291 set_state(inside_blob_href);
292 *blob_href = attribute_table[
"href"].value;
302inline bool DDXParser::is_attribute_or_alias(
const char *name,
const xmlChar **attrs,
int nb_attributes) {
303 if (strcmp(name,
"Attribute") == 0) {
304 process_attribute_element(attrs, nb_attributes);
307 }
else if (strcmp(name,
"Alias") == 0) {
308 process_attribute_alias(attrs, nb_attributes);
321inline bool DDXParser::is_variable(
const char *name,
const xmlChar **attrs,
int nb_attributes) {
325 process_variable(t, inside_simple_type, attrs, nb_attributes);
327 }
else if (strcmp(name,
"Array") == 0) {
328 process_variable(
dods_array_c, inside_array, attrs, nb_attributes);
330 }
else if (strcmp(name,
"Structure") == 0) {
333 }
else if (strcmp(name,
"Sequence") == 0) {
334 process_variable(
dods_sequence_c, inside_sequence, attrs, nb_attributes);
336 }
else if (strcmp(name,
"Grid") == 0) {
337 process_variable(
dods_grid_c, inside_grid, attrs, nb_attributes);
344void DDXParser::finish_variable(
const char *tag,
Type t,
const char *expected) {
345 if (strcmp(tag, expected) != 0) {
352 BaseType *btp = bt_stack.top();
357 if (btp->type() != t) {
363 if (t ==
dods_array_c &&
static_cast<Array *
>(btp)->dimensions() == 0) {
369 BaseType *parent = bt_stack.top();
371 if (!(parent->is_vector_type() || parent->is_constructor_type())) {
373 bt_stack.top()->type_name().c_str(), bt_stack.top()->name().c_str());
378 parent->add_var_nocopy(btp);
393 DDXParser *parser =
static_cast<DDXParser *
>(p);
394 parser->error_msg =
"";
395 parser->char_data =
"";
403 parser->bt_stack.push(
new Structure(
"dummy_dds"));
405 parser->set_state(parser_start);
407 DBG2(cerr <<
"Parser state: " << states[parser->get_state()] << endl);
413 DDXParser *parser =
static_cast<DDXParser *
>(p);
414 DBG2(cerr <<
"Ending state == " << states[parser->get_state()] << endl);
416 if (parser->get_state() != parser_start)
421 if (parser->get_state() == parser_error) {
429 delete parser->bt_stack.top();
430 parser->bt_stack.pop();
431 ddx_fatal_error(parser,
"Parse error: Expected a Structure, Sequence or Grid variable.");
440 delete parser->bt_stack.top();
441 parser->bt_stack.pop();
445 int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
446 int ,
const xmlChar **attributes) {
447 DDXParser *parser =
static_cast<DDXParser *
>(p);
448 const char *localname = (
const char *)l;
450 DBG2(cerr <<
"start element: " << localname <<
", states: " << states[parser->get_state()]);
452 switch (parser->get_state()) {
454 if (strcmp(localname,
"Dataset") == 0) {
455 parser->set_state(inside_dataset);
456 parser->root_ns = URI != 0 ? (
const char *)URI :
"";
457 parser->transfer_xml_attrs(attributes, nb_attributes);
459 if (parser->check_required_attribute(
string(
"name")))
462 if (parser->check_attribute(
"dapVersion"))
463 parser->dds->
set_dap_version(parser->attribute_table[
"dapVersion"].value);
470 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
472 else if (parser->is_variable(localname, attributes, nb_attributes))
474 else if (strcmp(localname,
"blob") == 0 || strcmp(localname,
"dataBLOB") == 0) {
475 parser->process_blob(attributes, nb_attributes);
482 case inside_attribute_container:
483 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
490 case inside_attribute:
491 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
493 else if (strcmp(localname,
"value") == 0)
494 parser->set_state(inside_attribute_value);
496 ddx_fatal_error(parser,
"Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
500 case inside_attribute_value:
501 ddx_fatal_error(parser,
"Internal parser error; unexpected state, inside value while processing element '%s'.",
505 case inside_other_xml_attribute:
506 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname << endl);
508 parser->other_xml_depth++;
512 parser->other_xml.append(
"<");
514 parser->other_xml.append((
const char *)prefix);
515 parser->other_xml.append(
":");
517 parser->other_xml.append(localname);
519 if (nb_namespaces != 0) {
520 parser->transfer_xml_ns(namespaces, nb_namespaces);
522 for (map<string, string>::iterator i = parser->namespace_table.begin(); i != parser->namespace_table.end();
524 parser->other_xml.append(
" xmlns");
525 if (!i->first.empty()) {
526 parser->other_xml.append(
":");
527 parser->other_xml.append(i->first);
529 parser->other_xml.append(
"=\"");
530 parser->other_xml.append(i->second);
531 parser->other_xml.append(
"\"");
535 if (nb_attributes != 0) {
536 parser->transfer_xml_attrs(attributes, nb_attributes);
537 for (XMLAttrMap::iterator i = parser->attr_table_begin(); i != parser->attr_table_end(); ++i) {
538 parser->other_xml.append(
" ");
539 if (!i->second.prefix.empty()) {
540 parser->other_xml.append(i->second.prefix);
541 parser->other_xml.append(
":");
543 parser->other_xml.append(i->first);
544 parser->other_xml.append(
"=\"");
545 parser->other_xml.append(i->second.value);
546 parser->other_xml.append(
"\"");
550 parser->other_xml.append(
">");
554 ddx_fatal_error(parser,
"Internal parser error; unexpected state, inside alias while processing element '%s'.",
558 case inside_simple_type:
559 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
562 ddx_fatal_error(parser,
"Expected an 'Attribute' or 'Alias' element; found '%s' instead.", localname);
566 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
568 else if (is_not(localname,
"Array") && parser->is_variable(localname, attributes, nb_attributes))
570 else if (strcmp(localname,
"dimension") == 0) {
571 parser->process_dimension(attributes, nb_attributes);
574 ddx_fatal_error(parser,
"Expected an 'Attribute' or 'Alias' element; found '%s' instead.", localname);
577 case inside_dimension:
579 "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
583 case inside_structure:
584 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
586 else if (parser->is_variable(localname, attributes, nb_attributes))
593 case inside_sequence:
594 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
596 else if (parser->is_variable(localname, attributes, nb_attributes))
604 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
606 else if (strcmp(localname,
"Array") == 0)
607 parser->process_variable(
dods_array_c, inside_array, attributes, nb_attributes);
608 else if (strcmp(localname,
"Map") == 0)
609 parser->process_variable(
dods_array_c, inside_map, attributes, nb_attributes);
616 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
618 else if (is_not(localname,
"Array") && is_not(localname,
"Sequence") && is_not(localname,
"Grid") &&
619 parser->is_variable(localname, attributes, nb_attributes))
621 else if (strcmp(localname,
"dimension") == 0) {
622 parser->process_dimension(attributes, nb_attributes);
626 "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
630 case inside_blob_href:
632 "Internal parser error; unexpected state, inside blob href while processing element '%s'.",
638 parser->set_state(parser_unknown);
645 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
649 DDXParser *parser =
static_cast<DDXParser *
>(p);
650 const char *localname = (
const char *)l;
652 DBG2(cerr <<
"End element " << localname <<
" (state " << states[parser->get_state()] <<
")" << endl);
654 switch (parser->get_state()) {
657 "Internal parser error; unexpected state, inside start state while processing element '%s'.",
662 if (strcmp(localname,
"Dataset") == 0)
668 case inside_attribute_container:
669 if (strcmp(localname,
"Attribute") == 0) {
671 parser->at_stack.pop();
676 case inside_attribute:
677 if (strcmp(localname,
"Attribute") == 0)
683 case inside_attribute_value:
684 if (strcmp(localname,
"value") == 0) {
687 atp->
append_attr(parser->dods_attr_name, parser->dods_attr_type, parser->char_data);
688 parser->char_data =
"";
694 case inside_other_xml_attribute: {
695 if (strcmp(localname,
"Attribute") == 0 && parser->root_ns == (
const char *)URI) {
697 DBGN(cerr << endl <<
"\t Popping the 'inside_other_xml_attribute' state" << endl);
702 atp->
append_attr(parser->dods_attr_name, parser->dods_attr_type, parser->other_xml);
704 parser->other_xml =
"";
707 <<
"\t inside_other_xml_attribute: " << localname <<
", depth: " << parser->other_xml_depth
709 if (parser->other_xml_depth == 0)
712 parser->other_xml_depth--;
714 parser->other_xml.append(
"</");
716 parser->other_xml.append((
const char *)prefix);
717 parser->other_xml.append(
":");
719 parser->other_xml.append(localname);
720 parser->other_xml.append(
">");
729 case inside_simple_type: {
733 BaseType *btp = parser->bt_stack.top();
734 parser->bt_stack.pop();
735 parser->at_stack.pop();
737 BaseType *parent = parser->bt_stack.top();
744 parser,
"Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).", localname,
745 parser->bt_stack.top()->type_name().c_str(), parser->bt_stack.top()->name().c_str());
755 parser->finish_variable(localname,
dods_array_c,
"Array");
758 case inside_dimension:
759 if (strcmp(localname,
"dimension") == 0)
765 case inside_structure:
769 case inside_sequence:
774 parser->finish_variable(localname,
dods_grid_c,
"Grid");
778 parser->finish_variable(localname,
dods_array_c,
"Map");
781 case inside_blob_href:
782 if (strcmp(localname,
"blob") == 0 || strcmp(localname,
"dataBLOB") == 0)
796 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
803 DDXParser *parser =
static_cast<DDXParser *
>(p);
805 switch (parser->get_state()) {
806 case inside_attribute_value:
807 parser->char_data.append((
const char *)(ch), len);
808 DBG2(cerr <<
"Characters: '" << parser->char_data <<
"'" << endl);
811 case inside_other_xml_attribute:
812 parser->other_xml.append((
const char *)(ch), len);
813 DBG2(cerr <<
"Other XML Characters: '" << parser->other_xml <<
"'" << endl);
826 DDXParser *parser =
static_cast<DDXParser *
>(p);
828 switch (parser->get_state()) {
829 case inside_other_xml_attribute:
830 parser->other_xml.append((
const char *)(ch), len);
844 DDXParser *parser =
static_cast<DDXParser *
>(p);
846 switch (parser->get_state()) {
847 case inside_other_xml_attribute:
848 parser->other_xml.append((
const char *)(value), len);
876 DDXParser *parser =
static_cast<DDXParser *
>(p);
878 parser->set_state(parser_error);
882 vsnprintf(str, 1024, msg, args);
885 int line = xmlSAX2GetLineNumber(parser->ctxt);
888 parser->error_msg += string(str) + string(
"\n");
893void DDXParser::cleanup_parse() {
894 bool wellFormed = ctxt->wellFormed;
895 bool valid = ctxt->valid;
897 xmlFreeParserCtxt(ctxt);
901 while (!bt_stack.empty()) {
902 delete bt_stack.top();
907 throw DDXParseFailed(
string(
"The DDX is not a well formed XML document.\n") + error_msg);
911 throw DDXParseFailed(
string(
"The DDX is not a valid document.\n") + error_msg);
914 if (get_state() == parser_error) {
915 throw DDXParseFailed(
string(
"Error parsing DDX response.\n") + error_msg);
929 throw InternalErr(__FILE__, __LINE__,
"Input stream not open or read error");
931 const int size = 1024;
932 char chars[size + 1];
936 int res = in.gcount();
939 ctxt = xmlCreatePushParserCtxt(&ddx_sax_parser,
this, chars, res,
"stream");
942 throw DDXParseFailed(
"Error parsing DDX response: Input does not look like XML");
947 ctxt->validate =
true;
949 in.getline(chars, size);
951 chars[res - 1] =
'\n';
954 DBG(cerr <<
"line (" << res <<
"): " << chars << endl);
955 xmlParseChunk(ctxt, chars, res, 0);
957 in.getline(chars, size);
960 chars[res - 1] =
'\n';
967 xmlParseChunk(ctxt, chars, 0, 1);
971 throw DDXParseFailed(
"Error parsing DDX response: Could not read from input stream.");
979 if (!in || feof(in) || ferror(in))
980 throw InternalErr(__FILE__, __LINE__,
"Input stream not open or read error");
982 const int size = 1024;
985 int res = fread(chars, 1, 4, in);
988 ctxt = xmlCreatePushParserCtxt(&ddx_sax_parser,
this, chars, res,
"stream");
991 throw DDXParseFailed(
"Error parsing DDX response: Input does not look like XML");
996 ctxt->validate =
true;
998 while ((fgets(chars, size, in) != 0) && !
is_boundary(chars, boundary)) {
999 DBG(cerr <<
"line (" << strlen(chars) <<
"): " << chars << endl);
1000 xmlParseChunk(ctxt, chars, strlen(chars), 0);
1004 xmlParseChunk(ctxt, chars, 0, 1);
1008 throw DDXParseFailed(
"Error parsing DDX response: Could not read from input file.");
1043 ctxt = xmlCreateFileParserCtxt(document.c_str());
1047 (
"Could not initialize the parser with the file: '")
1048 + document +
string(
"'."));
1053 ctxt->validate =
false;
1055 xmlParseDocument(ctxt);
Contains the attributes for a dataset.
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
The basic data type for the DODS DAP types.
virtual bool is_vector_type() const
Returns true if the instance is a vector (i.e., array) type variable.
virtual bool is_constructor_type() const
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable.
virtual void add_var(BaseType *bt, Part part=nil)
Add a variable.
std::vector< BaseType * >::iterator Vars_iter
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_sax2_start_element(void *parser, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes)
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.
static void ddx_sax2_end_element(void *parser, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI)
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.
string long_to_string(long val, int base)
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)