|
Packit |
a4aae4 |
// -*- mode: c++; c-basic-offset:4 -*-
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
|
|
Packit |
a4aae4 |
// Access Protocol.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Copyright (c) 2012 OPeNDAP, Inc.
|
|
Packit |
a4aae4 |
// Author: James Gallagher <jgallagher@opendap.org>
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is free software; you can redistribute it and/or
|
|
Packit |
a4aae4 |
// modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License as published by the Free Software Foundation; either
|
|
Packit |
a4aae4 |
// version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is distributed in the hope that it will be useful,
|
|
Packit |
a4aae4 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4aae4 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4aae4 |
// Lesser General Public License for more details.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License along with this library; if not, write to the Free Software
|
|
Packit |
a4aae4 |
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
//#define DODS_DEBUG 1
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <iostream>
|
|
Packit |
a4aae4 |
#include <sstream>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <cstring>
|
|
Packit |
a4aae4 |
#include <cstdarg>
|
|
Packit |
a4aae4 |
#include <cassert>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <libxml/parserInternals.h>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "DMR.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "BaseType.h"
|
|
Packit |
a4aae4 |
#include "Array.h"
|
|
Packit |
a4aae4 |
#include "D4Group.h"
|
|
Packit |
a4aae4 |
#include "D4Attributes.h"
|
|
Packit |
a4aae4 |
#include "D4Maps.h"
|
|
Packit |
a4aae4 |
#include "D4Enum.h"
|
|
Packit |
a4aae4 |
#include "D4BaseTypeFactory.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "DapXmlNamespaces.h"
|
|
Packit |
a4aae4 |
#include "D4ParserSax2.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static const char *states[] = {
|
|
Packit |
a4aae4 |
"parser_start",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"inside_dataset",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// inside_group is the state just after parsing the start of a Group
|
|
Packit |
a4aae4 |
// element.
|
|
Packit |
a4aae4 |
"inside_group",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"inside_attribute_container",
|
|
Packit |
a4aae4 |
"inside_attribute",
|
|
Packit |
a4aae4 |
"inside_attribute_value",
|
|
Packit |
a4aae4 |
"inside_other_xml_attribute",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"inside_enum_def",
|
|
Packit |
a4aae4 |
"inside_enum_const",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"inside_dim_def",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This covers Byte, ..., Url, Opaque
|
|
Packit |
a4aae4 |
"inside_simple_type",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// "inside_array",
|
|
Packit |
a4aae4 |
"inside_dim",
|
|
Packit |
a4aae4 |
"inside_map",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"inside_constructor",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"not_dap4_element",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"parser_unknown",
|
|
Packit |
a4aae4 |
"parser_error",
|
|
Packit |
a4aae4 |
"parser_fatal_error",
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
"parser_end"
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static bool is_not(const char *name, const char *tag)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return strcmp(name, tag) != 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Return the current Enumeration definition
|
|
Packit |
a4aae4 |
* Allocate the Enumeration definition if needed and return it. Once parsing the current
|
|
Packit |
a4aae4 |
* enumeration definition is complete, the pointer allocated/returned by this method will
|
|
Packit |
a4aae4 |
* be copied into the current Group and this internal storage will be 'reset' using
|
|
Packit |
a4aae4 |
* clear_enum_def().
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @return
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
D4EnumDef *
|
|
Packit |
a4aae4 |
D4ParserSax2::enum_def()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!d_enum_def) d_enum_def = new D4EnumDef;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return d_enum_def;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Return the current Dimension definition
|
|
Packit |
a4aae4 |
* Allocate the Dimension definition if needed and return it.
|
|
Packit |
a4aae4 |
* @see enum_def() for an explanation of how this is used by the parser.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @return
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
D4Dimension *
|
|
Packit |
a4aae4 |
D4ParserSax2::dim_def() {
|
|
Packit |
a4aae4 |
if (!d_dim_def) d_dim_def = new D4Dimension;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return d_dim_def;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Dump XML attributes to local store so they can be easily manipulated.
|
|
Packit |
a4aae4 |
* XML attribute names are always folded to lower case.
|
|
Packit |
a4aae4 |
* @param attributes The XML attribute array
|
|
Packit |
a4aae4 |
* @param nb_attributes The number of attributes
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::transfer_xml_attrs(const xmlChar **attributes, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!xml_attrs.empty())
|
|
Packit |
a4aae4 |
xml_attrs.clear(); // erase old attributes
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Make a value using the attribute name and the prefix, namespace URI
|
|
Packit |
a4aae4 |
// and the value. The prefix might be null.
|
|
Packit |
a4aae4 |
unsigned int index = 0;
|
|
Packit |
a4aae4 |
for (int i = 0; i < nb_attributes; ++i, index += 5) {
|
|
Packit |
a4aae4 |
xml_attrs.insert(map<string, XMLAttribute>::value_type(string((const char *)attributes[index]),
|
|
Packit |
a4aae4 |
XMLAttribute(attributes + index + 1)));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG(cerr << "XML Attribute '" << (const char *)attributes[index] << "': "
|
|
Packit |
a4aae4 |
<< xml_attrs[(const char *)attributes[index]].value << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Transfer the XML namespaces to the local store so they can be manipulated
|
|
Packit |
a4aae4 |
* more easily.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param namespaces Array of xmlChar*
|
|
Packit |
a4aae4 |
* @param nb_namespaces The number of namespaces in the array.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::transfer_xml_ns(const xmlChar **namespaces, int nb_namespaces)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// make a value with the prefix and namespace URI. The prefix might be null.
|
|
Packit |
a4aae4 |
for (int i = 0; i < nb_namespaces; ++i) {
|
|
Packit |
a4aae4 |
namespace_table.insert(map<string, string>::value_type(namespaces[i * 2] != 0 ? (const char *)namespaces[i * 2] : "",
|
|
Packit |
a4aae4 |
(const char *)namespaces[i * 2 + 1]));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Is a required XML attribute present? Attribute names are always lower case.
|
|
Packit |
a4aae4 |
* @note To use this method, first call transfer_xml_attrs.
|
|
Packit |
a4aae4 |
* @param attr The XML attribute
|
|
Packit |
a4aae4 |
* @return True if the XML attribute was present in the last tag, otherwise
|
|
Packit |
a4aae4 |
* it sets the global error state and returns false.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool D4ParserSax2::check_required_attribute(const string & attr)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (xml_attrs.find(attr) == xml_attrs.end()) {
|
|
Packit |
a4aae4 |
dmr_error(this, "Required attribute '%s' not found.", attr.c_str());
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Is a XML attribute present? Attribute names are always lower case.
|
|
Packit |
a4aae4 |
* @note To use this method, first call transfer_xml_attrs.
|
|
Packit |
a4aae4 |
* @param attr The XML attribute
|
|
Packit |
a4aae4 |
* @return True if the XML attribute was present in the last/current tag,
|
|
Packit |
a4aae4 |
* false otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool D4ParserSax2::check_attribute(const string & attr)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return (xml_attrs.find(attr) != xml_attrs.end());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bool D4ParserSax2::process_dimension_def(const char *name, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (is_not(name, "Dimension"))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!(check_required_attribute("name") && check_required_attribute("size"))) {
|
|
Packit |
a4aae4 |
dmr_error(this, "The required attribute 'name' or 'size' was missing from a Dimension element.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This getter (dim_def) allocates a new object if needed.
|
|
Packit |
a4aae4 |
dim_def()->set_name(xml_attrs["name"].value);
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
dim_def()->set_size(xml_attrs["size"].value);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error &e) {
|
|
Packit |
a4aae4 |
dmr_error(this, e.get_error_message().c_str());
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Process a Dim element.
|
|
Packit |
a4aae4 |
* If a Dim element is found, the current variable is an Array. If the BaseType
|
|
Packit |
a4aae4 |
* on the TOS is not already an Array, make it one. Append the dimension
|
|
Packit |
a4aae4 |
* information to the Array variable on the TOS.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @note Dim elements can have two attributes: name or size. The latter defines
|
|
Packit |
a4aae4 |
* an 'anonymous' dimension (one without a name that does not reference a
|
|
Packit |
a4aae4 |
* shared dimension object. If the \c name attribute is used, then the shared
|
|
Packit |
a4aae4 |
* dimension used is the one defined by the enclosing group or found using the
|
|
Packit |
a4aae4 |
* fully qualified name. The \name and \c size attributes are mutually exclusive.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param name XML element name; must be Dim
|
|
Packit |
a4aae4 |
* @param attrs XML Attributes
|
|
Packit |
a4aae4 |
* @param nb_attributes The number of XML Attributes
|
|
Packit |
a4aae4 |
* @return True if the element is a Dim, false otherwise.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
bool D4ParserSax2::process_dimension(const char *name, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (is_not(name, "Dim"))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (check_attribute("size") && check_attribute("name")) {
|
|
Packit |
a4aae4 |
dmr_error(this, "Only one of 'size' and 'name' are allowed in a Dim element, but both were used.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
if (!(check_attribute("size") || check_attribute("name"))) {
|
|
Packit |
a4aae4 |
dmr_error(this, "Either 'size' or 'name' must be used in a Dim element.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!top_basetype()->is_vector_type()) {
|
|
Packit |
a4aae4 |
// Make the top BaseType* an array
|
|
Packit |
a4aae4 |
BaseType *b = top_basetype();
|
|
Packit |
a4aae4 |
pop_basetype();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array *a = static_cast<Array*>(dmr()->factory()->NewVariable(dods_array_c, b->name()));
|
|
Packit |
a4aae4 |
a->set_is_dap4(true);
|
|
Packit |
a4aae4 |
a->add_var_nocopy(b);
|
|
Packit |
a4aae4 |
a->set_attributes_nocopy(b->attributes());
|
|
Packit |
a4aae4 |
// trick: instead of popping b's attributes, copying them and then pushing
|
|
Packit |
a4aae4 |
// a's copy, just move the pointer (but make sure there's only one object that
|
|
Packit |
a4aae4 |
// references that pointer).
|
|
Packit |
a4aae4 |
b->set_attributes_nocopy(0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
push_basetype(a);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
assert(top_basetype()->is_vector_type());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array *a = static_cast<Array*>(top_basetype());
|
|
Packit |
a4aae4 |
if (check_attribute("size")) {
|
|
Packit |
a4aae4 |
a->append_dim(atoi(xml_attrs["size"].value.c_str())); // low budget code for now. jhrg 8/20/13
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (check_attribute("name")) {
|
|
Packit |
a4aae4 |
string name = xml_attrs["name"].value;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4Dimension *dim = 0;
|
|
Packit |
a4aae4 |
if (name[0] == '/') // lookup the Dimension in the root group
|
|
Packit |
a4aae4 |
dim = dmr()->root()->find_dim(name);
|
|
Packit |
a4aae4 |
else // get enclosing Group and lookup Dimension there
|
|
Packit |
a4aae4 |
dim = top_group()->find_dim(name);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!dim)
|
|
Packit |
a4aae4 |
throw Error("The dimension '" + name + "' was not found while parsing the variable '" + a->name() + "'.");
|
|
Packit |
a4aae4 |
a->append_dim(dim);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bool D4ParserSax2::process_map(const char *name, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (is_not(name, "Map"))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!check_attribute("name")) {
|
|
Packit |
a4aae4 |
dmr_error(this, "The 'name' attribute must be used in a Map element.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!top_basetype()->is_vector_type()) {
|
|
Packit |
a4aae4 |
// Make the top BaseType* an array
|
|
Packit |
a4aae4 |
BaseType *b = top_basetype();
|
|
Packit |
a4aae4 |
pop_basetype();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array *a = static_cast<Array*>(dmr()->factory()->NewVariable(dods_array_c, b->name()));
|
|
Packit |
a4aae4 |
a->set_is_dap4(true);
|
|
Packit |
a4aae4 |
a->add_var_nocopy(b);
|
|
Packit |
a4aae4 |
a->set_attributes_nocopy(b->attributes());
|
|
Packit |
a4aae4 |
// trick: instead of popping b's attributes, copying them and then pushing
|
|
Packit |
a4aae4 |
// a's copy, just move the pointer (but make sure there's only one object that
|
|
Packit |
a4aae4 |
// references that pointer).
|
|
Packit |
a4aae4 |
b->set_attributes_nocopy(0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
push_basetype(a);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
assert(top_basetype()->is_vector_type());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array *a = static_cast<Array*>(top_basetype());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string map_name = xml_attrs["name"].value;
|
|
Packit |
a4aae4 |
if (xml_attrs["name"].value[0] != '/')
|
|
Packit |
a4aae4 |
map_name = top_group()->FQN() + map_name;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Array *map_source = 0; // The array variable that holds the data for the Map
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (map_name[0] == '/') // lookup the Map in the root group
|
|
Packit |
a4aae4 |
map_source = dmr()->root()->find_map_source(map_name);
|
|
Packit |
a4aae4 |
else // get enclosing Group and lookup Map there
|
|
Packit |
a4aae4 |
map_source = top_group()->find_map_source(map_name);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Change: If the parser is in 'strict' mode (the default) and the Array named by
|
|
Packit |
a4aae4 |
// the Map cannot be fond, it is an error. If 'strict' mode is false (permissive
|
|
Packit |
a4aae4 |
// mode), then this is not an error. However, the Array referenced by the Map will
|
|
Packit |
a4aae4 |
// be null. This is a change in the parser's behavior to accommodate requests for
|
|
Packit |
a4aae4 |
// Arrays that include Maps that do not also include the Map(s) in the request.
|
|
Packit |
a4aae4 |
// See https://opendap.atlassian.net/browse/HYRAX-98. jhrg 4/13/16
|
|
Packit |
a4aae4 |
if (!map_source && d_strict)
|
|
Packit |
a4aae4 |
throw Error("The Map '" + map_name + "' was not found while parsing the variable '" + a->name() + "'.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
a->maps()->add_map(new D4Map(map_name, map_source));
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
bool D4ParserSax2::process_group(const char *name, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (is_not(name, "Group"))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!check_required_attribute("name")) {
|
|
Packit |
a4aae4 |
dmr_error(this, "The required attribute 'name' was missing from a Group element.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *btp = dmr()->factory()->NewVariable(dods_group_c, xml_attrs["name"].value);
|
|
Packit |
a4aae4 |
if (!btp) {
|
|
Packit |
a4aae4 |
dmr_fatal_error(this, "Could not instantiate the Group '%s'.", xml_attrs["name"].value.c_str());
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4Group *grp = static_cast<D4Group*>(btp);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Need to set this to get the D4Attribute behavior in the type classes
|
|
Packit |
a4aae4 |
// shared between DAP2 and DAP4. jhrg 4/18/13
|
|
Packit |
a4aae4 |
grp->set_is_dap4(true);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// link it up and change the current group
|
|
Packit |
a4aae4 |
D4Group *parent = top_group();
|
|
Packit |
a4aae4 |
if (!parent) {
|
|
Packit |
a4aae4 |
dmr_fatal_error(this, "No Group on the Group stack.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
grp->set_parent(parent);
|
|
Packit |
a4aae4 |
parent->add_group_nocopy(grp);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
push_group(grp);
|
|
Packit |
a4aae4 |
push_attributes(grp->attributes());
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Check to see if the current tag is either an \c Attribute or an \c Alias
|
|
Packit |
a4aae4 |
start tag. This method is a glorified macro...
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param name The start tag name
|
|
Packit |
a4aae4 |
@param attrs The tag's XML attributes
|
|
Packit |
a4aae4 |
@return True if the tag was an \c Attribute or \c Alias tag */
|
|
Packit |
a4aae4 |
inline bool D4ParserSax2::process_attribute(const char *name, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (is_not(name, "Attribute"))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// These methods set the state to parser_error if a problem is found.
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// add error
|
|
Packit |
a4aae4 |
if (!(check_required_attribute(string("name")) && check_required_attribute(string("type")))) {
|
|
Packit |
a4aae4 |
dmr_error(this, "The required attribute 'name' or 'type' was missing from an Attribute element.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (xml_attrs["type"].value == "Container") {
|
|
Packit |
a4aae4 |
push_state(inside_attribute_container);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG(cerr << "Pushing attribute container " << xml_attrs["name"].value << endl);
|
|
Packit |
a4aae4 |
D4Attribute *child = new D4Attribute(xml_attrs["name"].value, attr_container_c);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
D4Attributes *tos = top_attributes();
|
|
Packit |
a4aae4 |
// add return
|
|
Packit |
a4aae4 |
if (!tos) {
|
|
Packit |
a4aae4 |
delete child;
|
|
Packit |
a4aae4 |
dmr_fatal_error(this, "Expected an Attribute container on the top of the attribute stack.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
tos->add_attribute_nocopy(child);
|
|
Packit |
a4aae4 |
push_attributes(child->attributes());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (xml_attrs["type"].value == "OtherXML") {
|
|
Packit |
a4aae4 |
push_state(inside_other_xml_attribute);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dods_attr_name = xml_attrs["name"].value;
|
|
Packit |
a4aae4 |
dods_attr_type = xml_attrs["type"].value;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
push_state(inside_attribute);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dods_attr_name = xml_attrs["name"].value;
|
|
Packit |
a4aae4 |
dods_attr_type = xml_attrs["type"].value;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Check to see if the current tag is an \c Enumeration start tag.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param name The start tag name
|
|
Packit |
a4aae4 |
@param attrs The tag's XML attributes
|
|
Packit |
a4aae4 |
@return True if the tag was an \c Enumeration */
|
|
Packit |
a4aae4 |
inline bool D4ParserSax2::process_enum_def(const char *name, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (is_not(name, "Enumeration"))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!(check_required_attribute("name") && check_required_attribute("basetype"))) {
|
|
Packit |
a4aae4 |
dmr_error(this, "The required attribute 'name' or 'basetype' was missing from an Enumeration element.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Type t = get_type(xml_attrs["basetype"].value.c_str());
|
|
Packit |
a4aae4 |
if (!is_integer_type(t)) {
|
|
Packit |
a4aae4 |
dmr_error(this, "The Enumeration '%s' must have an integer type, instead the type '%s' was used.",
|
|
Packit |
a4aae4 |
xml_attrs["name"].value.c_str(), xml_attrs["basetype"].value.c_str());
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This getter allocates a new object if needed.
|
|
Packit |
a4aae4 |
string enum_def_path = xml_attrs["name"].value;
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
// Use FQNs when things are referenced, not when they are defined
|
|
Packit |
a4aae4 |
if (xml_attrs["name"].value[0] != '/')
|
|
Packit |
a4aae4 |
enum_def_path = top_group()->FQN() + enum_def_path;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
enum_def()->set_name(enum_def_path);
|
|
Packit |
a4aae4 |
enum_def()->set_type(t);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
inline bool D4ParserSax2::process_enum_const(const char *name, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (is_not(name, "EnumConst"))
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// These methods set the state to parser_error if a problem is found.
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!(check_required_attribute("name") && check_required_attribute("value"))) {
|
|
Packit |
a4aae4 |
dmr_error(this, "The required attribute 'name' or 'value' was missing from an EnumConst element.");
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
istringstream iss(xml_attrs["value"].value);
|
|
Packit |
a4aae4 |
long long value = 0;
|
|
Packit |
a4aae4 |
iss >> skipws >> value;
|
|
Packit |
a4aae4 |
if (iss.fail() || iss.bad()) {
|
|
Packit |
a4aae4 |
dmr_error(this, "Expected an integer value for an Enumeration constant, got '%s' instead.",
|
|
Packit |
a4aae4 |
xml_attrs["value"].value.c_str());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (!enum_def()->is_valid_enum_value(value)) {
|
|
Packit |
a4aae4 |
dmr_error(this, "In an Enumeration constant, the value '%s' cannot fit in a variable of type '%s'.",
|
|
Packit |
a4aae4 |
xml_attrs["value"].value.c_str(), D4type_name(d_enum_def->type()).c_str());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// unfortunate choice of names... args are 'label' and 'value'
|
|
Packit |
a4aae4 |
enum_def()->add_value(xml_attrs["name"].value, value);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Check to see if the current element is the start of a variable declaration.
|
|
Packit |
a4aae4 |
If so, process it. A glorified macro...
|
|
Packit |
a4aae4 |
@param name The start element name
|
|
Packit |
a4aae4 |
@param attrs The element's XML attributes
|
|
Packit |
a4aae4 |
@return True if the element was a variable */
|
|
Packit |
a4aae4 |
inline bool D4ParserSax2::process_variable(const char *name, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
Type t = get_type(name);
|
|
Packit |
a4aae4 |
if (is_simple_type(t)) {
|
|
Packit |
a4aae4 |
process_variable_helper(t, inside_simple_type, attrs, nb_attributes);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
switch(t) {
|
|
Packit |
a4aae4 |
case dods_structure_c:
|
|
Packit |
a4aae4 |
process_variable_helper(t, inside_constructor, attrs, nb_attributes);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case dods_sequence_c:
|
|
Packit |
a4aae4 |
process_variable_helper(t, inside_constructor, attrs, nb_attributes);
|
|
Packit |
a4aae4 |
return true;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
return false;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Given that a tag which opens a variable declaration has just been read,
|
|
Packit |
a4aae4 |
create the variable. Once created, push the variable onto the stack of
|
|
Packit |
a4aae4 |
variables, push that variable's attribute table onto the attribute table
|
|
Packit |
a4aae4 |
stack and update the state of the parser.
|
|
Packit |
a4aae4 |
@param t The type of variable to create.
|
|
Packit |
a4aae4 |
@param s The next state of the parser (e.g., inside_simple_type, ...)
|
|
Packit |
a4aae4 |
@param attrs the attributes read with the tag */
|
|
Packit |
a4aae4 |
void D4ParserSax2::process_variable_helper(Type t, ParseState s, const xmlChar **attrs, int nb_attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
transfer_xml_attrs(attrs, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (check_required_attribute("name")) {
|
|
Packit |
a4aae4 |
BaseType *btp = dmr()->factory()->NewVariable(t, xml_attrs["name"].value);
|
|
Packit |
a4aae4 |
if (!btp) {
|
|
Packit |
a4aae4 |
dmr_fatal_error(this, "Could not instantiate the variable '%s'.", xml_attrs["name"].value.c_str());
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if ((t == dods_enum_c) && check_required_attribute("enum")) {
|
|
Packit |
a4aae4 |
D4EnumDef *enum_def = 0;
|
|
Packit |
a4aae4 |
string enum_path = xml_attrs["enum"].value;
|
|
Packit |
a4aae4 |
if (enum_path[0] == '/')
|
|
Packit |
a4aae4 |
enum_def = dmr()->root()->find_enum_def(enum_path);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
enum_def = top_group()->find_enum_def(enum_path);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!enum_def)
|
|
Packit |
a4aae4 |
dmr_fatal_error(this, "Could not find the Enumeration definition '%s'.", enum_path.c_str());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static_cast<D4Enum*>(btp)->set_enumeration(enum_def);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
btp->set_is_dap4(true); // see comment above
|
|
Packit |
a4aae4 |
push_basetype(btp);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
push_attributes(btp->attributes());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
push_state(s);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @name SAX Parser Callbacks
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
These methods are declared static in the class header. This gives them C
|
|
Packit |
a4aae4 |
linkage which allows them to be used as callbacks by the SAX parser
|
|
Packit |
a4aae4 |
engine. */
|
|
Packit |
a4aae4 |
//@{
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Initialize the SAX parser state object. This object is passed to each
|
|
Packit |
a4aae4 |
callback as a void pointer. The initial state is parser_start.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param p The SAX parser */
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_start_document(void * p)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
parser->d_error_msg = "";
|
|
Packit |
a4aae4 |
parser->char_data = "";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Set this in intern_helper so that the loop test for the parser_end
|
|
Packit |
a4aae4 |
// state works for the first iteration. It seems like XMLParseChunk calls this
|
|
Packit |
a4aae4 |
// function on it's first run. jhrg 9/16/13
|
|
Packit |
a4aae4 |
// parser->push_state(parser_start);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->push_attributes(parser->dmr()->root()->attributes());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "Parser start state: " << states[parser->get_state()] << endl;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Clean up after finishing a parse.
|
|
Packit |
a4aae4 |
@param p The SAX parser */
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_end_document(void * p)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "Parser end state: " << states[parser->get_state()] << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->get_state() != parser_end)
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "The document contained unbalanced tags.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If we've found any sort of error, don't make the DMR; intern() will
|
|
Packit |
a4aae4 |
// take care of the error.
|
|
Packit |
a4aae4 |
if (parser->get_state() == parser_error || parser->get_state() == parser_fatal_error)
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!parser->empty_basetype() || parser->empty_group())
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "The document did not contain a valid root Group or contained unbalanced tags.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_group(); // leave the stack 'clean'
|
|
Packit |
a4aae4 |
parser->pop_attributes();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Callback run when libxml2 reads the start of an element
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param p Pointer to the parser object
|
|
Packit |
a4aae4 |
* @param l Localname of the element
|
|
Packit |
a4aae4 |
* @param prefix Namespace prefix of the element
|
|
Packit |
a4aae4 |
* @param URI the Element namespace name if available
|
|
Packit |
a4aae4 |
* @param nb_namespaces Number of namespace definitions on that node
|
|
Packit |
a4aae4 |
* @param namespaces Pointer to the array of prefix/URI pairs namespace definitions
|
|
Packit |
a4aae4 |
* @param nb_attributes The number of attributes on that node
|
|
Packit |
a4aae4 |
* @param nb_defaulted The number of defaulted attributes. The defaulted ones are at the end of the array
|
|
Packit |
a4aae4 |
* @param attributes Pointer to the array of (localname/prefix/URI/value/end) attribute values.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_start_element(void *p, const xmlChar *l, const xmlChar *prefix, const xmlChar *URI,
|
|
Packit |
a4aae4 |
int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int /*nb_defaulted*/,
|
|
Packit |
a4aae4 |
const xmlChar **attributes)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
const char *localname = (const char *) l;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "Start element " << localname << " prefix: "<< (prefix?(char *)prefix:"null") << " ns: "<< (URI?(char *)URI:"null")
|
|
Packit |
a4aae4 |
<< " (state: " << states[parser->get_state()] << ")" << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if(parser->get_state() != parser_error){
|
|
Packit |
a4aae4 |
string dap4_ns_name = DapXmlNamspaces::getDapNamespaceString(DAP_4_0);
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "dap4_ns_name: " << dap4_ns_name << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string this_element_ns_name = (URI != 0) ? ((char *)URI) : "";
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "this_element_ns_name: " << this_element_ns_name << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if(this_element_ns_name.compare(dap4_ns_name)){
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "Start of non DAP4 element: " << localname << " detected." << endl;
|
|
Packit |
a4aae4 |
parser->push_state(not_dap4_element);
|
|
Packit |
a4aae4 |
// return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case parser_start:
|
|
Packit |
a4aae4 |
if (is_not(localname, "Dataset"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected DMR to start with a Dataset element; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->root_ns = URI ? (const char *) URI : "";
|
|
Packit |
a4aae4 |
parser->transfer_xml_attrs(attributes, nb_attributes);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->check_required_attribute(string("name")))
|
|
Packit |
a4aae4 |
parser->dmr()->set_name(parser->xml_attrs["name"].value);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->check_attribute("dapVersion"))
|
|
Packit |
a4aae4 |
parser->dmr()->set_dap_version(parser->xml_attrs["dapVersion"].value);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->check_attribute("dmrVersion"))
|
|
Packit |
a4aae4 |
parser->dmr()->set_dmr_version(parser->xml_attrs["dmrVersion"].value);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->check_attribute("base"))
|
|
Packit |
a4aae4 |
parser->dmr()->set_request_xml_base(parser->xml_attrs["base"].value);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!parser->root_ns.empty())
|
|
Packit |
a4aae4 |
parser->dmr()->set_namespace(parser->root_ns);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Push the root Group on the stack
|
|
Packit |
a4aae4 |
parser->push_group(parser->dmr()->root());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->push_state(inside_dataset);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Both inside dataset and inside group can have the same stuff.
|
|
Packit |
a4aae4 |
// The difference is that the Dataset holds the root group, which
|
|
Packit |
a4aae4 |
// must be present; other groups are optional
|
|
Packit |
a4aae4 |
case inside_dataset:
|
|
Packit |
a4aae4 |
case inside_group:
|
|
Packit |
a4aae4 |
if (parser->process_enum_def(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
parser->push_state(inside_enum_def);
|
|
Packit |
a4aae4 |
else if (parser->process_dimension_def(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
parser->push_state(inside_dim_def);
|
|
Packit |
a4aae4 |
else if (parser->process_group(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
parser->push_state(inside_group);
|
|
Packit |
a4aae4 |
else if (parser->process_variable(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
// This will push either inside_simple_type or inside_structure
|
|
Packit |
a4aae4 |
// onto the parser state stack.
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (parser->process_attribute(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
// This will push either inside_attribute, inside_attribute_container
|
|
Packit |
a4aae4 |
// or inside_otherxml_attribute onto the parser state stack
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an Attribute, Enumeration, Dimension, Group or variable element; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute_container:
|
|
Packit |
a4aae4 |
if (parser->process_attribute(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an Attribute element; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute:
|
|
Packit |
a4aae4 |
if (parser->process_attribute(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (strcmp(localname, "Value") == 0)
|
|
Packit |
a4aae4 |
parser->push_state(inside_attribute_value);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
dmr_error(parser, "Expected an 'Attribute' or 'Value' element; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute_value:
|
|
Packit |
a4aae4 |
// Attribute values are processed by the end element code.
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute:
|
|
Packit |
a4aae4 |
parser->other_xml_depth++;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Accumulate the elements here
|
|
Packit |
a4aae4 |
parser->other_xml.append("<");
|
|
Packit |
a4aae4 |
if (prefix) {
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *) prefix);
|
|
Packit |
a4aae4 |
parser->other_xml.append(":");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml.append(localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (nb_namespaces != 0) {
|
|
Packit |
a4aae4 |
parser->transfer_xml_ns(namespaces, nb_namespaces);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
for (map<string, string>::iterator i = parser->namespace_table.begin();
|
|
Packit |
a4aae4 |
i != parser->namespace_table.end(); ++i) {
|
|
Packit |
a4aae4 |
parser->other_xml.append(" xmlns");
|
|
Packit |
a4aae4 |
if (!i->first.empty()) {
|
|
Packit |
a4aae4 |
parser->other_xml.append(":");
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->first);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml.append("=\"");
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->second);
|
|
Packit |
a4aae4 |
parser->other_xml.append("\"");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (nb_attributes != 0) {
|
|
Packit |
a4aae4 |
parser->transfer_xml_attrs(attributes, nb_attributes);
|
|
Packit |
a4aae4 |
for (XMLAttrMap::iterator i = parser->xml_attr_begin(); i != parser->xml_attr_end(); ++i) {
|
|
Packit |
a4aae4 |
parser->other_xml.append(" ");
|
|
Packit |
a4aae4 |
if (!i->second.prefix.empty()) {
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->second.prefix);
|
|
Packit |
a4aae4 |
parser->other_xml.append(":");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->first);
|
|
Packit |
a4aae4 |
parser->other_xml.append("=\"");
|
|
Packit |
a4aae4 |
parser->other_xml.append(i->second.value);
|
|
Packit |
a4aae4 |
parser->other_xml.append("\"");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->other_xml.append(">");
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_enum_def:
|
|
Packit |
a4aae4 |
// process an EnumConst element
|
|
Packit |
a4aae4 |
if (parser->process_enum_const(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
parser->push_state(inside_enum_const);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
dmr_error(parser, "Expected an 'EnumConst' element; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_enum_const:
|
|
Packit |
a4aae4 |
// No content; nothing to do
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_dim_def:
|
|
Packit |
a4aae4 |
// No content; nothing to do
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
case inside_dimension:
|
|
Packit |
a4aae4 |
// No content.
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
case inside_dim:
|
|
Packit |
a4aae4 |
// No content.
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_map:
|
|
Packit |
a4aae4 |
// No content.
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_simple_type:
|
|
Packit |
a4aae4 |
if (parser->process_attribute(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (parser->process_dimension(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
parser->push_state(inside_dim);
|
|
Packit |
a4aae4 |
else if (parser->process_map(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
parser->push_state(inside_map);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
dmr_error(parser, "Expected an 'Attribute', 'Dim' or 'Map' element; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_constructor:
|
|
Packit |
a4aae4 |
if (parser->process_variable(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
// This will push either inside_simple_type or inside_structure
|
|
Packit |
a4aae4 |
// onto the parser state stack.
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (parser->process_attribute(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
else if (parser->process_dimension(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
parser->push_state(inside_dim);
|
|
Packit |
a4aae4 |
else if (parser->process_map(localname, attributes, nb_attributes))
|
|
Packit |
a4aae4 |
parser->push_state(inside_map);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an Attribute, Dim, Map or variable element; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case not_dap4_element:
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "Inside non DAP4 element. localname: " << localname << endl;
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_unknown:
|
|
Packit |
a4aae4 |
// FIXME?
|
|
Packit |
a4aae4 |
// *** Never used? If so remove/error
|
|
Packit |
a4aae4 |
parser->push_state(parser_unknown);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_error:
|
|
Packit |
a4aae4 |
case parser_fatal_error:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_end:
|
|
Packit |
a4aae4 |
// FIXME Error?
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "Start element exit state: " << states[parser->get_state()] << endl;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_end_element(void *p, const xmlChar *l, const xmlChar *prefix, const xmlChar *URI)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
const char *localname = (const char *) l;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->debug())
|
|
Packit |
a4aae4 |
cerr << "End element " << localname << " (state " << states[parser->get_state()] << ")" << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case parser_start:
|
|
Packit |
a4aae4 |
dmr_fatal_error(parser, "Unexpected state, inside start state while processing element '%s'.", localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_dataset:
|
|
Packit |
a4aae4 |
if (is_not(localname, "Dataset"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end Dataset tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
if (parser->get_state() != parser_start)
|
|
Packit |
a4aae4 |
dmr_fatal_error(parser, "Unexpected state, expected start state.");
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
parser->push_state(parser_end);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_group: {
|
|
Packit |
a4aae4 |
if (is_not(localname, "Group"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end tag for a Group; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!parser->empty_basetype() || parser->empty_group())
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser,
|
|
Packit |
a4aae4 |
"The document did not contain a valid root Group or contained unbalanced tags.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_group();
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute_container:
|
|
Packit |
a4aae4 |
if (is_not(localname, "Attribute"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end Attribute tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
parser->pop_attributes();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute:
|
|
Packit |
a4aae4 |
if (is_not(localname, "Attribute"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end Attribute tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_attribute_value: {
|
|
Packit |
a4aae4 |
if (is_not(localname, "Value"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end value tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The old code added more values using the name and type as
|
|
Packit |
a4aae4 |
// indexes to find the correct attribute. Use get() for that
|
|
Packit |
a4aae4 |
// now. Or fix this code to keep a pointer to the to attribute...
|
|
Packit |
a4aae4 |
D4Attributes *attrs = parser->top_attributes();
|
|
Packit |
a4aae4 |
D4Attribute *attr = attrs->get(parser->dods_attr_name);
|
|
Packit |
a4aae4 |
if (!attr) {
|
|
Packit |
a4aae4 |
attr = new D4Attribute(parser->dods_attr_name, StringToD4AttributeType(parser->dods_attr_type));
|
|
Packit |
a4aae4 |
attrs->add_attribute_nocopy(attr);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
attr->add_value(parser->char_data);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->char_data = ""; // Null this after use.
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute: {
|
|
Packit |
a4aae4 |
if (strcmp(localname, "Attribute") == 0 && parser->root_ns == (const char *) URI) {
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// The old code added more values using the name and type as
|
|
Packit |
a4aae4 |
// indexes to find the correct attribute. Use get() for that
|
|
Packit |
a4aae4 |
// now. Or fix this code to keep a pointer to the to attribute...
|
|
Packit |
a4aae4 |
D4Attributes *attrs = parser->top_attributes();
|
|
Packit |
a4aae4 |
D4Attribute *attr = attrs->get(parser->dods_attr_name);
|
|
Packit |
a4aae4 |
if (!attr) {
|
|
Packit |
a4aae4 |
attr = new D4Attribute(parser->dods_attr_name, StringToD4AttributeType(parser->dods_attr_type));
|
|
Packit |
a4aae4 |
attrs->add_attribute_nocopy(attr);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
attr->add_value(parser->other_xml);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->other_xml = ""; // Null this after use.
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
if (parser->other_xml_depth == 0) {
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an OtherXML attribute to end! Instead I found '%s'",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml_depth--;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->other_xml.append("</");
|
|
Packit |
a4aae4 |
if (prefix) {
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *) prefix);
|
|
Packit |
a4aae4 |
parser->other_xml.append(":");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
parser->other_xml.append(localname);
|
|
Packit |
a4aae4 |
parser->other_xml.append(">");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_enum_def:
|
|
Packit |
a4aae4 |
if (is_not(localname, "Enumeration"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end Enumeration tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
if (!parser->top_group())
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_fatal_error(parser,
|
|
Packit |
a4aae4 |
"Expected a Group to be the current item, while finishing up an Enumeration.");
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
// copy the pointer; not a deep copy
|
|
Packit |
a4aae4 |
parser->top_group()->enum_defs()->add_enum_nocopy(parser->enum_def());
|
|
Packit |
a4aae4 |
// Set the enum_def to null; next call to enum_def() will
|
|
Packit |
a4aae4 |
// allocate a new object
|
|
Packit |
a4aae4 |
parser->clear_enum_def();
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_enum_const:
|
|
Packit |
a4aae4 |
if (is_not(localname, "EnumConst"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end EnumConst tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_dim_def: {
|
|
Packit |
a4aae4 |
if (is_not(localname, "Dimension"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end Dimension tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!parser->top_group())
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser,
|
|
Packit |
a4aae4 |
"Expected a Group to be the current item, while finishing up an Dimension.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// FIXME Use the Group on the top of the group stack
|
|
Packit |
a4aae4 |
// copy the pointer; not a deep copy
|
|
Packit |
a4aae4 |
parser->top_group()->dims()->add_dim_nocopy(parser->dim_def());
|
|
Packit |
a4aae4 |
//parser->dmr()->root()->dims()->add_dim_nocopy(parser->dim_def());
|
|
Packit |
a4aae4 |
// Set the dim_def to null; next call to dim_def() will
|
|
Packit |
a4aae4 |
// allocate a new object. Calling 'clear' is important because
|
|
Packit |
a4aae4 |
// the cleanup method will free dim_def if it's not null and
|
|
Packit |
a4aae4 |
// we just copied the pointer in the add_dim_nocopy() call
|
|
Packit |
a4aae4 |
// above.
|
|
Packit |
a4aae4 |
parser->clear_dim_def();
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_simple_type:
|
|
Packit |
a4aae4 |
if (is_simple_type(get_type(localname))) {
|
|
Packit |
a4aae4 |
BaseType *btp = parser->top_basetype();
|
|
Packit |
a4aae4 |
parser->pop_basetype();
|
|
Packit |
a4aae4 |
parser->pop_attributes();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *parent = 0;
|
|
Packit |
a4aae4 |
if (!parser->empty_basetype())
|
|
Packit |
a4aae4 |
parent = parser->top_basetype();
|
|
Packit |
a4aae4 |
else if (!parser->empty_group())
|
|
Packit |
a4aae4 |
parent = parser->top_group();
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
dmr_fatal_error(parser, "Both the Variable and Groups stacks are empty while closing a %s element.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
delete btp;
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parent->type() == dods_array_c)
|
|
Packit |
a4aae4 |
static_cast<Array*>(parent)->prototype()->add_var_nocopy(btp);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
parent->add_var_nocopy(btp);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end tag for a simple type; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_dim:
|
|
Packit |
a4aae4 |
if (is_not(localname, "Dim"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_fatal_error(parser, "Expected an end Dim tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_map:
|
|
Packit |
a4aae4 |
if (is_not(localname, "Map"))
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_fatal_error(parser, "Expected an end Map tag; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_constructor: {
|
|
Packit |
a4aae4 |
if (strcmp(localname, "Structure") != 0 && strcmp(localname, "Sequence") != 0) {
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Expected an end tag for a constructor; found '%s' instead.", localname);
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *btp = parser->top_basetype();
|
|
Packit |
a4aae4 |
parser->pop_basetype();
|
|
Packit |
a4aae4 |
parser->pop_attributes();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
BaseType *parent = 0;
|
|
Packit |
a4aae4 |
if (!parser->empty_basetype())
|
|
Packit |
a4aae4 |
parent = parser->top_basetype();
|
|
Packit |
a4aae4 |
else if (!parser->empty_group())
|
|
Packit |
a4aae4 |
parent = parser->top_group();
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
dmr_fatal_error(parser, "Both the Variable and Groups stacks are empty while closing a %s element.",
|
|
Packit |
a4aae4 |
localname);
|
|
Packit |
a4aae4 |
delete btp;
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// TODO Why doesn't this code mirror the simple_var case and test
|
|
Packit |
a4aae4 |
// for the parent being an array? jhrg 10/13/13
|
|
Packit |
a4aae4 |
parent->add_var_nocopy(btp);
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case not_dap4_element:
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "End of non DAP4 element: " << localname << endl;
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_unknown:
|
|
Packit |
a4aae4 |
parser->pop_state();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_error:
|
|
Packit |
a4aae4 |
case parser_fatal_error:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_end:
|
|
Packit |
a4aae4 |
// FIXME Error?
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (parser->debug()) cerr << "End element exit state: " << states[parser->get_state()] << endl;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Process/accumulate character data. This may be called more than once for
|
|
Packit |
a4aae4 |
one logical clump of data. Only save character data when processing
|
|
Packit |
a4aae4 |
'value' elements; throw away all other characters. */
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_get_characters(void * p, const xmlChar * ch, int len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case inside_attribute_value:
|
|
Packit |
a4aae4 |
parser->char_data.append((const char *) (ch), len);
|
|
Packit |
a4aae4 |
DBG(cerr << "Characters: '" << parser->char_data << "'" << endl);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute:
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *) (ch), len);
|
|
Packit |
a4aae4 |
DBG(cerr << "Other XML Characters: '" << parser->other_xml << "'" << endl);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Read whitespace that's not really important for content. This is used
|
|
Packit |
a4aae4 |
only for the OtherXML attribute type to preserve formating of the XML.
|
|
Packit |
a4aae4 |
Doing so makes the attribute value far easier to read.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_ignoreable_whitespace(void *p, const xmlChar *ch, int len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute:
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *) (ch), len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get characters in a cdata block. DAP does not use CData, but XML in an
|
|
Packit |
a4aae4 |
OtherXML attribute (the value of that DAP attribute) might use it. This
|
|
Packit |
a4aae4 |
callback also allows CData when the parser is in the 'parser_unknown'
|
|
Packit |
a4aae4 |
state since some future DAP element might use it.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_get_cdata(void *p, const xmlChar *value, int len)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
switch (parser->get_state()) {
|
|
Packit |
a4aae4 |
case inside_other_xml_attribute:
|
|
Packit |
a4aae4 |
parser->other_xml.append((const char *) (value), len);
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
case parser_unknown:
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
default:
|
|
Packit |
a4aae4 |
D4ParserSax2::dmr_error(parser, "Found a CData block but none are allowed by DAP4.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Handle the standard XML entities.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param parser The SAX parser
|
|
Packit |
a4aae4 |
@param name The XML entity. */
|
|
Packit |
a4aae4 |
xmlEntityPtr D4ParserSax2::dmr_get_entity(void *, const xmlChar * name)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return xmlGetPredefinedEntity(name);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Process an XML fatal error. Note that SAX provides for warnings, errors
|
|
Packit |
a4aae4 |
and fatal errors. This code treats them all as fatal errors since there's
|
|
Packit |
a4aae4 |
typically no way to tell a user about the error since there's often no
|
|
Packit |
a4aae4 |
user interface for this software.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@note This static function does not throw an exception or otherwise
|
|
Packit |
a4aae4 |
alter flow of control except for altering the parser state.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param p The SAX parser
|
|
Packit |
a4aae4 |
@param msg A printf-style format string. */
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_fatal_error(void * p, const char *msg, ...)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
va_list args;
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->push_state(parser_fatal_error);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
va_start(args, msg);
|
|
Packit |
a4aae4 |
char str[1024];
|
|
Packit |
a4aae4 |
vsnprintf(str, 1024, msg, args);
|
|
Packit |
a4aae4 |
va_end(args);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int line = xmlSAX2GetLineNumber(parser->d_context);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!parser->d_error_msg.empty()) parser->d_error_msg += "\n";
|
|
Packit |
a4aae4 |
parser->d_error_msg += "At line " + long_to_string(line) + ": " + string(str);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void D4ParserSax2::dmr_error(void *p, const char *msg, ...)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
va_list args;
|
|
Packit |
a4aae4 |
D4ParserSax2 *parser = static_cast<D4ParserSax2*>(p);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
parser->push_state(parser_error);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
va_start(args, msg);
|
|
Packit |
a4aae4 |
char str[1024];
|
|
Packit |
a4aae4 |
vsnprintf(str, 1024, msg, args);
|
|
Packit |
a4aae4 |
va_end(args);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int line = xmlSAX2GetLineNumber(parser->d_context);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!parser->d_error_msg.empty()) parser->d_error_msg += "\n";
|
|
Packit |
a4aae4 |
parser->d_error_msg += "At line " + long_to_string(line) + ": " + string(str);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
//@}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Clean up after a parse operation. If the parser encountered an error,
|
|
Packit |
a4aae4 |
* throw either an Error or InternalErr object.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::cleanup_parse()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
bool wellFormed = d_context->wellFormed;
|
|
Packit |
a4aae4 |
bool valid = d_context->valid;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_context->sax = NULL;
|
|
Packit |
a4aae4 |
xmlFreeParserCtxt(d_context);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
delete d_enum_def;
|
|
Packit |
a4aae4 |
d_enum_def = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
delete d_dim_def;
|
|
Packit |
a4aae4 |
d_dim_def = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If there's an error, there may still be items on the stack at the
|
|
Packit |
a4aae4 |
// end of the parse.
|
|
Packit |
a4aae4 |
while (!btp_stack.empty()) {
|
|
Packit |
a4aae4 |
delete top_basetype();
|
|
Packit |
a4aae4 |
pop_basetype();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!wellFormed)
|
|
Packit |
a4aae4 |
throw Error("The DMR was not well formed. " + d_error_msg);
|
|
Packit |
a4aae4 |
else if (!valid)
|
|
Packit |
a4aae4 |
throw Error("The DMR was not valid." + d_error_msg);
|
|
Packit |
a4aae4 |
else if (get_state() == parser_error)
|
|
Packit |
a4aae4 |
throw Error(d_error_msg);
|
|
Packit |
a4aae4 |
else if (get_state() == parser_fatal_error)
|
|
Packit |
a4aae4 |
throw InternalErr(d_error_msg);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Read the DMR from a stream.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param f The input stream
|
|
Packit |
a4aae4 |
* @param dest_dmr Value-result parameter. Pass a pointer to a DMR in and
|
|
Packit |
a4aae4 |
* the information in the DMR will be added to it.
|
|
Packit |
a4aae4 |
* @param boundary If not empty, use this as the boundary tag in a MPM document
|
|
Packit |
a4aae4 |
* that marks the end of the part hat holds the DMR. Stop reading when the
|
|
Packit |
a4aae4 |
* boundary is found.
|
|
Packit |
a4aae4 |
* @param debug If true, ouput helpful debugging messages, False by default.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @exception Error Thrown if the XML document could not be read or parsed.
|
|
Packit |
a4aae4 |
* @exception InternalErr Thrown if an internal error is found.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::intern(istream &f, DMR *dest_dmr, bool debug)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_debug = debug;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Code example from libxml2 docs re: read from a stream.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!f.good())
|
|
Packit |
a4aae4 |
throw Error("Input stream not open or read error");
|
|
Packit |
a4aae4 |
if (!dest_dmr)
|
|
Packit |
a4aae4 |
throw InternalErr(__FILE__, __LINE__, "DMR object is null");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_dmr = dest_dmr; // dump values here
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
// Old, bad, code. Lines are limited to 1023 chars including the element text.
|
|
Packit |
a4aae4 |
const int size = 1024;
|
|
Packit |
a4aae4 |
char chars[size];
|
|
Packit |
a4aae4 |
int line = 1;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
f.getline(chars, size);
|
|
Packit |
a4aae4 |
int res = f.gcount();
|
|
Packit |
a4aae4 |
if (res == 0) throw Error("No input found while parsing the DMR.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
getline(f, line);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (debug) cerr << "line: (" << line++ << "): " << chars << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_context = xmlCreatePushParserCtxt(&d_dmr_sax_parser, this, chars, res - 1, "stream");
|
|
Packit |
a4aae4 |
d_context->validate = true;
|
|
Packit |
a4aae4 |
push_state(parser_start);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
f.getline(chars, size);
|
|
Packit |
a4aae4 |
while ((f.gcount() > 0) && (get_state() != parser_end)) {
|
|
Packit |
a4aae4 |
if (debug) cerr << "line: (" << line++ << "): " << chars << endl;
|
|
Packit |
a4aae4 |
xmlParseChunk(d_context, chars, f.gcount() - 1, 0);
|
|
Packit |
a4aae4 |
f.getline(chars, size);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This call ends the parse.
|
|
Packit |
a4aae4 |
xmlParseChunk(d_context, chars, 0, 1/*terminate*/);
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
int line_num = 1;
|
|
Packit |
a4aae4 |
string line;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Get the <xml ... ?> line
|
|
Packit |
a4aae4 |
getline(f, line);
|
|
Packit |
a4aae4 |
if (line.length() == 0) throw Error("No input found while parsing the DMR.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (debug) cerr << "line: (" << line_num << "): " << endl << line << endl << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_context = xmlCreatePushParserCtxt(&d_dmr_sax_parser, this, line.c_str(), line.length(), "stream");
|
|
Packit |
a4aae4 |
d_context->validate = true;
|
|
Packit |
a4aae4 |
push_state(parser_start);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Get the first line of stuff
|
|
Packit |
a4aae4 |
getline(f, line);
|
|
Packit |
a4aae4 |
++line_num;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (debug) cerr << "line: (" << line_num << "): " << endl << line << endl << endl;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
while (!f.eof() && (get_state() != parser_end)) {
|
|
Packit |
a4aae4 |
xmlParseChunk(d_context, line.c_str(), line.length(), 0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Get the next line
|
|
Packit |
a4aae4 |
getline(f, line);
|
|
Packit |
a4aae4 |
++line_num;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (debug) cerr << "line: (" << line_num << "): " << endl << line << endl << endl;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This call ends the parse.
|
|
Packit |
a4aae4 |
xmlParseChunk(d_context, line.c_str(), 0, 1/*terminate*/);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This checks that the state on the parser stack is parser_end and throws
|
|
Packit |
a4aae4 |
// an exception if it's not (i.e., the loop exited with gcount() == 0).
|
|
Packit |
a4aae4 |
cleanup_parse();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Parse a DMR document stored in a string.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param document Read the DMR from this string.
|
|
Packit |
a4aae4 |
* @param dest_dmr Value/result parameter; dumps the information to this DMR
|
|
Packit |
a4aae4 |
* instance.
|
|
Packit |
a4aae4 |
* @param debug If true, ouput helpful debugging messages, False by default
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @exception Error Thrown if the XML document could not be read or parsed.
|
|
Packit |
a4aae4 |
* @exception InternalErr Thrown if an internal error is found.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::intern(const string &document, DMR *dest_dmr, bool debug)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
intern(document.c_str(), document.length(), dest_dmr, debug);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Parse a DMR document stored in a char *buffer.
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @param document Read the DMR from this string.
|
|
Packit |
a4aae4 |
* @param dest_dmr Value/result parameter; dumps the information to this DMR
|
|
Packit |
a4aae4 |
* instance.
|
|
Packit |
a4aae4 |
* @param debug If true, ouput helpful debugging messages, False by default
|
|
Packit |
a4aae4 |
*
|
|
Packit |
a4aae4 |
* @exception Error Thrown if the XML document could not be read or parsed.
|
|
Packit |
a4aae4 |
* @exception InternalErr Thrown if an internal error is found.
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void D4ParserSax2::intern(const char *buffer, int size, DMR *dest_dmr, bool debug)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (!(size > 0)) return;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_debug = debug;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Code example from libxml2 docs re: read from a stream.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!dest_dmr) throw InternalErr(__FILE__, __LINE__, "DMR object is null");
|
|
Packit |
a4aae4 |
d_dmr = dest_dmr; // dump values in dest_dmr
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
push_state(parser_start);
|
|
Packit |
a4aae4 |
d_context = xmlCreatePushParserCtxt(&d_dmr_sax_parser, this, buffer, size, "stream");
|
|
Packit |
a4aae4 |
d_context->validate = true;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This call ends the parse.
|
|
Packit |
a4aae4 |
xmlParseChunk(d_context, buffer, 0, 1/*terminate*/);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This checks that the state on the parser stack is parser_end and throws
|
|
Packit |
a4aae4 |
// an exception if it's not (i.e., the loop exited with gcount() == 0).
|
|
Packit |
a4aae4 |
cleanup_parse();
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|