34#include <libxml/parserInternals.h>
36#include <libdap/DMR.h>
38#include <libdap/BaseType.h>
39#include <libdap/Array.h>
40#include <libdap/D4Group.h>
41#include <libdap/D4Attributes.h>
42#include <libdap/D4Maps.h>
43#include <libdap/D4Enum.h>
44#include <libdap/D4BaseTypeFactory.h>
46#include <libdap/DapXmlNamespaces.h>
47#include <libdap/util.h>
49#include <BESInternalError.h>
51#include <BESCatalog.h>
52#include <BESCatalogUtils.h>
53#include <BESCatalogList.h>
55#include <TheBESKeys.h>
58#include "DmrppRequestHandler.h"
60#include "DmrppParserSax2.h"
61#include "DmrppCommon.h"
63#include "DmrppNames.h"
64#include "DmrppArray.h"
71#define FIVE_12K 524288
73#define MAX_INPUT_LINE_LENGTH ONE_MB
74#define INCLUDE_BESDEBUG_ISSET 0
76#define prolog std::string("DmrppParserSax2::").append(__func__).append("() - ")
78static const string dmrpp_namespace =
"http://xml.opendap.org/dap/dmrpp/1.0.0#";
87static const char *states[] = {
93 "inside_attribute_container",
95 "inside_attribute_value",
96 "inside_other_xml_attribute",
101 "inside_simple_type",
105 "inside_constructor",
107 "inside_dmrpp_object",
108 "inside_dmrpp_chunkDimensionSizes_element",
109 "inside_dmrpp_compact_element",
112 "parser_fatal_error",
116static bool is_not(
const char *name,
const char *tag)
118 return strcmp(name, tag) != 0;
131DmrppParserSax2::enum_def()
133 if (!d_enum_def) d_enum_def =
new D4EnumDef;
145DmrppParserSax2::dim_def()
147 if (!d_dim_def) d_dim_def =
new D4Dimension;
159string DmrppParserSax2::get_attribute_val(
const string &name,
const xmlChar **attributes,
int num_attributes)
161 unsigned int index = 0;
162 for (
int i = 0; i < num_attributes; ++i, index += 5) {
163 if (strncmp(name.c_str(), (
const char *)attributes[index], name.size()) == 0) {
164 return string((
const char *)attributes[index+3], (
const char *)attributes[index+4]);
176void DmrppParserSax2::transfer_xml_attrs(
const xmlChar **attributes,
int nb_attributes)
178 if (!xml_attrs.empty()) xml_attrs.clear();
182 unsigned int index = 0;
183 for (
int i = 0; i < nb_attributes; ++i, index += 5) {
185 map<string, XMLAttribute>::value_type(
string((
const char *) attributes[index]),
186 XMLAttribute(attributes + index + 1)));
188 BESDEBUG(PARSER, prolog <<
189 "XML Attribute '" << (
const char *)attributes[index] <<
"': " << xml_attrs[(
const char *)attributes[index]].value << endl);
200void DmrppParserSax2::transfer_xml_ns(
const xmlChar **namespaces,
int nb_namespaces)
203 for (
int i = 0; i < nb_namespaces; ++i) {
204 namespace_table.insert(
205 map<string, string>::value_type(namespaces[i * 2] != 0 ? (
const char *) namespaces[i * 2] :
"",
206 (
const char *) namespaces[i * 2 + 1]));
217bool DmrppParserSax2::check_required_attribute(
const string & attr)
219 if (xml_attrs.find(attr) == xml_attrs.end()) {
220 dmr_error(
this,
"Required attribute '%s' not found.", attr.c_str());
237bool DmrppParserSax2::check_required_attribute(
const string &name,
const xmlChar **attributes,
int num_attributes)
239 unsigned int index = 0;
240 for (
int i = 0; i < num_attributes; ++i, index += 5) {
241 if (strncmp(name.c_str(), (
const char *)attributes[index], name.size()) == 0) {
246 dmr_error(
this,
"Required attribute '%s' not found.", name.c_str());
257bool DmrppParserSax2::check_attribute(
const string & attr)
259 return (xml_attrs.find(attr) != xml_attrs.end());
273bool DmrppParserSax2::check_attribute(
const string &name,
const xmlChar **attributes,
int num_attributes)
275 unsigned int index = 0;
276 for (
int i = 0; i < num_attributes; ++i, index += 5) {
277 if (strncmp(name.c_str(), (
const char *)attributes[index], name.size()) == 0) {
284bool DmrppParserSax2::process_dimension_def(
const char *name,
const xmlChar **attrs,
int nb_attributes)
286 if (is_not(name,
"Dimension"))
return false;
289 transfer_xml_attrs(attrs, nb_attributes);
293 if (!(check_required_attribute(
"name", attrs, nb_attributes) && check_required_attribute(
"size", attrs, nb_attributes))) {
294 dmr_error(
this,
"The required attribute 'name' or 'size' was missing from a Dimension element.");
299 if (!check_required_attribute(
"name", attrs, nb_attributes)) {
300 dmr_error(
this,
"The required attribute 'name' was missing from a Dimension element.");
304 if (!check_required_attribute(
"size", attrs, nb_attributes)) {
305 dmr_error(
this,
"The required attribute 'size' was missing from a Dimension element.");
310 dim_def()->set_name(get_attribute_val(
"name", attrs, nb_attributes));
312 dim_def()->set_size(get_attribute_val(
"size", attrs, nb_attributes));
315 dmr_error(
this, e.get_error_message().c_str());
339bool DmrppParserSax2::process_dimension(
const char *name,
const xmlChar **attrs,
int nb_attributes)
341 if (is_not(name,
"Dim"))
return false;
344 transfer_xml_attrs(attrs, nb_attributes);
347 if (check_attribute(
"size", attrs, nb_attributes) && check_attribute(
"name", attrs, nb_attributes)) {
348 dmr_error(
this,
"Only one of 'size' and 'name' are allowed in a Dim element, but both were used.");
351 if (!(check_attribute(
"size", attrs, nb_attributes) || check_attribute(
"name", attrs, nb_attributes))) {
352 dmr_error(
this,
"Either 'size' or 'name' must be used in a Dim element.");
356 bool has_size = check_attribute(
"size", attrs, nb_attributes);
357 bool has_name = check_attribute(
"name", attrs, nb_attributes);
358 if (has_size && has_name) {
359 dmr_error(
this,
"Only one of 'size' and 'name' are allowed in a Dim element, but both were used.");
362 if (!has_size && !has_name) {
363 dmr_error(
this,
"Either 'size' or 'name' must be used in a Dim element.");
368 if (!top_basetype()->is_vector_type()) {
370 BaseType *b = top_basetype();
373 Array *a =
static_cast<Array*
>(dmr()->factory()->NewVariable(dods_array_c, b->name()));
374 a->set_is_dap4(
true);
375 a->add_var_nocopy(b);
376 a->set_attributes_nocopy(b->attributes());
380 b->set_attributes_nocopy(0);
385 assert(top_basetype()->is_vector_type());
387 Array *a =
static_cast<Array*
>(top_basetype());
389 size_t dim_size = stoll(get_attribute_val(
"size", attrs, nb_attributes));
390 BESDEBUG(PARSER, prolog <<
"Processing nameless Dim of size: " << dim_size << endl);
391 a->append_dim_ll(dim_size);
395 string name = get_attribute_val(
"name", attrs, nb_attributes);
396 BESDEBUG(PARSER, prolog <<
"Processing Dim with named Dimension reference: " << name << endl);
398 D4Dimension *dim = 0;
400 dim = dmr()->root()->find_dim(name);
403 dim = top_group()->find_dim(name);
406 throw BESInternalError(
"The dimension '" + name +
"' was not found while parsing the variable '" + a->name() +
"'.",__FILE__,__LINE__);
414bool DmrppParserSax2::process_dmrpp_compact_start(
const char *name){
415 if ( strcmp(name,
"compact") == 0) {
416 BESDEBUG(PARSER, prolog <<
"DMR++ compact element. localname: " << name << endl);
417 BaseType *bt = top_basetype();
418 if (!bt)
throw BESInternalError(
"Could not locate parent BaseType during parse operation.", __FILE__, __LINE__);
419 DmrppCommon *dc =
dynamic_cast<DmrppCommon*
>(bt);
421 throw BESInternalError(
"Could not cast BaseType to DmrppType in the drmpp handler.", __FILE__, __LINE__);
422 dc->set_compact(
true);
431void DmrppParserSax2::process_dmrpp_compact_end(
const char *localname)
433 BESDEBUG(PARSER, prolog <<
"BEGIN DMR++ compact element. localname: " << localname << endl);
434 if (is_not(localname,
"compact"))
437 BaseType *target = top_basetype();
439 throw BESInternalError(
"Could not locate parent BaseType during parse operation.", __FILE__, __LINE__);
440 BESDEBUG(PARSER, prolog <<
"BaseType: " << target->type_name() <<
" " << target->name() << endl);
442 if (target->type() != dods_array_c)
443 throw BESInternalError(
"The dmrpp::compact element must be the child of an array variable",__FILE__,__LINE__);
445 DmrppCommon *dc =
dynamic_cast<DmrppCommon*
>(target);
447 throw BESInternalError(
"Could not cast BaseType to DmrppType in the drmpp handler.", __FILE__, __LINE__);
449 dc->set_compact(
true);
453 std::string data(char_data);
454 BESDEBUG(PARSER, prolog <<
"Read compact element text. size: " << data.size() <<
" length: " << data.size() <<
" value: '" << data <<
"'" << endl);
456 std::vector <u_int8_t> decoded = base64::Base64::decode(data);
458 switch (target->var()->type()) {
460 throw BESInternalError(
"Parser state has been corrupted. An Array may not be the template for an Array.", __FILE__, __LINE__);
478 target->val2buf(
reinterpret_cast<void *
>(decoded.data()));
479 target->set_read_p(
true);
485 std::string str(decoded.begin(), decoded.end());
486 DmrppArray *st =
dynamic_cast<DmrppArray *
>(target);
489 msg << prolog <<
"The target BaseType MUST be an array. and it's a " << target->type_name();
490 BESDEBUG(MODULE, msg.str() << endl);
491 throw BESInternalError(msg.str(),__FILE__,__LINE__);
494 st->set_read_p(
true);
499 throw BESInternalError(
"Unsupported COMPACT storage variable type in the drmpp handler.", __FILE__, __LINE__);
504 BESDEBUG(PARSER, prolog <<
"END" << endl);
507bool DmrppParserSax2::process_map(
const char *name,
const xmlChar **attrs,
int nb_attributes)
509 if (is_not(name,
"Map"))
return false;
512 transfer_xml_attrs(attrs, nb_attributes);
515 if (!check_attribute(
"name", attrs, nb_attributes)) {
516 dmr_error(
this,
"The 'name' attribute must be used in a Map element.");
520 if (!top_basetype()->is_vector_type()) {
522 BaseType *b = top_basetype();
525 Array *a =
static_cast<Array*
>(dmr()->factory()->NewVariable(dods_array_c, b->name()));
526 a->set_is_dap4(
true);
527 a->add_var_nocopy(b);
528 a->set_attributes_nocopy(b->attributes());
532 b->set_attributes_nocopy(0);
537 assert(top_basetype()->is_vector_type());
539 Array *a =
static_cast<Array*
>(top_basetype());
541 string map_name = get_attribute_val(
"name", attrs, nb_attributes);
542 if (get_attribute_val(
"name", attrs, nb_attributes).at(0) !=
'/') map_name = top_group()->FQN() + map_name;
544 Array *map_source = 0;
546 if (map_name[0] ==
'/')
547 map_source = dmr()->root()->find_map_source(map_name);
550 map_source = top_group()->find_map_source(map_name);
558 if (!map_source && d_strict)
559 throw BESInternalError(
"The Map '" + map_name +
"' was not found while parsing the variable '" + a->name() +
"'.",__FILE__,__LINE__);
561 a->maps()->add_map(
new D4Map(map_name, map_source));
566bool DmrppParserSax2::process_group(
const char *name,
const xmlChar **attrs,
int nb_attributes)
568 if (is_not(name,
"Group"))
return false;
571 transfer_xml_attrs(attrs, nb_attributes);
574 if (!check_required_attribute(
"name", attrs, nb_attributes)) {
575 dmr_error(
this,
"The required attribute 'name' was missing from a Group element.");
579 BaseType *btp = dmr()->factory()->NewVariable(dods_group_c, get_attribute_val(
"name", attrs, nb_attributes));
581 dmr_fatal_error(
this,
"Could not instantiate the Group '%s'.", get_attribute_val(
"name", attrs, nb_attributes).c_str());
585 D4Group *grp =
static_cast<D4Group*
>(btp);
589 grp->set_is_dap4(
true);
592 D4Group *parent = top_group();
598 grp->set_parent(parent);
599 parent->add_group_nocopy(grp);
602 push_attributes(grp->attributes());
612inline bool DmrppParserSax2::process_attribute(
const char *name,
const xmlChar **attrs,
int nb_attributes)
614 if (is_not(name,
"Attribute"))
return false;
618 transfer_xml_attrs(attrs, nb_attributes);
622 if (!(check_required_attribute(
string(
"name"), attrs, nb_attributes) && check_required_attribute(
string(
"type"), attrs, nb_attributes))) {
623 dmr_error(
this,
"The required attribute 'name' or 'type' was missing from an Attribute element.");
627 if (get_attribute_val(
"type", attrs, nb_attributes) ==
"Container") {
628 push_state(inside_attribute_container);
630 BESDEBUG(PARSER, prolog <<
"Pushing attribute container " << get_attribute_val(
"name", attrs, nb_attributes) << endl);
631 D4Attribute *child =
new D4Attribute(get_attribute_val(
"name", attrs, nb_attributes), attr_container_c);
633 D4Attributes *tos = top_attributes();
637 dmr_fatal_error(
this,
"Expected an Attribute container on the top of the attribute stack.");
641 tos->add_attribute_nocopy(child);
642 push_attributes(child->attributes());
644 else if (get_attribute_val(
"type", attrs, nb_attributes) ==
"OtherXML") {
645 push_state(inside_other_xml_attribute);
647 dods_attr_name = get_attribute_val(
"name", attrs, nb_attributes);
648 dods_attr_type = get_attribute_val(
"type", attrs, nb_attributes);
651 push_state(inside_attribute);
653 dods_attr_name = get_attribute_val(
"name", attrs, nb_attributes);
654 dods_attr_type = get_attribute_val(
"type", attrs, nb_attributes);
665inline bool DmrppParserSax2::process_enum_def(
const char *name,
const xmlChar **attrs,
int nb_attributes)
667 if (is_not(name,
"Enumeration"))
return false;
670 transfer_xml_attrs(attrs, nb_attributes);
673 if (!(check_required_attribute(
"name", attrs, nb_attributes) && check_required_attribute(
"basetype", attrs, nb_attributes))) {
674 dmr_error(
this,
"The required attribute 'name' or 'basetype' was missing from an Enumeration element.");
678 Type t = get_type(get_attribute_val(
"basetype", attrs, nb_attributes).c_str());
679 if (!is_integer_type(t)) {
680 dmr_error(
this,
"The Enumeration '%s' must have an integer type, instead the type '%s' was used.",
681 get_attribute_val(
"name", attrs, nb_attributes).c_str(), get_attribute_val(
"basetype", attrs, nb_attributes).c_str());
686 string enum_def_path = get_attribute_val(
"name", attrs, nb_attributes);
689 if (xml_attrs[
"name"].value[0] !=
'/')
690 enum_def_path = top_group()->FQN() + enum_def_path;
692 enum_def()->set_name(enum_def_path);
693 enum_def()->set_type(t);
698inline bool DmrppParserSax2::process_enum_const(
const char *name,
const xmlChar **attrs,
int nb_attributes)
700 if (is_not(name,
"EnumConst"))
return false;
704 transfer_xml_attrs(attrs, nb_attributes);
707 if (!(check_required_attribute(
"name", attrs, nb_attributes) && check_required_attribute(
"value", attrs, nb_attributes))) {
708 dmr_error(
this,
"The required attribute 'name' or 'value' was missing from an EnumConst element.");
712 istringstream iss(get_attribute_val(
"value", attrs, nb_attributes));
714 iss >> skipws >> value;
715 if (iss.fail() || iss.bad()) {
716 dmr_error(
this,
"Expected an integer value for an Enumeration constant, got '%s' instead.",
717 get_attribute_val(
"value", attrs, nb_attributes).c_str());
719 else if (!enum_def()->is_valid_enum_value(value)) {
720 dmr_error(
this,
"In an Enumeration constant, the value '%s' cannot fit in a variable of type '%s'.",
721 get_attribute_val(
"value", attrs, nb_attributes).c_str(), D4type_name(d_enum_def->type()).c_str());
725 enum_def()->add_value(get_attribute_val(
"name", attrs, nb_attributes), value);
736inline bool DmrppParserSax2::process_variable(
const char *name,
const xmlChar **attrs,
int nb_attributes)
738 Type t = get_type(name);
739 if (is_simple_type(t)) {
740 process_variable_helper(t, inside_simple_type, attrs, nb_attributes);
745 case dods_structure_c:
746 process_variable_helper(t, inside_constructor, attrs, nb_attributes);
749 case dods_sequence_c:
750 process_variable_helper(t, inside_constructor, attrs, nb_attributes);
766void DmrppParserSax2::process_variable_helper(
Type t, ParseState s,
const xmlChar **attrs,
int nb_attributes)
769 transfer_xml_attrs(attrs, nb_attributes);
772 if (check_required_attribute(
"name", attrs, nb_attributes)) {
773 BaseType *btp = dmr()->factory()->NewVariable(t, get_attribute_val(
"name", attrs, nb_attributes));
775 dmr_fatal_error(
this,
"Could not instantiate the variable '%s'.", xml_attrs[
"name"].value.c_str());
779 if ((t == dods_enum_c) && check_required_attribute(
"enum", attrs, nb_attributes)) {
780 D4EnumDef *enum_def = 0;
781 string enum_path = get_attribute_val(
"enum", attrs, nb_attributes);
782 if (enum_path[0] ==
'/')
783 enum_def = dmr()->root()->find_enum_def(enum_path);
785 enum_def = top_group()->find_enum_def(enum_path);
787 if (!enum_def)
dmr_fatal_error(
this,
"Could not find the Enumeration definition '%s'.", enum_path.c_str());
789 static_cast<D4Enum*
>(btp)->set_enumeration(enum_def);
792 btp->set_is_dap4(
true);
795 push_attributes(btp->attributes());
813 DmrppParserSax2 *parser =
static_cast<DmrppParserSax2*
>(p);
814 parser->error_msg =
"";
815 parser->char_data =
"";
822 parser->push_attributes(parser->dmr()->root()->attributes());
824 BESDEBUG(PARSER, prolog <<
"Parser start state: " << states[parser->get_state()] << endl);
831 DmrppParserSax2 *parser =
static_cast<DmrppParserSax2*
>(p);
833 BESDEBUG(PARSER, prolog <<
"Parser end state: " << states[parser->get_state()] << endl);
835 if (parser->get_state() != parser_end)
836 DmrppParserSax2::dmr_error(parser,
"The document contained unbalanced tags.");
840 if (parser->get_state() == parser_error || parser->get_state() == parser_fatal_error)
return;
842 if (!parser->empty_basetype() || parser->empty_group())
843 DmrppParserSax2::dmr_error(parser,
844 "The document did not contain a valid root Group or contained unbalanced tags.");
846#if INCLUDE_BESDEBUG_ISSET
849 *os << prolog <<
"parser->top_group() BEGIN " << endl;
850 parser->top_group()->dump(*os);
851 *os << endl << prolog <<
"parser->top_group() END " << endl;
856 parser->pop_attributes();
859void DmrppParserSax2::dmr_start_element(
void *p,
const xmlChar *l,
const xmlChar *prefix,
const xmlChar *URI,
860 int nb_namespaces,
const xmlChar **namespaces,
int nb_attributes,
int ,
const xmlChar **attributes)
863 const char *localname =
reinterpret_cast<const char *
>(l);
865 string this_element_ns_name(URI ? (
char *) URI :
"null");
867 if (parser->get_state() != parser_error) {
868 string dap4_ns_name = DapXmlNamspaces::getDapNamespaceString(DAP_4_0);
869 BESDEBUG(PARSER, prolog <<
"dap4_ns_name: " << dap4_ns_name << endl);
871 if (this_element_ns_name == dmrpp_namespace) {
872 if (strcmp(localname,
"chunkDimensionSizes") == 0) {
873 BESDEBUG(PARSER, prolog <<
"Found dmrpp:chunkDimensionSizes element. Pushing state." << endl);
874 parser->push_state(inside_dmrpp_chunkDimensionSizes_element);
876 else if (strcmp(localname,
"compact") == 0) {
877 BESDEBUG(PARSER, prolog <<
"Found dmrpp:compact element. Pushing state." << endl);
878 parser->push_state(inside_dmrpp_compact_element);
882 prolog <<
"Start of element in dmrpp namespace: " << localname <<
" detected." << endl);
883 parser->push_state(inside_dmrpp_object);
886 else if (this_element_ns_name != dap4_ns_name) {
887 BESDEBUG(PARSER, prolog <<
"Start of non DAP4 element: " << localname <<
" detected." << endl);
888 parser->push_state(not_dap4_element);
892 BESDEBUG(PARSER, prolog <<
"Start element " << localname <<
" prefix: " << (prefix ? (
char *) prefix :
"null") <<
" ns: "
893 << this_element_ns_name <<
" (state: " << states[parser->get_state()] <<
")" << endl);
895 switch (parser->get_state()) {
897 if (is_not(localname,
"Dataset"))
898 DmrppParserSax2::dmr_error(parser,
"Expected DMR to start with a Dataset element; found '%s' instead.",
901 parser->root_ns = URI ? (
const char *) URI :
"";
904 parser->transfer_xml_attrs(attributes, nb_attributes);
907 if (parser->check_required_attribute(
string(
"name"), attributes, nb_attributes))
908 parser->dmr()->set_name(parser->get_attribute_val(
"name", attributes, nb_attributes));
917 if (parser->check_attribute(
"version", attributes, nb_attributes)) {
918 auto dmrpp =
dynamic_cast<DMRpp*
>(parser->dmr());
920 dmrpp->set_version(parser->get_attribute_val(
"version", attributes, nb_attributes));
921 DmrppRequestHandler::d_emulate_original_filter_order_behavior =
false;
924 DmrppRequestHandler::d_emulate_original_filter_order_behavior =
true;
927 if (parser->check_attribute(
"dapVersion", attributes, nb_attributes))
928 parser->dmr()->set_dap_version(parser->get_attribute_val(
"dapVersion", attributes, nb_attributes));
930 if (parser->check_attribute(
"dmrVersion", attributes, nb_attributes))
931 parser->dmr()->set_dmr_version(parser->get_attribute_val(
"dmrVersion", attributes, nb_attributes));
933 if (parser->check_attribute(
"base", attributes, nb_attributes)) {
934 parser->dmr()->set_request_xml_base(parser->get_attribute_val(
"base", attributes, nb_attributes));
936 BESDEBUG(PARSER, prolog <<
"Dataset xml:base is set to '" << parser->dmr()->request_xml_base() <<
"'" << endl);
938 if (parser->check_attribute(
"href", attributes, nb_attributes)) {
939 bool trusted =
false;
940 if (parser->check_attribute(
"trust", attributes, nb_attributes)) {
941 string value = parser->get_attribute_val(
"trust", attributes, nb_attributes);
942 trusted = value ==
"true";
944 string href = parser->get_attribute_val(
"href", attributes, nb_attributes);
945 parser->dmrpp_dataset_href = shared_ptr<http::url>(
new http::url(href,trusted));
946 BESDEBUG(PARSER, prolog <<
"Processed 'href' value into data_url. href: " << parser->dmrpp_dataset_href->str() << (trusted?
"(trusted)":
"") << endl);
963 BESDEBUG(PARSER, prolog <<
"Dataset dmrpp:href is set to '" << parser->dmrpp_dataset_href->str() <<
"'" << endl);
965 if (!parser->root_ns.empty()) parser->dmr()->set_namespace(parser->root_ns);
968 parser->push_group(parser->dmr()->root());
970 parser->push_state(inside_dataset);
979 if (parser->process_enum_def(localname, attributes, nb_attributes))
980 parser->push_state(inside_enum_def);
981 else if (parser->process_dimension_def(localname, attributes, nb_attributes))
982 parser->push_state(inside_dim_def);
983 else if (parser->process_group(localname, attributes, nb_attributes))
984 parser->push_state(inside_group);
985 else if (parser->process_variable(localname, attributes, nb_attributes))
989 else if (parser->process_attribute(localname, attributes, nb_attributes))
994 DmrppParserSax2::dmr_error(parser,
995 "Expected an Attribute, Enumeration, Dimension, Group or variable element; found '%s' instead.",
999 case inside_attribute_container:
1000 if (parser->process_attribute(localname, attributes, nb_attributes))
1003 DmrppParserSax2::dmr_error(parser,
"Expected an Attribute element; found '%s' instead.", localname);
1006 case inside_attribute:
1007 if (parser->process_attribute(localname, attributes, nb_attributes))
1009 else if (strcmp(localname,
"Value") == 0)
1010 parser->push_state(inside_attribute_value);
1012 dmr_error(parser,
"Expected an 'Attribute' or 'Value' element; found '%s' instead.", localname);
1015 case inside_attribute_value:
1019 case inside_other_xml_attribute:
1020 parser->other_xml_depth++;
1023 parser->other_xml.append(
"<");
1025 parser->other_xml.append((
const char *) prefix);
1026 parser->other_xml.append(
":");
1028 parser->other_xml.append(localname);
1030 if (nb_namespaces != 0) {
1031 parser->transfer_xml_ns(namespaces, nb_namespaces);
1033 for (map<string, string>::iterator i = parser->namespace_table.begin(); i != parser->namespace_table.end();
1035 parser->other_xml.append(
" xmlns");
1036 if (!i->first.empty()) {
1037 parser->other_xml.append(
":");
1038 parser->other_xml.append(i->first);
1040 parser->other_xml.append(
"=\"");
1041 parser->other_xml.append(i->second);
1042 parser->other_xml.append(
"\"");
1046 if (nb_attributes != 0) {
1048 parser->transfer_xml_attrs(attributes, nb_attributes);
1050 for (XMLAttrMap::iterator i = parser->xml_attr_begin(); i != parser->xml_attr_end(); ++i) {
1051 parser->other_xml.append(
" ");
1052 if (!i->second.prefix.empty()) {
1053 parser->other_xml.append(i->second.prefix);
1054 parser->other_xml.append(
":");
1056 parser->other_xml.append(i->first);
1057 parser->other_xml.append(
"=\"");
1058 parser->other_xml.append(i->second.value);
1059 parser->other_xml.append(
"\"");
1063 parser->other_xml.append(
">");
1066 case inside_enum_def:
1068 if (parser->process_enum_const(localname, attributes, nb_attributes))
1069 parser->push_state(inside_enum_const);
1071 dmr_error(parser,
"Expected an 'EnumConst' element; found '%s' instead.", localname);
1074 case inside_enum_const:
1078 case inside_dim_def:
1090 case inside_simple_type:
1091 if (parser->process_attribute(localname, attributes, nb_attributes))
1093 else if (parser->process_dimension(localname, attributes, nb_attributes))
1094 parser->push_state(inside_dim);
1095 else if (parser->process_map(localname, attributes, nb_attributes))
1096 parser->push_state(inside_map);
1098 dmr_error(parser,
"Expected an 'Attribute', 'Dim' or 'Map' element; found '%s' instead.", localname);
1101 case inside_constructor:
1102 if (parser->process_variable(localname, attributes, nb_attributes))
1106 else if (parser->process_attribute(localname, attributes, nb_attributes))
1108 else if (parser->process_dimension(localname, attributes, nb_attributes))
1109 parser->push_state(inside_dim);
1110 else if (parser->process_map(localname, attributes, nb_attributes))
1111 parser->push_state(inside_map);
1113 DmrppParserSax2::dmr_error(parser,
1114 "Expected an Attribute, Dim, Map or variable element; found '%s' instead.", localname);
1117 case not_dap4_element:
1118 BESDEBUG(PARSER, prolog <<
"SKIPPING unexpected element. localname: " << localname <<
"namespace: "
1119 << this_element_ns_name << endl);
1122 case inside_dmrpp_compact_element:
1123 if (parser->process_dmrpp_compact_start(localname)) {
1124 BESDEBUG(PARSER, prolog <<
"Call to parser->process_dmrpp_compact_start() completed." << endl);
1128 case inside_dmrpp_object: {
1129 BESDEBUG(PARSER, prolog <<
"Inside dmrpp namespaced element. localname: " << localname << endl);
1130 assert(this_element_ns_name == dmrpp_namespace);
1133 parser->transfer_xml_attrs(attributes, nb_attributes);
1136 BaseType *bt = parser->top_basetype();
1137 if (!bt)
throw BESInternalError(
"Could locate parent BaseType during parse operation.", __FILE__, __LINE__);
1139 DmrppCommon *dc =
dynamic_cast<DmrppCommon*
>(bt);
1141 throw BESInternalError(
"Could not cast BaseType to DmrppType in the drmpp handler.", __FILE__, __LINE__);
1144 if (strcmp(localname,
"chunks") == 0) {
1145 BESDEBUG(PARSER, prolog <<
"DMR++ chunks element. localname: " << localname << endl);
1147 if (parser->check_attribute(
"compressionType", attributes, nb_attributes)) {
1148 string compression_type_string(parser->get_attribute_val(
"compressionType", attributes, nb_attributes));
1149 dc->ingest_compression_type(compression_type_string);
1151 BESDEBUG(PARSER, prolog <<
"Processed attribute 'compressionType=\"" <<
1152 compression_type_string <<
"\"'" << endl);
1155 BESDEBUG(PARSER, prolog <<
"There was no 'compressionType' attribute associated with the variable '"
1156 << bt->type_name() <<
" " << bt->name() <<
"'" << endl);
1159 if (parser->check_attribute(
"byteOrder", attributes, nb_attributes)) {
1160 string byte_order_string(parser->get_attribute_val(
"byteOrder", attributes, nb_attributes));
1161 dc->ingest_byte_order(byte_order_string);
1163 BESDEBUG(PARSER, prolog <<
"Processed attribute 'byteOrder=\"" << byte_order_string <<
"\"'" << endl);
1166 BESDEBUG(PARSER, prolog <<
"There was no 'byteOrder' attribute associated with the variable '" << bt->type_name()
1167 <<
" " << bt->name() <<
"'" << endl);
1171 else if (strcmp(localname,
"chunk") == 0) {
1172 string data_url_str =
"unknown_data_location";
1173 shared_ptr<http::url> data_url;
1175 if (parser->check_attribute(
"href", attributes, nb_attributes)) {
1176 bool trusted =
false;
1177 if (parser->check_attribute(
"trust", attributes, nb_attributes)) {
1178 string value = parser->get_attribute_val(
"trust", attributes, nb_attributes);
1179 trusted = value ==
"true";
1183 data_url_str = parser->get_attribute_val(
"href", attributes, nb_attributes);
1184 data_url = shared_ptr<http::url> (
new http::url(data_url_str,trusted));
1185 BESDEBUG(PARSER, prolog <<
"Processed 'href' value into data_url. href: " << data_url->str() << (trusted?
"":
"(trusted)") << endl);
1205 BESDEBUG(PARSER, prolog <<
"No attribute 'href' located. Trying Dataset/@dmrpp:href..." << endl);
1208 data_url = parser->dmrpp_dataset_href;
1211 BESDEBUG(PARSER, prolog <<
"Processing dmrpp:href into data_url. dmrpp:href='" << data_url->str() <<
"'" << endl);
1214 if (data_url->protocol() != HTTP_PROTOCOL && data_url->protocol() != HTTPS_PROTOCOL && data_url->protocol() != FILE_PROTOCOL) {
1215 BESDEBUG(PARSER, prolog <<
"data_url does NOT start with 'http://', 'https://' or 'file://'. "
1216 "Retrieving default catalog root directory" << endl);
1219 BESCatalog *defcat = BESCatalogList::TheCatalogList()->
default_catalog();
1221 BESDEBUG(PARSER, prolog <<
"Not able to find the default catalog." << endl);
1227 BESDEBUG(PARSER, prolog <<
"Found default catalog root_dir: '" << utils->
get_root_dir() <<
"'" << endl);
1230 data_url_str = FILE_PROTOCOL + data_url_str;
1231 data_url = shared_ptr<http::url> (
new http::url(data_url_str));
1235 BESDEBUG(PARSER, prolog <<
"Processed data_url: '" << data_url->str() <<
"'" << endl);
1237 unsigned long long offset = 0;
1238 unsigned long long size = 0;
1239 string chunk_position_in_array(
"");
1240 std::string byte_order = dc->get_byte_order();
1242 if (parser->check_required_attribute(
"offset", attributes, nb_attributes)) {
1243 istringstream offset_ss(parser->get_attribute_val(
"offset", attributes, nb_attributes));
1244 offset_ss >> offset;
1245 BESDEBUG(PARSER, prolog <<
"Processed attribute 'offset=\"" << offset <<
"\"'" << endl);
1248 dmr_error(parser,
"The hdf:byteStream element is missing the required attribute 'offset'.");
1251 if (parser->check_required_attribute(
"nBytes", attributes, nb_attributes)) {
1252 istringstream size_ss(parser->get_attribute_val(
"nBytes", attributes, nb_attributes));
1254 BESDEBUG(PARSER, prolog <<
"Processed attribute 'nBytes=\"" << size <<
"\"'" << endl);
1257 dmr_error(parser,
"The hdf:byteStream element is missing the required attribute 'size'.");
1260 if (parser->check_attribute(
"chunkPositionInArray", attributes, nb_attributes)) {
1261 istringstream chunk_position_ss(parser->get_attribute_val(
"chunkPositionInArray", attributes, nb_attributes));
1262 chunk_position_in_array = chunk_position_ss.str();
1263 BESDEBUG(PARSER, prolog <<
"Found attribute 'chunkPositionInArray' value: " << chunk_position_ss.str() << endl);
1266 BESDEBUG(PARSER, prolog <<
"No attribute 'chunkPositionInArray' located" << endl);
1269 dc->add_chunk(data_url, byte_order, size, offset, chunk_position_in_array);
1274 case inside_dmrpp_chunkDimensionSizes_element:
1278 case parser_unknown:
1280 case parser_fatal_error:
1288 BESDEBUG(PARSER, prolog <<
"Start element exit state: " << states[parser->get_state()] << endl);
1291void DmrppParserSax2::dmr_end_element(
void *p,
const xmlChar *l,
const xmlChar *prefix,
const xmlChar *URI)
1293 DmrppParserSax2 *parser =
static_cast<DmrppParserSax2*
>(p);
1294 const char *localname = (
const char *) l;
1296 BESDEBUG(PARSER, prolog <<
"End element " << localname <<
" (state " << states[parser->get_state()] <<
")" << endl);
1298 switch (parser->get_state()) {
1300 dmr_fatal_error(parser,
"Unexpected state, inside start state while processing element '%s'.", localname);
1303 case inside_dataset:
1304 if (is_not(localname,
"Dataset"))
1305 DmrppParserSax2::dmr_error(parser,
"Expected an end Dataset tag; found '%s' instead.", localname);
1307 parser->pop_state();
1308 if (parser->get_state() != parser_start)
1311 parser->pop_state();
1312 parser->push_state(parser_end);
1316 case inside_group: {
1317 if (is_not(localname,
"Group"))
1318 DmrppParserSax2::dmr_error(parser,
"Expected an end tag for a Group; found '%s' instead.", localname);
1320 if (!parser->empty_basetype() || parser->empty_group())
1321 DmrppParserSax2::dmr_error(parser,
1322 "The document did not contain a valid root Group or contained unbalanced tags.");
1324 parser->pop_group();
1325 parser->pop_state();
1329 case inside_attribute_container:
1330 if (is_not(localname,
"Attribute"))
1331 DmrppParserSax2::dmr_error(parser,
"Expected an end Attribute tag; found '%s' instead.", localname);
1333 parser->pop_state();
1334 parser->pop_attributes();
1337 case inside_attribute:
1338 if (is_not(localname,
"Attribute"))
1339 DmrppParserSax2::dmr_error(parser,
"Expected an end Attribute tag; found '%s' instead.", localname);
1341 parser->pop_state();
1344 case inside_attribute_value: {
1345 if (is_not(localname,
"Value"))
1346 DmrppParserSax2::dmr_error(parser,
"Expected an end value tag; found '%s' instead.", localname);
1348 parser->pop_state();
1353 D4Attributes *attrs = parser->top_attributes();
1354 D4Attribute *attr = attrs->get(parser->dods_attr_name);
1356 attr =
new D4Attribute(parser->dods_attr_name, StringToD4AttributeType(parser->dods_attr_type));
1357 attrs->add_attribute_nocopy(attr);
1359 attr->add_value(parser->char_data);
1361 parser->char_data =
"";
1365 case inside_other_xml_attribute: {
1366 if (strcmp(localname,
"Attribute") == 0 && parser->root_ns == (
const char *) URI) {
1367 parser->pop_state();
1372 D4Attributes *attrs = parser->top_attributes();
1373 D4Attribute *attr = attrs->get(parser->dods_attr_name);
1375 attr =
new D4Attribute(parser->dods_attr_name, StringToD4AttributeType(parser->dods_attr_type));
1376 attrs->add_attribute_nocopy(attr);
1378 attr->add_value(parser->other_xml);
1380 parser->other_xml =
"";
1383 if (parser->other_xml_depth == 0) {
1384 DmrppParserSax2::dmr_error(parser,
"Expected an OtherXML attribute to end! Instead I found '%s'",
1388 parser->other_xml_depth--;
1390 parser->other_xml.append(
"</");
1392 parser->other_xml.append((
const char *) prefix);
1393 parser->other_xml.append(
":");
1395 parser->other_xml.append(localname);
1396 parser->other_xml.append(
">");
1401 case inside_enum_def:
1402 if (is_not(localname,
"Enumeration"))
1403 DmrppParserSax2::dmr_error(parser,
"Expected an end Enumeration tag; found '%s' instead.", localname);
1404 if (!parser->top_group())
1406 "Expected a Group to be the current item, while finishing up an Enumeration.");
1409 parser->top_group()->enum_defs()->add_enum_nocopy(parser->enum_def());
1412 parser->clear_enum_def();
1413 parser->pop_state();
1417 case inside_enum_const:
1418 if (is_not(localname,
"EnumConst"))
1419 DmrppParserSax2::dmr_error(parser,
"Expected an end EnumConst tag; found '%s' instead.", localname);
1421 parser->pop_state();
1424 case inside_dim_def: {
1425 if (is_not(localname,
"Dimension"))
1426 DmrppParserSax2::dmr_error(parser,
"Expected an end Dimension tag; found '%s' instead.", localname);
1428 if (!parser->top_group())
1429 DmrppParserSax2::dmr_error(parser,
1430 "Expected a Group to be the current item, while finishing up an Dimension.");
1432 parser->top_group()->dims()->add_dim_nocopy(parser->dim_def());
1438 parser->clear_dim_def();
1439 parser->pop_state();
1443 case inside_simple_type:
1444 if (is_simple_type(get_type(localname))) {
1445 BaseType *btp = parser->top_basetype();
1446 parser->pop_basetype();
1447 parser->pop_attributes();
1448 BaseType *parent = 0;
1449 if (!parser->empty_basetype())
1450 parent = parser->top_basetype();
1451 else if (!parser->empty_group())
1452 parent = parser->top_group();
1454 dmr_fatal_error(parser,
"Both the Variable and Groups stacks are empty while closing a %s element.",
1457 parser->pop_state();
1460 if (parent->type() == dods_array_c)
1461 static_cast<Array*
>(parent)->prototype()->add_var_nocopy(btp);
1463 parent->add_var_nocopy(btp);
1466 DmrppParserSax2::dmr_error(parser,
"Expected an end tag for a simple type; found '%s' instead.", localname);
1468 parser->pop_state();
1472 if (is_not(localname,
"Dim"))
1475 parser->pop_state();
1479 if (is_not(localname,
"Map"))
1482 parser->pop_state();
1485 case inside_constructor: {
1486 if (strcmp(localname,
"Structure") != 0 && strcmp(localname,
"Sequence") != 0) {
1487 DmrppParserSax2::dmr_error(parser,
"Expected an end tag for a constructor; found '%s' instead.", localname);
1490 BaseType *btp = parser->top_basetype();
1491 parser->pop_basetype();
1492 parser->pop_attributes();
1493 BaseType *parent = 0;
1494 if (!parser->empty_basetype())
1495 parent = parser->top_basetype();
1496 else if (!parser->empty_group())
1497 parent = parser->top_group();
1499 dmr_fatal_error(parser,
"Both the Variable and Groups stacks are empty while closing a %s element.",
1502 parser->pop_state();
1507 parent->add_var_nocopy(btp);
1508 parser->pop_state();
1512 case not_dap4_element:
1513 BESDEBUG(PARSER, prolog <<
"End of non DAP4 element: " << localname << endl);
1514 parser->pop_state();
1518 case inside_dmrpp_compact_element: {
1519 parser->process_dmrpp_compact_end(localname);
1520 BESDEBUG(PARSER, prolog <<
"End of dmrpp compact element: " << localname << endl);
1521 parser->pop_state();
1526 case inside_dmrpp_object: {
1527 BESDEBUG(PARSER, prolog <<
"End of dmrpp namespace element: " << localname << endl);
1528 parser->pop_state();
1532 case inside_dmrpp_chunkDimensionSizes_element: {
1533 BESDEBUG(PARSER, prolog <<
"End of chunkDimensionSizes element. localname: " << localname << endl);
1535 if (is_not(localname,
"chunkDimensionSizes"))
1536 DmrppParserSax2::dmr_error(parser,
"Expected an end value tag; found '%s' instead.", localname);
1537 DmrppCommon *dc =
dynamic_cast<DmrppCommon*
>(parser->top_basetype());
1539 throw BESInternalError(
"Could not cast BaseType to DmrppType in the drmpp handler.", __FILE__, __LINE__);
1540 string element_text(parser->char_data);
1541 BESDEBUG(PARSER, prolog <<
"chunkDimensionSizes element_text: '" << element_text <<
"'" << endl);
1542 dc->parse_chunk_dimension_sizes(element_text);
1543 parser->char_data =
"";
1544 parser->pop_state();
1548 case parser_unknown:
1549 parser->pop_state();
1553 case parser_fatal_error:
1562 BESDEBUG(PARSER, prolog <<
"End element exit state: " << states[parser->get_state()] <<
1563 " ("<<parser->get_state()<<
")"<< endl);
1571 DmrppParserSax2 *parser =
static_cast<DmrppParserSax2*
>(p);
1573 switch (parser->get_state()) {
1574 case inside_attribute_value:
1575 case inside_dmrpp_chunkDimensionSizes_element:
1576 case inside_dmrpp_compact_element:
1577 parser->char_data.append((
const char *) (ch), len);
1578 BESDEBUG(PARSER, prolog <<
"Characters[" << parser->char_data.size() <<
"]" << parser->char_data <<
"'" << endl);
1581 case inside_other_xml_attribute:
1582 parser->other_xml.append((
const char *) (ch), len);
1583 BESDEBUG(PARSER, prolog <<
"Other XML Characters: '" << parser->other_xml <<
"'" << endl);
1597 DmrppParserSax2 *parser =
static_cast<DmrppParserSax2*
>(p);
1599 switch (parser->get_state()) {
1600 case inside_other_xml_attribute:
1601 parser->other_xml.append((
const char *) (ch), len);
1616 DmrppParserSax2 *parser =
static_cast<DmrppParserSax2*
>(p);
1618 switch (parser->get_state()) {
1619 case inside_other_xml_attribute:
1620 parser->other_xml.append((
const char *) (value), len);
1623 case parser_unknown:
1627 DmrppParserSax2::dmr_error(parser,
"Found a CData block but none are allowed by DAP4.");
1639 return xmlGetPredefinedEntity(name);
1655 DmrppParserSax2 *parser =
static_cast<DmrppParserSax2*
>(p);
1657 parser->push_state(parser_fatal_error);
1659 va_start(args, msg);
1661 vsnprintf(str, 1024, msg, args);
1664 int line = xmlSAX2GetLineNumber(parser->context);
1666 if (!parser->error_msg.empty()) parser->error_msg +=
"\n";
1667 parser->error_msg +=
"At line " + long_to_string(line) +
": " + string(str);
1670void DmrppParserSax2::dmr_error(
void *p,
const char *msg, ...)
1675 parser->push_state(parser_error);
1677 va_start(args, msg);
1679 vsnprintf(str, 1024, msg, args);
1682 int line = xmlSAX2GetLineNumber(parser->context);
1684 if (!parser->error_msg.empty()) parser->error_msg +=
"\n";
1685 parser->error_msg +=
"At line " + long_to_string(line) +
": " + string(str);
1692void DmrppParserSax2::cleanup_parse()
1694 bool wellFormed = context->wellFormed;
1695 bool valid = context->valid;
1699 xmlFreeParserCtxt(context);
1709 while (!btp_stack.empty()) {
1710 delete top_basetype();
1715 throw BESInternalError(
"The DMR was not well formed. " + error_msg,__FILE__,__LINE__);
1717 throw BESInternalError(
"The DMR was not valid." + error_msg,__FILE__,__LINE__);
1718 else if (get_state() == parser_error)
1719 throw BESInternalError(error_msg,__FILE__,__LINE__);
1720 else if (get_state() == parser_fatal_error)
throw BESInternalError(error_msg,__FILE__,__LINE__);
1740 if (!f.good())
throw BESInternalError(prolog +
"ERROR - Supplied istream instance not open or read error",__FILE__,__LINE__);
1741 if (!dest_dmr)
throw BESInternalError(prolog +
"THe supplied DMR object pointer is null", __FILE__, __LINE__);
1750 if (line.size() == 0)
throw BESInternalError(prolog +
"ERROR - No input found when parsing the DMR++",__FILE__,__LINE__);
1752 BESDEBUG(PARSER, prolog <<
"line: (" << line_num <<
"): " << endl << line << endl << endl);
1754 context = xmlCreatePushParserCtxt(&dmrpp_sax_parser,
this, line.c_str(), line.size(),
"stream");
1755 context->validate =
true;
1756 push_state(parser_start);
1759 long chunk_count = 0;
1760 long chunk_size = 0;
1762 f.read(d_parse_buffer, D4_PARSE_BUFF_SIZE);
1763 chunk_size=f.gcount();
1764 d_parse_buffer[chunk_size]=0;
1765 BESDEBUG(PARSER, prolog <<
"chunk: (" << chunk_count++ <<
"): " << endl);
1766 BESDEBUG(PARSER, prolog <<
"d_parse_buffer: (" << d_parse_buffer <<
"): " << endl);
1768 while(!f.eof() && (get_state() != parser_end)){
1770 xmlParseChunk(context, d_parse_buffer, chunk_size, 0);
1773 f.read(d_parse_buffer, D4_PARSE_BUFF_SIZE);
1774 chunk_size=f.gcount();
1775 d_parse_buffer[chunk_size]=0;
1776 BESDEBUG(PARSER, prolog <<
"chunk: (" << chunk_count++ <<
"): " << endl);
1777 BESDEBUG(PARSER, prolog <<
"d_parse_buffer: (" << d_parse_buffer <<
"): " << endl);
1781 xmlParseChunk(context, d_parse_buffer, chunk_size, 1);
1800 intern(document.c_str(), document.size(), dest_dmr);
1813 if (!(size > 0))
return;
1817 if (!dest_dmr)
throw InternalErr(__FILE__, __LINE__,
"DMR object is null");
1820 push_state(parser_start);
1821 context = xmlCreatePushParserCtxt(&dmrpp_sax_parser,
this, buffer, size,
"stream");
1822 context->validate =
true;
1825 xmlParseChunk(context, buffer, 0, 1);
virtual BESCatalog * default_catalog() const
The the default catalog.
const std::string & get_root_dir() const
Get the root directory of the catalog.
virtual BESCatalogUtils * get_catalog_utils() const
Get a pointer to the utilities, customized for this catalog.
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
static std::ostream * GetStrm()
return the debug stream
exception thrown if internal error encountered
static std::string assemblePath(const std::string &firstPart, const std::string &secondPart, bool leadingSlash=false, bool trailingSlash=false)
Assemble path fragments making sure that they are separated by a single '/' character.
void intern(std::istream &f, libdap::DMR *dest_dmr)
static void dmr_get_cdata(void *parser, const xmlChar *value, int len)
static void dmr_ignoreable_whitespace(void *parser, const xmlChar *ch, int len)
static void dmr_end_document(void *parser)
static void dmr_get_characters(void *parser, const xmlChar *ch, int len)
static void dmr_fatal_error(void *parser, const char *msg,...)
static xmlEntityPtr dmr_get_entity(void *parser, const xmlChar *name)
static void dmr_start_document(void *parser)