42 #include "Structure.h"
57 const string ValuesElement::_sTypeName =
"values";
58 const vector<string> ValuesElement::_sValidAttributes = getValidAttributes();
60 ValuesElement::ValuesElement()
76 _start = proto._start;
77 _increment = proto._increment;
78 _separator = proto._separator;
79 _gotContent = proto._gotContent;
80 _tokens = proto._tokens;
110 if (!_start.empty() && _increment.empty())
114 " had a start attribute without a corresponding increment attribute!");
116 if (_start.empty() && !_increment.empty())
119 "values element=" +
toString() +
" had an increment attribute without a corresponding start attribute!");
129 BESDEBUG(
"ncml",
"ValuesElement::handleBegin called with element=" <<
toString() <<
130 " at scope=" << p.getScopeString() << endl);
133 if (!p.isScopeVariable())
136 "Got values element while not parsing a variable! values=" +
toString() +
137 " at scope=" + p.getTypedScopeString());
146 "Got a values element when one was already specified for this variable=" +
148 " at scope=" + p.getScopeString());
152 if (shouldAutoGenerateValues())
154 BaseType* pVar = p.getCurrentVariable();
155 NCML_ASSERT_MSG(pVar,
"ValuesElement::handleBegin(): Expected non-null p.getCurrentVariable()!");
156 autogenerateAndSetVariableValues(p, *pVar);
162 _accumulated_content.resize(0);
170 BESDEBUG(
"ncml",
"ValuesElement::handleContent called for " <<
toString() <<
" with content=" << content << endl);
180 " specified a start and increment to autogenerate values but also illegally specified content!");
184 BaseType* pVar = p.getCurrentVariable();
185 NCML_ASSERT_MSG(pVar,
"ValuesElement::handleContent: got unexpected null getCurrentVariable() from parser!!");
194 "This version of the NCML Module cannot change the values of an existing variable! "
195 "However, we got " +
toString() +
" element for variable=" + pVarElt->
toString() +
" at scope=" + p.getScopeString());
199 _accumulated_content.append(content);
206 if (pVar->is_simple_type() &&
207 (pVar->type() == dods_str_c || pVar->type() == dods_url_c))
210 _tokens.push_back(
string(content));
213 else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) ==
"char")
217 else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) ==
"string")
229 setVariableValuesFromTokens(p, *pVar);
231 setGotValuesOnOurVariableElement(p);
238 BESDEBUG(
"ncml",
"ValuesElement::handleEnd called for " <<
toString() << endl);
242 BaseType* pVar = p.getCurrentVariable();
243 NCML_ASSERT_MSG(pVar,
"ValuesElement::handleContent: got unexpected null getCurrentVariable() from parser!!");
246 _gotContent = !_accumulated_content.empty();
248 if (!shouldAutoGenerateValues() && !_gotContent)
251 "Values element=" +
toString() +
" expected content for values but didn't get any!");
258 if (pVar->is_simple_type() && (pVar->type() == dods_str_c || pVar->type() == dods_url_c))
261 _tokens.push_back(
string(_accumulated_content));
264 else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) ==
"char")
268 else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) ==
"string")
279 if (!shouldAutoGenerateValues())
281 setVariableValuesFromTokens(p, *pVar);
282 setGotValuesOnOurVariableElement(p);
293 if (!shouldAutoGenerateValues())
295 dealWithEmptyStringValues();
305 ((_start.empty())?(
""):(
"start=\"" + _start +
"\" ")) +
306 ((_increment.empty())?(
""):(
"increment=\"" + _increment +
"\" ")) +
312 ValuesElement::validateStartAndIncrementForVariableTypeOrThrow(libdap::BaseType& )
const
318 template <
class DAPType,
typename ValueType>
320 ValuesElement::setScalarValue(libdap::BaseType& var,
const string& valueAsToken)
323 DAPType* pVar =
dynamic_cast<DAPType*
>(&var);
324 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
327 std::stringstream sis;
328 sis.str(valueAsToken);
334 "Setting array values failed to read the value token properly! value was for var name=" +
335 var.name() +
" and the value token was " + valueAsToken);
339 pVar->set_value(value);
348 ValuesElement::setScalarValue<Byte, dods_byte>(libdap::BaseType& var,
const string& valueAsToken)
350 Byte* pVar =
dynamic_cast<Byte*
>(&var);
351 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
353 std::stringstream sis;
354 sis.str(valueAsToken);
360 _parser->getParseLineNumber(),
361 "Setting array values failed to read the value token properly! value was for var name=" +
362 var.name() +
" and the value token was " + valueAsToken);
366 pVar->set_value(static_cast<dods_byte>(value));
374 ValuesElement::setScalarValue<Str, string>(libdap::BaseType& var,
const string& valueAsToken)
376 Str* pVar =
dynamic_cast<Str*
>(&var);
377 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
378 pVar->set_value(valueAsToken);
387 ValuesElement::setScalarValue<Url, string>(libdap::BaseType& var,
const string& valueAsToken)
389 Url* pVar =
dynamic_cast<Url*
>(&var);
390 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
391 pVar->set_value(valueAsToken);
394 template <
typename DAPType>
396 ValuesElement::setVectorValues(libdap::Array* pArray,
const vector<string>& valueTokens)
400 vector<DAPType> values;
401 values.reserve(valueTokens.size());
404 vector<string>::const_iterator endIt = valueTokens.end();
405 for (vector<string>::const_iterator it = valueTokens.begin(); it != endIt; ++it)
408 stringstream valueTokenAsStream;
409 const std::string& token = *it;
410 valueTokenAsStream.str(token);
411 valueTokenAsStream >> value;
412 if (valueTokenAsStream.fail())
415 msg <<
"Got fail() on parsing a value token for an Array name=" << pArray->name() <<
416 " for value token index " << count <<
417 " with token=" << (*it) <<
421 values.push_back(value);
426 pArray->set_value(values, values.size());
434 ValuesElement::setVectorValues <string> (libdap::Array* pArray,
const vector<string>& valueTokens)
438 vector<string>& values =
const_cast< vector<string>&
>(valueTokens);
439 pArray->set_value(values, values.size());
446 ValuesElement::parseAndSetCharValue(libdap::BaseType& var,
const string& valueAsToken)
448 Byte* pVar =
dynamic_cast<Byte*
>(&var);
449 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
451 if (valueAsToken.size() != 1)
454 "Parsing scalar char, expected single character but didnt get it. value was for var name=" +
455 var.name() +
" and the value token was " + valueAsToken);
459 dods_byte val = valueAsToken.at(0);
460 pVar->set_value(val);
464 ValuesElement::parseAndSetCharValueArray(NCMLParser& , libdap::Array* pVecVar,
const vector<string>& tokens)
466 vector<dods_byte> values;
467 for (
unsigned int i=0; i<tokens.size(); ++i)
469 values.push_back(static_cast<dods_byte>((tokens.at(i))[0]));
471 pVecVar->set_value(values, values.size());
475 ValuesElement::setVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
478 if (var.type() == dods_structure_c)
481 "Illegal to specify <values> element for a Structure type variable name=" + var.name() +
482 " at scope=" + p.getScopeString());
485 if (var.is_simple_type())
487 setScalarVariableValuesFromTokens(p, var);
489 else if (var.is_vector_type())
491 setVectorVariableValuesFromTokens(p, var);
496 "Can't call ValuesElement::setVariableValuesFromTokens for constructor type now!! "
497 "Variable named " + var.name() +
" at scope=" + p.getScopeString());
502 ValuesElement::setScalarVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
505 if (_tokens.size() != 1)
508 msg <<
"While setting scalar variable name=" << var.name() <<
509 " we expected exactly 1 value in content but found " << _tokens.size() <<
517 if (getNCMLTypeForVariable(p) !=
"char")
519 p.checkDataIsValidForCanonicalTypeOrThrow(var.type_name(), _tokens);
523 const string& valueToken = _tokens.at(0);
526 Type varType = var.type();
532 if (getNCMLTypeForVariable(p) ==
"char")
534 parseAndSetCharValue(var, valueToken);
538 setScalarValue <Byte, dods_byte> (var, valueToken);
543 setScalarValue<Int16, dods_int16>(var, valueToken);
547 setScalarValue<UInt16, dods_uint16>(var, valueToken);
551 setScalarValue<Int32, dods_int32>(var, valueToken);
555 setScalarValue<UInt32, dods_uint32>(var, valueToken);
559 setScalarValue<Float32, dods_float32>(var, valueToken);
563 setScalarValue<Float64, dods_float64>(var, valueToken);
567 setScalarValue<Str, string>(var, valueToken);
571 setScalarValue<Url, string>(var, valueToken);
581 ValuesElement::setVectorVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
583 Array* pVecVar =
dynamic_cast<Array*
>(&var);
584 NCML_ASSERT_MSG(pVecVar,
"ValuesElement::setVectorVariableValuesFromTokens expect var"
585 " to be castable to class Array but it wasn't!!");
589 if (pVecVar->length() > 0 &&
590 static_cast<unsigned int>(pVecVar->length()) != _tokens.size())
593 msg <<
"Dimension mismatch! Variable name=" << pVecVar->name() <<
594 " has dimension product=" << pVecVar->length() <<
595 " but we got " << _tokens.size() <<
596 " values in the values element " <<
toString();
601 if (getNCMLTypeForVariable(p) !=
"char")
603 BaseType* pTemplate = var.var();
605 p.checkDataIsValidForCanonicalTypeOrThrow(pTemplate->type_name(), _tokens);
610 libdap::Type valType = pVecVar->var()->type();
616 if (getNCMLTypeForVariable(p) ==
"char")
618 parseAndSetCharValueArray(p, pVecVar, _tokens);
622 setVectorValues <dods_byte> (pVecVar, _tokens);
627 setVectorValues <dods_int16> (pVecVar, _tokens);
631 setVectorValues <dods_uint16> (pVecVar, _tokens);
635 setVectorValues <dods_int32> (pVecVar, _tokens);
639 setVectorValues <dods_uint32> (pVecVar, _tokens);
643 setVectorValues <dods_float32> (pVecVar, _tokens);
647 setVectorValues <dods_float64> (pVecVar, _tokens);
651 setVectorValues <string> (pVecVar, _tokens);
655 setVectorValues <string> (pVecVar, _tokens);
665 template <
typename DAPType>
667 ValuesElement::generateAndSetVectorValues(NCMLParser& p, libdap::Array* pArray)
682 "Failed to parse the values@start=" + _start +
" for " +
toString() +
683 " at scope=" + p.getScopeString());
695 "Failed to parse the values@increment=" + _start +
" for " +
toString() +
696 " at scope=" + p.getScopeString());
700 int numPoints = pArray->length();
702 vector<DAPType> values;
703 values.reserve(numPoints);
706 for (
int i=1; i<numPoints; ++i)
711 NCML_ASSERT(values.size() ==
static_cast<unsigned int>(numPoints));
712 pArray->set_value(values, values.size());
716 ValuesElement::autogenerateAndSetVariableValues(NCMLParser& p, BaseType& var)
719 libdap::Array* pArray =
dynamic_cast<libdap::Array*
>(&var);
722 THROW_NCML_INTERNAL_ERROR(
"ValuesElement::autogenerateAndSetVariableValues: expected variable of type libdap::Array but failed to cast it!");
725 setGotValuesOnOurVariableElement(p);
728 libdap::BaseType* pTemplate = pArray->var();
730 switch (pTemplate->type())
734 if (getNCMLTypeForVariable(p) ==
"char")
737 "Can't use values@start for non-numeric values!");
741 generateAndSetVectorValues <dods_byte> (p, pArray);
746 generateAndSetVectorValues <dods_int16> (p, pArray);
750 generateAndSetVectorValues <dods_uint16> (p, pArray);
754 generateAndSetVectorValues <dods_int32> (p, pArray);
758 generateAndSetVectorValues <dods_uint32> (p, pArray);
762 generateAndSetVectorValues <dods_float32> (p, pArray);
766 generateAndSetVectorValues <dods_float64> (p, pArray);
773 "Can't use values@start for non-numeric values!");
784 ValuesElement::getNCMLTypeForVariable(NCMLParser& p)
const
786 const VariableElement* pMyParent = getContainingVariableElement(p);
788 return pMyParent->type();
791 const VariableElement*
792 ValuesElement::getContainingVariableElement(NCMLParser& p)
const
794 const VariableElement* ret = 0;
797 NCMLParser::ElementStackConstIterator it;
798 NCMLParser::ElementStackConstIterator endIt = p.getElementStackEnd();
799 for (it = p.getElementStackBegin(); it != endIt; ++it)
802 const VariableElement* pVarElt =
dynamic_cast<const VariableElement*
>(pElt);
813 ValuesElement::setGotValuesOnOurVariableElement(NCMLParser& p)
816 VariableElement* pContainingVar =
const_cast<VariableElement*
>(getContainingVariableElement(p));
818 pContainingVar->setGotValues();
824 ValuesElement::dealWithEmptyStringValues()
835 ValuesElement::getValidAttributes()
837 vector<string> validAttrs;
838 validAttrs.reserve(3);
839 validAttrs.push_back(
"start");
840 validAttrs.push_back(
"increment");
841 validAttrs.push_back(
"separator");
bool isNewVariable() const
virtual bool validateAttributes(const XMLAttributeMap &attrs, const vector< string > &validAttrs, vector< string > *pInvalidAttrs=0, bool printInvalid=true, bool throwOnError=true)
Check that the given attributes are all in the valid set, otherwise fill in *pInvalidAttrs with the p...
#define NCML_ASSERT(cond)
An abstract superclass for NCMLArray that handles the non-parameterized functionality and allows u...
const string getValueForLocalNameOrDefault(const string &localname, const string &defVal="") const
If there is an attribute with localname, return its value, else return default.
static bool isAllWhitespace(const std::string &str)
Is all the string whitespace as defined by chars in WHITESPACE ?
#define NCML_ASSERT_MSG(cond, msg)
static class NCMLUtil overview
static int tokenizeChars(const std::string &str, std::vector< std::string > &tokens)
Split str into a vector with one char in str per token slot.
virtual void setAttributes(const XMLAttributeMap &attrs)
Set the attributes of this from the map.
virtual const string & getTypeName() const
Return the type of the element, which should be: the same as ConcreteClassName::getTypeName() ...
virtual string toString() const
Return a string describing the element.
bool checkGotValues() const
int getParseLineNumber() const
Get the line of the NCML file the parser is currently parsing.
static const string _sTypeName
#define THROW_NCML_PARSE_ERROR(parseLine, msg)
NCMLElement(NCMLParser *p)
Base class for NcML element concrete classes.
virtual string toString() const
Return a string describing the element.
#define THROW_NCML_INTERNAL_ERROR(msg)
virtual void handleBegin()
Handle a begin on this element.
Concrete class for NcML element.
virtual ValuesElement * clone() const
Make and return a copy of this.
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
static const std::string WHITESPACE
Delimiter set for tokenizing whitespace separated data.
static const vector< string > _sValidAttributes
virtual void handleContent(const string &content)
Handle the characters content for the element.
virtual void handleEnd()
Handle the closing of this element.
static int tokenize(const std::string &str, std::vector< std::string > &tokens, const std::string &delimiters=" \t")
Split str into tokens using the characters in delimiters as split boundaries.