57 static const not_used char *states[] =
63 "attribute_container",
66 "other_xml_attribute",
90 BaseType *DDXParser::factory(
Type t,
const string & name)
94 return d_factory->
NewByte(name);
122 return d_factory->
NewStr(name);
126 return d_factory->
NewUrl(name);
142 return d_factory->
NewGrid(name);
151 static Type get_type(
const char *name)
153 if (strcmp(name,
"Byte") == 0)
156 if (strcmp(name,
"Int16") == 0)
159 if (strcmp(name,
"UInt16") == 0)
162 if (strcmp(name,
"Int32") == 0)
165 if (strcmp(name,
"UInt32") == 0)
168 if (strcmp(name,
"Float32") == 0)
171 if (strcmp(name,
"Float64") == 0)
174 if (strcmp(name,
"String") == 0)
177 if (strcmp(name,
"Url") == 0)
180 if (strcmp(name,
"Array") == 0)
183 if (strcmp(name,
"Structure") == 0)
186 if (strcmp(name,
"Sequence") == 0)
189 if (strcmp(name,
"Grid") == 0)
195 static Type is_simple_type(
const char *name)
197 Type t = get_type(name);
214 static bool is_not(
const char *name,
const char *tag)
216 return strcmp(name, tag) != 0;
219 void DDXParser::set_state(DDXParser::ParseState state)
224 DDXParser::ParseState DDXParser::get_state()
const
229 void DDXParser::pop_state()
237 void DDXParser::transfer_xml_attrs(
const xmlChar **attributes,
int nb_attributes)
239 if (!attribute_table.empty())
240 attribute_table.clear();
242 unsigned int index = 0;
243 for (
int i = 0; i < nb_attributes; ++i, index += 5) {
246 attribute_table.insert(map<string, XMLAttribute>::value_type(
247 string((
const char *)attributes[index]),
248 XMLAttribute(attributes + index + 1)));
250 DBG(cerr <<
"Attribute '" << (
const char *)attributes[index] <<
"': "
251 << attribute_table[(
const char *)attributes[index]].value << endl);
255 void DDXParser::transfer_xml_ns(
const xmlChar **namespaces,
int nb_namespaces)
257 for (
int i = 0; i < nb_namespaces; ++i ) {
260 namespace_table.insert(map<string,string>::value_type(
261 namespaces[i*2] != 0 ? (
const char *)namespaces[i*2] :
"",
262 (
const char *)namespaces[i*2+1]));
270 bool DDXParser::check_required_attribute(
const string & attr)
272 map < string, XMLAttribute >::iterator i = attribute_table.find(attr);
273 if (i == attribute_table.end())
284 bool DDXParser::check_attribute(
const string & attr)
286 return (attribute_table.find(attr) != attribute_table.end());
297 void DDXParser::process_attribute_element(
const xmlChar **attrs,
int nb_attributes)
300 transfer_xml_attrs(attrs, nb_attributes);
302 bool error = !(check_required_attribute(
string(
"name"))
303 && check_required_attribute(
string(
"type")));
307 if (attribute_table[
"type"].value ==
"Container") {
308 set_state(inside_attribute_container);
311 AttrTable *parent = at_stack.top();
313 child = parent->append_container(attribute_table[
"name"].value);
314 at_stack.push(child);
315 DBG2(cerr <<
"Pushing at" << endl);
317 else if (attribute_table[
"type"].value ==
"OtherXML") {
318 set_state(inside_other_xml_attribute);
320 dods_attr_name = attribute_table[
"name"].value;
321 dods_attr_type = attribute_table[
"type"].value;
324 set_state(inside_attribute);
328 dods_attr_name = attribute_table[
"name"].value;
329 dods_attr_type = attribute_table[
"type"].value;
336 void DDXParser::process_attribute_alias(
const xmlChar **attrs,
int nb_attributes)
338 transfer_xml_attrs(attrs, nb_attributes);
339 if (check_required_attribute(
string(
"name"))
340 && check_required_attribute(
string(
"attribute"))) {
341 set_state(inside_alias);
342 at_stack.top()->attr_alias(attribute_table[
"name"].value,
343 attribute_table[
"attribute"].value);
354 void DDXParser::process_variable(
Type t, ParseState s,
const xmlChar **attrs,
357 transfer_xml_attrs(attrs, nb_attributes);
361 || check_required_attribute(
"name")) {
362 BaseType *btp = factory(t, attribute_table[
"name"].value);
366 "Internal parser error; could not instantiate the variable '%s'.",
367 attribute_table[
"name"].value.c_str());
374 at_stack.push(&btp->get_attr_table());
381 void DDXParser::process_dimension(
const xmlChar **attrs,
int nb_attributes)
383 transfer_xml_attrs(attrs, nb_attributes);
384 if (check_required_attribute(
string(
"size"))) {
385 set_state(inside_dimension);
386 Array *ap = dynamic_cast < Array * >(bt_stack.top());
392 ap->append_dim(atoi(attribute_table[
"size"].value.c_str()),
393 attribute_table[
"name"].value);
399 void DDXParser::process_blob(
const xmlChar **attrs,
int nb_attributes)
401 transfer_xml_attrs(attrs, nb_attributes);
402 if (check_required_attribute(
string(
"href"))) {
403 set_state(inside_blob_href);
404 *blob_href = attribute_table[
"href"].value;
415 DDXParser::is_attribute_or_alias(
const char *name,
const xmlChar **attrs,
418 if (strcmp(name,
"Attribute") == 0) {
419 process_attribute_element(attrs, nb_attributes);
423 else if (strcmp(name,
"Alias") == 0) {
424 process_attribute_alias(attrs, nb_attributes);
437 inline bool DDXParser::is_variable(
const char *name,
const xmlChar **attrs,
442 process_variable(t, inside_simple_type, attrs, nb_attributes);
445 else if (strcmp(name,
"Array") == 0) {
446 process_variable(
dods_array_c, inside_array, attrs, nb_attributes);
449 else if (strcmp(name,
"Structure") == 0) {
453 else if (strcmp(name,
"Sequence") == 0) {
454 process_variable(
dods_sequence_c, inside_sequence, attrs, nb_attributes);
457 else if (strcmp(name,
"Grid") == 0) {
458 process_variable(
dods_grid_c, inside_grid, attrs, nb_attributes);
465 void DDXParser::finish_variable(
const char *tag,
Type t,
const char *expected)
467 if (strcmp(tag, expected) != 0) {
469 "Expected an end tag for a %s; found '%s' instead.",
476 BaseType *btp = bt_stack.top();
481 if (btp->type() != t) {
483 "Internal error: Expected a %s variable.",
489 && dynamic_cast < Array * >(btp)->dimensions() == 0) {
491 "No dimension element included in the Array '%s'.",
492 btp->name().c_str());
496 BaseType *parent = bt_stack.top();
498 if (!(parent->is_vector_type() || parent->is_constructor_type())) {
500 "Tried to add the array variable '%s' to a non-constructor type (%s %s).",
502 bt_stack.top()->type_name().c_str(),
503 bt_stack.top()->name().c_str());
507 parent->add_var(btp);
524 parser->error_msg =
"";
525 parser->char_data =
"";
533 parser->bt_stack.push(
new Structure(
"dummy_dds"));
535 parser->set_state(parser_start);
537 DBG2(cerr <<
"Parser state: " << states[parser->get_state()] << endl);
545 DBG2(cerr <<
"Ending state == " << states[parser->get_state()] <<
548 if (parser->get_state() != parser_start)
550 "The document contained unbalanced tags.");
554 if (parser->get_state() == parser_error)
561 ddx_fatal_error(parser,
"Parse error: Expected a Structure, Sequence or Grid variable.");
570 parser->bt_stack.pop();
575 const xmlChar *l,
const xmlChar *prefix,
const xmlChar *URI,
576 int nb_namespaces,
const xmlChar **namespaces,
577 int nb_attributes,
int ,
const xmlChar **attributes)
580 const char *localname = (
const char *)l;
582 DBG2(cerr <<
"start element: " << localname <<
", states: "
583 << states[parser->get_state()]);
585 switch (parser->get_state()) {
587 if (strcmp(localname,
"Dataset") == 0) {
588 parser->set_state(inside_dataset);
589 parser->root_ns = URI != 0 ? (
const char *)URI:
"";
590 parser->transfer_xml_attrs(attributes, nb_attributes);
592 if (parser->check_required_attribute(
string(
"name")))
595 if (parser->check_attribute(
"dapVersion"))
596 parser->dds->
set_dap_version(parser->attribute_table[
"dapVersion"].value);
600 "Expected response to start with a Dataset element; found '%s' instead.",
605 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
607 else if (parser->is_variable(localname, attributes, nb_attributes))
609 else if (strcmp(localname,
"blob") == 0 || strcmp(localname,
"dataBLOB") == 0) {
610 parser->process_blob(attributes, nb_attributes);
615 "Expected an Attribute, Alias or variable element; found '%s' instead.",
619 case inside_attribute_container:
620 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
624 "Expected an Attribute or Alias element; found '%s' instead.",
628 case inside_attribute:
629 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
631 else if (strcmp(localname,
"value") == 0)
632 parser->set_state(inside_attribute_value);
635 "Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
639 case inside_attribute_value:
641 "Internal parser error; unexpected state, inside value while processing element '%s'.",
645 case inside_other_xml_attribute:
646 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname << endl);
648 parser->other_xml_depth++;
652 parser->other_xml.append(
"<");
654 parser->other_xml.append((
const char *)prefix);
655 parser->other_xml.append(
":");
657 parser->other_xml.append(localname);
659 if (nb_namespaces != 0) {
660 parser->transfer_xml_ns(namespaces, nb_namespaces);
662 for (map<string,string>::iterator i = parser->namespace_table.begin();
663 i != parser->namespace_table.end();
665 parser->other_xml.append(
" xmlns");
666 if (!i->first.empty()) {
667 parser->other_xml.append(
":");
668 parser->other_xml.append(i->first);
670 parser->other_xml.append(
"=\"");
671 parser->other_xml.append(i->second);
672 parser->other_xml.append(
"\"");
676 if (nb_attributes != 0) {
677 parser->transfer_xml_attrs(attributes, nb_attributes);
678 for (XMLAttrMap::iterator i = parser->attr_table_begin();
679 i != parser->attr_table_end();
681 parser->other_xml.append(
" ");
682 if (!i->second.prefix.empty()) {
683 parser->other_xml.append(i->second.prefix);
684 parser->other_xml.append(
":");
686 parser->other_xml.append(i->first);
687 parser->other_xml.append(
"=\"");
688 parser->other_xml.append(i->second.value);
689 parser->other_xml.append(
"\"");
693 parser->other_xml.append(
">");
698 "Internal parser error; unexpected state, inside alias while processing element '%s'.",
702 case inside_simple_type:
703 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
707 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
712 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
714 else if (is_not(localname,
"Array")
715 && parser->is_variable(localname, attributes, nb_attributes))
717 else if (strcmp(localname,
"dimension") == 0) {
718 parser->process_dimension(attributes, nb_attributes);
723 "Expected an 'Attribute' or 'Alias' element; found '%s' instead.",
727 case inside_dimension:
729 "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
733 case inside_structure:
734 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
736 else if (parser->is_variable(localname, attributes, nb_attributes))
740 "Expected an Attribute, Alias or variable element; found '%s' instead.",
744 case inside_sequence:
745 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
747 else if (parser->is_variable(localname, attributes, nb_attributes))
751 "Expected an Attribute, Alias or variable element; found '%s' instead.",
756 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
758 else if (strcmp(localname,
"Array") == 0)
759 parser->process_variable(
dods_array_c, inside_array, attributes, nb_attributes);
760 else if (strcmp(localname,
"Map") == 0)
761 parser->process_variable(
dods_array_c, inside_map, attributes, nb_attributes);
764 "Expected an Attribute, Alias or variable element; found '%s' instead.",
769 if (parser->is_attribute_or_alias(localname, attributes, nb_attributes))
771 else if (is_not(localname,
"Array") && is_not(localname,
"Sequence")
772 && is_not(localname,
"Grid")
773 && parser->is_variable(localname, attributes, nb_attributes))
775 else if (strcmp(localname,
"dimension") == 0) {
776 parser->process_dimension(attributes, nb_attributes);
781 "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
785 case inside_blob_href:
787 "Internal parser error; unexpected state, inside blob href while processing element '%s'.",
793 parser->set_state(parser_unknown);
800 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
804 const xmlChar *prefix,
const xmlChar *URI)
807 const char *localname = (
const char *)l;
809 DBG2(cerr <<
"End element " << localname <<
" (state "
810 << states[parser->get_state()] <<
")" << endl);
812 switch (parser->get_state()) {
815 "Internal parser error; unexpected state, inside start state while processing element '%s'.",
820 if (strcmp(localname,
"Dataset") == 0)
824 "Expected an end Dataset tag; found '%s' instead.",
828 case inside_attribute_container:
829 if (strcmp(localname,
"Attribute") == 0) {
831 parser->at_stack.pop();
835 "Expected an end Attribute tag; found '%s' instead.",
839 case inside_attribute:
840 if (strcmp(localname,
"Attribute") == 0)
844 "Expected an end Attribute tag; found '%s' instead.",
848 case inside_attribute_value:
849 if (strcmp(localname,
"value") == 0) {
853 parser->dods_attr_type, parser->char_data);
854 parser->char_data =
"";
858 "Expected an end value tag; found '%s' instead.",
863 case inside_other_xml_attribute: {
864 if (strcmp(localname,
"Attribute") == 0
865 && parser->root_ns == (
const char *)URI) {
867 DBGN(cerr << endl <<
"\t Popping the 'inside_other_xml_attribute' state"
874 parser->dods_attr_type, parser->other_xml);
876 parser->other_xml =
"";
879 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname
880 <<
", depth: " << parser->other_xml_depth << endl);
881 if (parser->other_xml_depth == 0)
883 "Expected an OtherXML attribute to end! Instead I found '%s'",
885 parser->other_xml_depth--;
887 parser->other_xml.append(
"</");
889 parser->other_xml.append((
const char *)prefix);
890 parser->other_xml.append(
":");
892 parser->other_xml.append(localname);
893 parser->other_xml.append(
">");
902 case inside_simple_type:
905 BaseType *btp = parser->bt_stack.top();
906 parser->bt_stack.pop();
907 parser->at_stack.pop();
909 BaseType *parent = parser->bt_stack.top();
915 "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).",
917 parser->bt_stack.top()->
919 parser->bt_stack.top()->name().
924 "Expected an end tag for a simple type; found '%s' instead.",
929 parser->finish_variable(localname,
dods_array_c,
"Array");
932 case inside_dimension:
933 if (strcmp(localname,
"dimension") == 0)
937 "Expected an end dimension tag; found '%s' instead.",
941 case inside_structure:
945 case inside_sequence:
950 parser->finish_variable(localname,
dods_grid_c,
"Grid");
954 parser->finish_variable(localname,
dods_array_c,
"Map");
957 case inside_blob_href:
958 if (strcmp(localname,
"blob") == 0 || strcmp(localname,
"dataBLOB") == 0)
962 "Expected an end dataBLOB/blob tag; found '%s' instead.",
975 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
985 switch (parser->get_state()) {
986 case inside_attribute_value:
987 parser->char_data.append((
const char *)(ch), len);
988 DBG2(cerr <<
"Characters: '" << parser->char_data <<
"'" << endl);
991 case inside_other_xml_attribute:
992 parser->other_xml.append((
const char *)(ch), len);
993 DBG2(cerr <<
"Other XML Characters: '" << parser->other_xml <<
"'" << endl);
1010 switch (parser->get_state()) {
1011 case inside_other_xml_attribute:
1012 parser->other_xml.append((
const char *)(ch), len);
1029 switch (parser->get_state()) {
1030 case inside_other_xml_attribute:
1031 parser->other_xml.append((
const char *)(value), len);
1034 case parser_unknown:
1039 "Found a CData block but none are allowed by DAP.");
1051 return xmlGetPredefinedEntity(name);
1066 parser->set_state(parser_error);
1068 va_start(args, msg);
1070 vsnprintf(str, 1024, msg, args);
1073 int line = xmlSAX2GetLineNumber(parser->ctxt);
1076 parser->error_msg += string(str) + string(
"\n");
1081 void DDXParser::cleanup_parse(xmlParserCtxtPtr & context)
const
1083 if (!context->wellFormed) {
1084 context->sax = NULL;
1085 xmlFreeParserCtxt(context);
1088 (
"\nThe DDX is not a well formed XML document.\n")
1092 if (!context->valid) {
1093 context->sax = NULL;
1094 xmlFreeParserCtxt(context);
1095 throw DDXParseFailed(
string(
"\nThe DDX is not a valid document.\n")
1099 if (get_state() == parser_error) {
1100 context->sax = NULL;
1101 xmlFreeParserCtxt(context);
1102 throw DDXParseFailed(
string(
"\nError parsing DDX response.\n") +
1106 context->sax = NULL;
1107 xmlFreeParserCtxt(context);
1113 const string &boundary)
1117 if (!in || feof(in) || ferror(in))
1119 "Input stream not open or read error");
1121 const int size = 1024;
1124 int res = fread(chars, 1, 4, in);
1127 xmlParserCtxtPtr context =
1128 xmlCreatePushParserCtxt(NULL, NULL, chars, res,
"stream");
1134 xmlSAXHandler ddx_sax_parser;
1135 memset( &ddx_sax_parser, 0,
sizeof(xmlSAXHandler) );
1146 ddx_sax_parser.initialized = XML_SAX2_MAGIC;
1150 context->sax = &ddx_sax_parser;
1151 context->userData =
this;
1152 context->validate =
true;
1155 while ((fgets(chars, size, in) > 0) && !
is_boundary(chars, boundary)) {
1156 chars[size-1] =
'\0';
1157 DBG(cerr <<
"line: " << chars << endl);
1158 xmlParseChunk(ctxt, chars, strlen(chars), 0);
1162 xmlParseChunk(ctxt, chars, 0, 1);
1164 cleanup_parse(context);
1189 xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str());
1193 (
"Could not initialize the parser with the file: '")
1194 + document +
string(
"'."));
1200 xmlSAXHandler ddx_sax_parser;
1201 memset( &ddx_sax_parser, 0,
sizeof(xmlSAXHandler) );
1212 ddx_sax_parser.initialized = XML_SAX2_MAGIC;
1216 context->sax = &ddx_sax_parser;
1217 context->userData =
this;
1218 context->validate =
false;
1220 xmlParseDocument(context);
1222 cleanup_parse(context);