69 static const not_used char *states[] = {
76 "inside_attribute_container",
78 "inside_attribute_value",
79 "inside_other_xml_attribute",
102 BaseType *D4ParserSax2::factory(
Type t,
const string & name)
106 return d_factory->
NewByte(name);
110 return d_factory->
NewInt8(name);
128 return d_factory->
NewStr(name);
130 return d_factory->
NewUrl(name);
132 return d_factory->
NewURL(name);
140 return d_factory->
NewGrid(name);
148 static bool is_valid_enum_value(
const Type &t,
long long value)
155 return (value >= 0 && static_cast<unsigned long long>(value) <=
DODS_UCHAR_MAX);
159 return (value >= 0 && static_cast<unsigned long long>(value) <=
DODS_USHRT_MAX);
163 return (value >= 0 && static_cast<unsigned long long>(value) <=
DODS_UINT_MAX);
167 return (value >= 0 && static_cast<unsigned long long>(value) <=
DODS_ULLONG_MAX);
173 static bool is_not(
const char *name,
const char *tag)
175 return strcmp(name, tag) != 0;
178 void D4ParserSax2::set_state(D4ParserSax2::ParseState state)
183 D4ParserSax2::ParseState D4ParserSax2::get_state()
const
188 void D4ParserSax2::pop_state()
197 void D4ParserSax2::transfer_xml_attrs(
const xmlChar **attributes,
int nb_attributes)
199 if (!xml_attrs.empty())
202 unsigned int index = 0;
203 for (
int i = 0; i < nb_attributes; ++i, index += 5) {
206 xml_attrs.insert(map<string, XMLAttribute>::value_type(
string((
const char *) attributes[index]),
207 XMLAttribute(attributes + index + 1)));
209 DBG(cerr <<
"Attribute '" << (
const char *)attributes[index] <<
"': "
210 << xml_attrs[(
const char *)attributes[index]].value << endl);
214 void D4ParserSax2::transfer_xml_ns(
const xmlChar **namespaces,
int nb_namespaces)
216 for (
int i = 0; i < nb_namespaces; ++i) {
219 namespace_table.insert(
220 map<string, string>::value_type(namespaces[i * 2] != 0 ? (
const char *) namespaces[i * 2] :
"",
221 (
const char *) namespaces[i * 2 + 1]));
229 bool D4ParserSax2::check_required_attribute(
const string & attr)
231 map<string, XMLAttribute>::iterator i = xml_attrs.find(attr);
232 if (i == xml_attrs.end())
233 ddx_fatal_error(
this,
"Required attribute '%s' not found.", attr.c_str());
242 bool D4ParserSax2::check_attribute(
const string & attr)
244 return (xml_attrs.find(attr) != xml_attrs.end());
255 void D4ParserSax2::process_attribute_helper(
const xmlChar **attrs,
int nb_attributes)
258 transfer_xml_attrs(attrs, nb_attributes);
260 bool error = !(check_required_attribute(
string(
"name")) && check_required_attribute(
string(
"type")));
264 if (xml_attrs[
"type"].value ==
"Container") {
265 set_state(inside_attribute_container);
268 AttrTable *parent = at_stack.top();
270 child = parent->append_container(xml_attrs[
"name"].value);
271 at_stack.push(child);
272 DBG2(cerr <<
"Pushing at" << endl);
274 else if (xml_attrs[
"type"].value ==
"OtherXML") {
275 set_state(inside_other_xml_attribute);
277 dods_attr_name = xml_attrs[
"name"].value;
278 dods_attr_type = xml_attrs[
"type"].value;
281 set_state(inside_attribute);
283 dods_attr_name = xml_attrs[
"name"].value;
284 dods_attr_type = xml_attrs[
"type"].value;
292 void D4ParserSax2::process_enum_def_helper(
const xmlChar **attrs,
int nb_attributes)
295 transfer_xml_attrs(attrs, nb_attributes);
297 bool error = !(check_required_attribute(
string(
"name"))
298 && check_required_attribute(
string(
"basetype")));
304 ddx_fatal_error(
this,
"Error: The Enumeration '%s' must have an integer type, instead the type '%s' was used.",
305 xml_attrs[
"name"].value.c_str(), xml_attrs[
"basetype"].value.c_str());
310 d_enum_def =
new D4EnumDef(xml_attrs[
"name"].value, t);
312 set_state(inside_enum_def);
319 void D4ParserSax2::process_enum_const_helper(
const xmlChar **attrs,
int nb_attributes)
322 transfer_xml_attrs(attrs, nb_attributes);
324 bool error = !(check_required_attribute(
string(
"name"))
325 && check_required_attribute(
string(
"value")));
329 istringstream iss(xml_attrs[
"value"].value);
331 iss >> skipws >> value;
332 if (iss.fail() || iss.bad()) {
333 ddx_fatal_error(
this,
"Error: Expected an integer value for an Enumeration constant, got '%s' instead.",
334 xml_attrs[
"value"].value.c_str());
336 else if (!is_valid_enum_value(d_enum_def->get_type(), value))
337 ddx_fatal_error(
this,
"Error: In an Enumeration constant, the value '%s' cannot fit in a variable of type '%s'.",
338 xml_attrs[
"value"].value.c_str(),
type_name(d_enum_def->get_type()).c_str());
341 d_enum_def->add_value(xml_attrs[
"name"].value, value);
344 set_state(inside_enum_const);
350 void D4ParserSax2::process_dimension(
const xmlChar **attrs,
int nb_attributes)
352 transfer_xml_attrs(attrs, nb_attributes);
353 if (check_required_attribute(
string(
"size"))) {
354 set_state(inside_dimension);
355 Array *ap =
dynamic_cast<Array *
>(bt_stack.top());
361 ap->append_dim(atoi(xml_attrs[
"size"].value.c_str()), xml_attrs[
"name"].value);
371 inline bool D4ParserSax2::process_attribute(
const char *name,
const xmlChar **attrs,
int nb_attributes)
373 if (strcmp(name,
"Attribute") == 0) {
374 process_attribute_helper(attrs, nb_attributes);
387 inline bool D4ParserSax2::process_enum_def(
const char *name,
const xmlChar **attrs,
int nb_attributes)
389 if (strcmp(name,
"Enumeration") == 0) {
390 process_enum_def_helper(attrs, nb_attributes);
398 inline bool D4ParserSax2::process_enum_const(
const char *name,
const xmlChar **attrs,
int nb_attributes)
400 if (strcmp(name,
"EnumConst") == 0) {
401 process_enum_const_helper(attrs, nb_attributes);
414 inline bool D4ParserSax2::process_variable(
const char *name,
const xmlChar **attrs,
int nb_attributes)
418 process_variable_helper(t, inside_simple_type, attrs, nb_attributes);
421 else if (strcmp(name,
"Structure") == 0) {
422 process_variable_helper(
dods_structure_c, inside_constructor, attrs, nb_attributes);
425 else if (strcmp(name,
"Sequence") == 0) {
426 process_variable_helper(
dods_sequence_c, inside_sequence, attrs, nb_attributes);
440 void D4ParserSax2::process_variable_helper(
Type t, ParseState s,
const xmlChar **attrs,
int nb_attributes)
442 transfer_xml_attrs(attrs, nb_attributes);
448 if (check_required_attribute(
"name")) {
449 BaseType *btp = factory(t, xml_attrs[
"name"].value);
451 ddx_fatal_error(
this,
"Internal parser error; could not instantiate the variable '%s'.",
452 xml_attrs[
"name"].value.c_str());
459 at_stack.push(&btp->get_attr_table());
463 void D4ParserSax2::finish_variable(
const char *tag,
Type t,
const char *expected)
465 if (strcmp(tag, expected) != 0) {
472 BaseType *btp = bt_stack.top();
477 if (btp->type() != t) {
482 if (t ==
dods_array_c && dynamic_cast<Array *>(btp)->dimensions() == 0) {
487 BaseType *parent = bt_stack.top();
489 if (!(parent->is_vector_type() || parent->is_constructor_type())) {
491 tag, bt_stack.top()->type_name().c_str(), bt_stack.top()->name().c_str());
495 parent->add_var(btp);
511 parser->error_msg =
"";
512 parser->char_data =
"";
514 parser->set_state(parser_start);
516 DBG2(cerr <<
"Parser state: " << states[parser->get_state()] << endl);
525 DBG2(cerr <<
"Ending state == " << states[parser->get_state()] << endl);
527 if (parser->get_state() != parser_start)
532 if (parser->get_state() == parser_error)
539 parser->bt_stack.pop();
543 int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int ,
544 const xmlChar **attributes)
547 const char *localname = (
const char *) l;
549 DBG2(cerr <<
"start element: " << localname <<
", state: " << states[parser->get_state()] << endl);
551 switch (parser->get_state()) {
553 if (strcmp(localname,
"Group") == 0) {
555 parser->set_state(inside_group);
557 parser->root_ns = URI ? (
const char *) URI :
"";
558 parser->transfer_xml_attrs(attributes, nb_attributes);
561 if (parser->check_required_attribute(
string(
"name")))
564 if (parser->check_attribute(
"dapVersion"))
569 if (parser->check_attribute(
"dmrVersion"))
572 if (parser->check_attribute(
"base"))
575 if (!parser->root_ns.empty())
580 parser->bt_stack.push(btp);
585 "Expected DMR to start with a Group element; found '%s' instead.", localname);
592 if (parser->process_attribute(localname, attributes, nb_attributes))
594 else if (parser->process_variable(localname, attributes, nb_attributes))
596 else if (parser->process_enum_def(localname, attributes, nb_attributes))
600 "Expected an Attribute, or variable element; found '%s' instead.", localname);
603 case inside_attribute_container:
604 if (parser->process_attribute(localname, attributes, nb_attributes))
611 case inside_attribute:
612 if (parser->process_attribute(localname, attributes, nb_attributes))
614 else if (strcmp(localname,
"value") == 0)
615 parser->set_state(inside_attribute_value);
617 ddx_fatal_error(parser,
"Expected an 'Attribute', 'Alias' or 'value' element; found '%s' instead.",
621 case inside_attribute_value:
625 case inside_other_xml_attribute:
626 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname << endl);
628 parser->other_xml_depth++;
632 parser->other_xml.append(
"<");
634 parser->other_xml.append((
const char *) prefix);
635 parser->other_xml.append(
":");
637 parser->other_xml.append(localname);
639 if (nb_namespaces != 0) {
640 parser->transfer_xml_ns(namespaces, nb_namespaces);
642 for (map<string, string>::iterator i = parser->namespace_table.begin();
643 i != parser->namespace_table.end(); ++i) {
644 parser->other_xml.append(
" xmlns");
645 if (!i->first.empty()) {
646 parser->other_xml.append(
":");
647 parser->other_xml.append(i->first);
649 parser->other_xml.append(
"=\"");
650 parser->other_xml.append(i->second);
651 parser->other_xml.append(
"\"");
655 if (nb_attributes != 0) {
656 parser->transfer_xml_attrs(attributes, nb_attributes);
657 for (XMLAttrMap::iterator i = parser->xml_attr_begin(); i != parser->xml_attr_end(); ++i) {
658 parser->other_xml.append(
" ");
659 if (!i->second.prefix.empty()) {
660 parser->other_xml.append(i->second.prefix);
661 parser->other_xml.append(
":");
663 parser->other_xml.append(i->first);
664 parser->other_xml.append(
"=\"");
665 parser->other_xml.append(i->second.value);
666 parser->other_xml.append(
"\"");
670 parser->other_xml.append(
">");
673 case inside_enum_def:
675 if (parser->process_enum_const(localname, attributes, nb_attributes))
678 ddx_fatal_error(parser,
"Expected an 'EnumConst' element; found '%s' instead.", localname);
681 case inside_enum_const:
685 case inside_simple_type:
686 if (parser->process_attribute(localname, attributes, nb_attributes))
689 ddx_fatal_error(parser,
"Expected an 'Attribute' or 'Alias' element; found '%s' instead.", localname);
693 if (parser->process_attribute(localname, attributes, nb_attributes))
695 else if (is_not(localname,
"Array") && parser->process_variable(localname, attributes, nb_attributes))
697 else if (strcmp(localname,
"dimension") == 0) {
698 parser->process_dimension(attributes, nb_attributes);
702 ddx_fatal_error(parser,
"Expected an 'Attribute' or 'Alias' element; found '%s' instead.", localname);
705 case inside_dimension:
707 "Internal parser error; unexpected state, inside dimension while processing element '%s'.",
711 case inside_constructor:
712 if (parser->process_attribute(localname, attributes, nb_attributes))
714 else if (parser->process_variable(localname, attributes, nb_attributes))
718 "Expected an Attribute, Alias or variable element; found '%s' instead.", localname);
721 case inside_sequence:
722 if (parser->process_attribute(localname, attributes, nb_attributes))
724 else if (parser->process_variable(localname, attributes, nb_attributes))
728 "Expected an Attribute, Alias or variable element; found '%s' instead.", localname);
732 if (parser->process_attribute(localname, attributes, nb_attributes))
734 else if (strcmp(localname,
"Array") == 0)
735 parser->process_variable_helper(
dods_array_c, inside_array, attributes, nb_attributes);
736 else if (strcmp(localname,
"Map") == 0)
737 parser->process_variable_helper(
dods_array_c, inside_map, attributes, nb_attributes);
740 "Expected an Attribute, Alias or variable element; found '%s' instead.", localname);
744 if (parser->process_attribute(localname, attributes, nb_attributes))
746 else if (is_not(localname,
"Array") && is_not(localname,
"Sequence") && is_not(localname,
"Grid")
747 && parser->process_variable(localname, attributes, nb_attributes))
749 else if (strcmp(localname,
"dimension") == 0) {
750 parser->process_dimension(attributes, nb_attributes);
755 "Expected an 'Attribute', 'Alias', variable or 'dimension' element; found '%s' instead.",
761 parser->set_state(parser_unknown);
768 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
774 const char *localname = (
const char *) l;
776 DBG2(cerr <<
"End element " << localname <<
" (state "
777 << states[parser->get_state()] <<
")" << endl);
779 switch (parser->get_state()) {
782 "Internal parser error; unexpected state, inside start state while processing element '%s'.",
787 if (strcmp(localname,
"Group") == 0)
793 case inside_attribute_container:
794 if (strcmp(localname,
"Attribute") == 0) {
796 parser->at_stack.pop();
802 case inside_attribute:
803 if (strcmp(localname,
"Attribute") == 0)
809 case inside_attribute_value:
810 if (strcmp(localname,
"value") == 0) {
813 atp->
append_attr(parser->dods_attr_name, parser->dods_attr_type, parser->char_data);
814 parser->char_data =
"";
821 case inside_other_xml_attribute: {
822 if (strcmp(localname,
"Attribute") == 0 && parser->root_ns == (
const char *) URI) {
824 DBGN(cerr << endl <<
"\t Popping the 'inside_other_xml_attribute' state"
830 atp->
append_attr(parser->dods_attr_name, parser->dods_attr_type, parser->other_xml);
832 parser->other_xml =
"";
835 DBGN(cerr << endl <<
"\t inside_other_xml_attribute: " << localname
836 <<
", depth: " << parser->other_xml_depth << endl);
837 if (parser->other_xml_depth == 0)
839 "Expected an OtherXML attribute to end! Instead I found '%s'", localname);
840 parser->other_xml_depth--;
842 parser->other_xml.append(
"</");
844 parser->other_xml.append((
const char *) prefix);
845 parser->other_xml.append(
":");
847 parser->other_xml.append(localname);
848 parser->other_xml.append(
">");
853 case inside_enum_def:
854 if (strcmp(localname,
"Enumeration") == 0) {
855 BaseType *btp = parser->bt_stack.top();
869 case inside_enum_const:
870 if (strcmp(localname,
"EnumConst") == 0)
876 case inside_simple_type:
879 BaseType *btp = parser->bt_stack.top();
880 parser->bt_stack.pop();
881 parser->at_stack.pop();
883 BaseType *parent = parser->bt_stack.top();
894 "Tried to add the simple-type variable '%s' to a non-constructor type (%s %s).", localname,
895 parser->bt_stack.top()->type_name().c_str(), parser->bt_stack.top()->name().c_str());
903 parser->finish_variable(localname,
dods_array_c,
"Array");
906 case inside_dimension:
907 if (strcmp(localname,
"dimension") == 0)
913 case inside_constructor:
917 case inside_sequence:
922 parser->finish_variable(localname,
dods_grid_c,
"Grid");
926 parser->finish_variable(localname,
dods_array_c,
"Map");
937 DBGN(cerr <<
" ... " << states[parser->get_state()] << endl);
947 switch (parser->get_state()) {
948 case inside_attribute_value:
949 parser->char_data.append((
const char *) (ch), len);
950 DBG2(cerr <<
"Characters: '" << parser->char_data <<
"'" << endl);
953 case inside_other_xml_attribute:
954 parser->other_xml.append((
const char *) (ch), len);
955 DBG2(cerr <<
"Other XML Characters: '" << parser->other_xml <<
"'" << endl);
971 switch (parser->get_state()) {
972 case inside_other_xml_attribute:
973 parser->other_xml.append((
const char *) (ch), len);
990 switch (parser->get_state()) {
991 case inside_other_xml_attribute:
992 parser->other_xml.append((
const char *) (value), len);
1011 return xmlGetPredefinedEntity(name);
1029 parser->set_state(parser_error);
1031 va_start(args, msg);
1033 vsnprintf(str, 1024, msg, args);
1036 int line = xmlSAX2GetLineNumber(parser->ctxt);
1039 parser->error_msg += string(str) + string(
"\n");
1044 void D4ParserSax2::cleanup_parse(xmlParserCtxtPtr & context)
const
1046 if (!context->wellFormed) {
1047 context->sax = NULL;
1048 xmlFreeParserCtxt(context);
1049 throw D4ParseError(
string(
"\nThe DDX is not a well formed XML document.\n") + error_msg);
1052 if (!context->valid) {
1053 context->sax = NULL;
1054 xmlFreeParserCtxt(context);
1055 throw D4ParseError(
string(
"\nThe DDX is not a valid document.\n") + error_msg);
1058 if (get_state() == parser_error) {
1059 context->sax = NULL;
1060 xmlFreeParserCtxt(context);
1061 throw D4ParseError(
string(
"\nError parsing DMR response.\n") + error_msg);
1064 context->sax = NULL;
1065 xmlFreeParserCtxt(context);
1089 throw InternalErr(__FILE__, __LINE__,
"Input stream not open or read error");
1091 const int size = 1024;
1094 f.getline(chars, size);
1095 int res = f.gcount();
1098 DBG(cerr <<
"line: (" << res <<
"): " << chars << endl);
1099 xmlParserCtxtPtr context = xmlCreatePushParserCtxt(NULL, NULL, chars, res - 1,
"stream");
1105 throw InternalErr(__FILE__, __LINE__,
"Invalid factory class");
1107 xmlSAXHandler ddx_sax_parser;
1108 memset(&ddx_sax_parser, 0,
sizeof(xmlSAXHandler));
1119 ddx_sax_parser.initialized = XML_SAX2_MAGIC;
1123 context->sax = &ddx_sax_parser;
1124 context->userData =
this;
1125 context->validate =
true;
1127 f.getline(chars, size);
1128 while ((f.gcount() > 0)) {
1129 DBG(cerr <<
"line: (" << f.gcount() <<
"): " << chars << endl);
1130 xmlParseChunk(ctxt, chars, f.gcount() - 1, 0);
1131 f.getline(chars, size);
1135 xmlParseChunk(ctxt, chars, 0, 1);
1137 cleanup_parse(context);
1154 istringstream iss(document);
1164 xmlParserCtxtPtr context = xmlCreateFileParserCtxt(document.c_str());
1166 throw D4ParseError(
string(
"Could not initialize the parser with the file: '") + document +
string(
"'."));
1171 xmlSAXHandler ddx_sax_parser;
1172 memset(&ddx_sax_parser, 0,
sizeof(xmlSAXHandler));
1183 ddx_sax_parser.initialized = XML_SAX2_MAGIC;
1187 context->sax = &ddx_sax_parser;
1188 context->userData =
this;
1189 context->validate =
false;
1191 xmlParseDocument(context);
1193 cleanup_parse(context);
virtual Float64 * NewFloat64(const string &n="") const
void add_enumeration_nocopy(D4EnumDef *enum_def)
virtual UInt64 * NewUInt64(const string &n="") const
virtual Int64 * NewInt64(const string &n="") const
virtual D4Group * NewGroup(const string &n="") const
virtual UInt16 * NewUInt16(const string &n="") const
virtual Int16 * NewInt16(const string &n="") const
Contains the attributes for a dataset.
virtual Byte * NewByte(const string &n="") const
static void ddx_get_cdata(void *parser, const xmlChar *value, int len)
static void ddx_ignoreable_whitespace(void *parser, const xmlChar *ch, int len)
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
virtual void add_var(BaseType *bt, Part part=nil)
Add a variable.
Type
Identifies the data type.
Type type() const
Returns the type of the class instance.
A class for software fault reporting.
virtual bool is_vector_type()
Returns true if the instance is a vector (i.e., array) type variable.
virtual Structure * NewStructure(const string &n="") const
virtual bool is_constructor_type()
Returns true if the instance is a constructor (i.e., Structure, Sequence or Grid) type variable...
virtual Float32 * NewFloat32(const string &n="") const
virtual Str * NewStr(const string &n="") const
ObjectType get_type(const string &value)
static void ddx_start_document(void *parser)
virtual UInt32 * NewUInt32(const string &n="") const
bool is_simple_type(Type t)
Returns true if the instance is a numeric, string or URL type variable.
virtual Sequence * NewSequence(const string &n="") const
static void ddx_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)
virtual Int32 * NewInt32(const string &n="") const
virtual Array * NewArray(const string &n="", BaseType *v=0) const
virtual Url * NewUrl(const string &n="") const
string long_to_string(long val, int base)
static void ddx_get_characters(void *parser, const xmlChar *ch, int len)
static xmlEntityPtr ddx_get_entity(void *parser, const xmlChar *name)
BaseTypeFactory * get_factory() const
void set_namespace(const string &ns)
Set the namespace for this DDS/DDX object/response.
virtual Int8 * NewInt8(const string &n="") const
virtual AttrTable & get_attr_table()
virtual Url * NewURL(const string &n="") const
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.
virtual Grid * NewGrid(const string &n="") const
string type_name(Type t)
Returns the type of the class instance as a string.
virtual Byte * NewUInt8(const string &n="") const
static void ddx_fatal_error(void *parser, const char *msg,...)
void intern(const string &document, DDS *dest_dds)
void set_dap_version(const string &version_string="2.0")
void set_request_xml_base(const string &xb)
static void ddx_end_document(void *parser)
static void ddx_end_element(void *parser, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI)
bool is_integer_type(Type t)