30 #include "ValuesElement.h"
42 #include "Structure.h"
47 #include "NCMLDebug.h"
48 #include "NCMLParser.h"
51 #include "VariableElement.h"
56 const string ValuesElement::_sTypeName =
"values";
57 const vector<string> ValuesElement::_sValidAttributes = getValidAttributes();
59 ValuesElement::ValuesElement() :
60 RCObjectInterface(), NCMLElement(0), _start(
""), _increment(
""), _separator(
""), _gotContent(false), _tokens()
65 ValuesElement::ValuesElement(
const ValuesElement& proto) :
66 RCObjectInterface(), NCMLElement(proto)
68 _start = proto._start;
69 _increment = proto._increment;
70 _separator = proto._separator;
71 _gotContent = proto._gotContent;
72 _tokens = proto._tokens;
75 ValuesElement::~ValuesElement()
81 ValuesElement::getTypeName()
const
87 ValuesElement::clone()
const
94 validateAttributes(attrs, _sValidAttributes);
101 if (!_start.empty() && _increment.empty()) {
102 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
103 "values element=" + toString() +
" had a start attribute without a corresponding increment attribute!");
105 if (_start.empty() && !_increment.empty()) {
106 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
107 "values element=" + toString() +
" had an increment attribute without a corresponding start attribute!");
111 void ValuesElement::handleBegin()
117 "ValuesElement::handleBegin called with element=" << toString() <<
" at scope=" << p.getScopeString() << endl);
120 if (!p.isScopeVariable()) {
121 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
122 "Got values element while not parsing a variable! values=" + toString() +
" at scope="
123 + p.getTypedScopeString());
130 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
131 "Got a values element when one was already specified for this variable=" + pVarElt->
toString()
132 +
" at scope=" + p.getScopeString());
136 if (shouldAutoGenerateValues()) {
137 BaseType* pVar = p.getCurrentVariable();
138 NCML_ASSERT_MSG(pVar,
"ValuesElement::handleBegin(): Expected non-null p.getCurrentVariable()!");
139 autogenerateAndSetVariableValues(p, *pVar);
145 _accumulated_content.resize(0);
148 void ValuesElement::handleContent(
const string& content)
152 BESDEBUG(
"ncml",
"ValuesElement::handleContent called for " << toString() <<
" with content=" << content << endl);
158 if (shouldAutoGenerateValues() && !NCMLUtil::isAllWhitespace(content)) {
159 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
160 "Element: " + toString()
161 +
" specified a start and increment to autogenerate values but also illegally specified content!");
165 BaseType* pVar = p.getCurrentVariable();
166 NCML_ASSERT_MSG(pVar,
"ValuesElement::handleContent: got unexpected null getCurrentVariable() from parser!!");
173 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
174 "This version of the NCML Module cannot change the values of an existing variable! "
175 "However, we got " + toString() +
" element for variable=" + pVarElt->
toString() +
" at scope="
176 + p.getScopeString());
180 _accumulated_content.append(content);
187 if (pVar->is_simple_type() &&
188 (pVar->type() == dods_str_c || pVar->type() == dods_url_c))
191 _tokens.push_back(
string(content));
194 else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) ==
"char")
196 NCMLUtil::tokenizeChars(content, _tokens);
198 else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) ==
"string")
200 string sep = ((_separator.empty())?(NCMLUtil::WHITESPACE):(_separator));
201 NCMLUtil::tokenize(content, _tokens, sep);
205 string sep = ((_separator.empty())?(NCMLUtil::WHITESPACE):(_separator));
206 NCMLUtil::tokenize(content, _tokens, sep);
210 setVariableValuesFromTokens(p, *pVar);
212 setGotValuesOnOurVariableElement(p);
216 void ValuesElement::handleEnd()
218 BESDEBUG(
"ncml",
"ValuesElement::handleEnd called for " << toString() << endl);
222 BaseType* pVar = p.getCurrentVariable();
223 NCML_ASSERT_MSG(pVar,
"ValuesElement::handleContent: got unexpected null getCurrentVariable() from parser!!");
226 _gotContent = !_accumulated_content.empty();
228 if (!shouldAutoGenerateValues() && !_gotContent)
230 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
231 "Values element=" + toString() +
" expected content for values but didn't get any!");
238 if (pVar->is_simple_type() && (pVar->type() == dods_str_c || pVar->type() == dods_url_c)) {
240 _tokens.push_back(
string(_accumulated_content));
243 else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) ==
"char") {
244 NCMLUtil::tokenizeChars(_accumulated_content, _tokens);
246 else if (pVar->is_vector_type() && getNCMLTypeForVariable(p) ==
"string") {
247 string sep = ((_separator.empty()) ? (NCMLUtil::WHITESPACE) : (_separator));
248 NCMLUtil::tokenize(_accumulated_content, _tokens, sep);
252 string sep = ((_separator.empty()) ? (NCMLUtil::WHITESPACE) : (_separator));
253 NCMLUtil::tokenize(_accumulated_content, _tokens, sep);
256 if (!shouldAutoGenerateValues()) {
257 setVariableValuesFromTokens(p, *pVar);
258 setGotValuesOnOurVariableElement(p);
269 if (!shouldAutoGenerateValues())
271 dealWithEmptyStringValues();
277 string ValuesElement::toString()
const
279 return "<" + _sTypeName +
" " + ((_start.empty()) ? (
"") : (
"start=\"" + _start +
"\" "))
280 + ((_increment.empty()) ? (
"") : (
"increment=\"" + _increment +
"\" "))
281 + ((_separator == NCMLUtil::WHITESPACE) ? (
"") : (
"separator=\"" + _separator +
"\" ")) +
">";
284 void ValuesElement::validateStartAndIncrementForVariableTypeOrThrow(libdap::BaseType& )
const
290 template<
class DAPType,
typename ValueType>
291 void ValuesElement::setScalarValue(libdap::BaseType& var,
const string& valueAsToken)
294 DAPType* pVar =
dynamic_cast<DAPType*
>(&var);
295 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
298 std::stringstream sis;
299 sis.str(valueAsToken);
303 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
304 "Setting array values failed to read the value token properly! value was for var name=" + var.name()
305 +
" and the value token was " + valueAsToken);
309 pVar->set_value(value);
317 void ValuesElement::setScalarValue<Byte, dods_byte>(libdap::BaseType& var,
const string& valueAsToken)
319 Byte* pVar =
dynamic_cast<Byte*
>(&var);
320 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
322 std::stringstream sis;
323 sis.str(valueAsToken);
327 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
328 "Setting array values failed to read the value token properly! value was for var name=" + var.name()
329 +
" and the value token was " + valueAsToken);
333 pVar->set_value(
static_cast<dods_byte
>(value));
340 void ValuesElement::setScalarValue<Str, string>(libdap::BaseType& var,
const string& valueAsToken)
342 Str* pVar =
dynamic_cast<Str*
>(&var);
343 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
344 pVar->set_value(valueAsToken);
351 void ValuesElement::setScalarValue<Url, string>(libdap::BaseType& var,
const string& valueAsToken)
353 Url* pVar =
dynamic_cast<Url*
>(&var);
354 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
355 pVar->set_value(valueAsToken);
358 template<
typename DAPType>
359 void ValuesElement::setVectorValues(libdap::Array* pArray,
const vector<string>& valueTokens)
363 vector<DAPType> values;
364 values.reserve(valueTokens.size());
367 vector<string>::const_iterator endIt = valueTokens.end();
368 for (vector<string>::const_iterator it = valueTokens.begin(); it != endIt; ++it) {
370 stringstream valueTokenAsStream;
371 const std::string& token = *it;
372 valueTokenAsStream.str(token);
373 valueTokenAsStream >> value;
374 if (valueTokenAsStream.fail()) {
376 msg <<
"Got fail() on parsing a value token for an Array name=" << pArray->name()
377 <<
" for value token index " << count <<
" with token=" << (*it) <<
" for element " << toString();
378 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), msg.str());
380 values.push_back(value);
385 pArray->set_value(values, values.size());
392 void ValuesElement::setVectorValues<string>(libdap::Array* pArray,
const vector<string>& valueTokens)
396 vector<string>& values =
const_cast<vector<string>&
>(valueTokens);
397 pArray->set_value(values, values.size());
403 void ValuesElement::parseAndSetCharValue(libdap::BaseType& var,
const string& valueAsToken)
405 Byte* pVar =
dynamic_cast<Byte*
>(&var);
406 NCML_ASSERT_MSG(pVar,
"setScalarValue() got called with BaseType not matching the expected type.");
408 if (valueAsToken.size() != 1) {
409 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
410 "Parsing scalar char, expected single character but didnt get it. value was for var name=" + var.name()
411 +
" and the value token was " + valueAsToken);
415 dods_byte val = valueAsToken.at(0);
416 pVar->set_value(val);
419 void ValuesElement::parseAndSetCharValueArray(NCMLParser& , libdap::Array* pVecVar,
const vector<string>& tokens)
421 vector<dods_byte> values;
422 for (
unsigned int i = 0; i < tokens.size(); ++i) {
423 values.push_back(
static_cast<dods_byte
>((tokens.at(i))[0]));
425 pVecVar->set_value(values, values.size());
428 void ValuesElement::setVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
431 if (var.type() == dods_structure_c) {
432 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
433 "Illegal to specify <values> element for a Structure type variable name=" + var.name() +
" at scope="
434 + p.getScopeString());
437 if (var.is_simple_type()) {
438 setScalarVariableValuesFromTokens(p, var);
440 else if (var.is_vector_type()) {
441 setVectorVariableValuesFromTokens(p, var);
444 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
445 "Can't call ValuesElement::setVariableValuesFromTokens for constructor type now!! "
446 "Variable named " + var.name() +
" at scope=" + p.getScopeString());
450 void ValuesElement::setScalarVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
453 if (_tokens.size() != 1) {
455 msg <<
"While setting scalar variable name=" << var.name()
456 <<
" we expected exactly 1 value in content but found " << _tokens.size() <<
" tokens.";
457 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), msg.str());
462 if (getNCMLTypeForVariable(p) !=
"char") {
463 p.checkDataIsValidForCanonicalTypeOrThrow(var.type_name(), _tokens);
467 const string& valueToken = _tokens.at(0);
470 Type varType = var.type();
475 if (getNCMLTypeForVariable(p) ==
"char") {
476 parseAndSetCharValue(var, valueToken);
479 setScalarValue<Byte, dods_byte>(var, valueToken);
484 setScalarValue<Int16, dods_int16>(var, valueToken);
488 setScalarValue<UInt16, dods_uint16>(var, valueToken);
492 setScalarValue<Int32, dods_int32>(var, valueToken);
496 setScalarValue<UInt32, dods_uint32>(var, valueToken);
500 setScalarValue<Float32, dods_float32>(var, valueToken);
504 setScalarValue<Float64, dods_float64>(var, valueToken);
508 setScalarValue<Str, string>(var, valueToken);
512 setScalarValue<Url, string>(var, valueToken);
516 THROW_NCML_INTERNAL_ERROR(
"Expected simple type but didn't find it!")
522 void ValuesElement::setVectorVariableValuesFromTokens(NCMLParser& p, libdap::BaseType& var)
524 Array* pVecVar =
dynamic_cast<Array*
>(&var);
525 NCML_ASSERT_MSG(pVecVar,
"ValuesElement::setVectorVariableValuesFromTokens expect var"
526 " to be castable to class Array but it wasn't!!");
530 if (pVecVar->length() > 0 &&
static_cast<unsigned int>(pVecVar->length()) != _tokens.size()) {
532 msg <<
"Dimension mismatch! Variable name=" << pVecVar->name() <<
" has dimension product="
533 << pVecVar->length() <<
" but we got " << _tokens.size() <<
" values in the values element " << toString();
534 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), msg.str());
538 if (getNCMLTypeForVariable(p) !=
"char") {
539 BaseType* pTemplate = var.var();
540 VALID_PTR(pTemplate);
541 p.checkDataIsValidForCanonicalTypeOrThrow(pTemplate->type_name(), _tokens);
545 VALID_PTR(pVecVar->var());
551 if (getNCMLTypeForVariable(p) ==
"char") {
552 parseAndSetCharValueArray(p, pVecVar, _tokens);
555 setVectorValues<dods_byte>(pVecVar, _tokens);
560 setVectorValues<dods_int16>(pVecVar, _tokens);
564 setVectorValues<dods_uint16>(pVecVar, _tokens);
568 setVectorValues<dods_int32>(pVecVar, _tokens);
572 setVectorValues<dods_uint32>(pVecVar, _tokens);
576 setVectorValues<dods_float32>(pVecVar, _tokens);
580 setVectorValues<dods_float64>(pVecVar, _tokens);
584 setVectorValues<string>(pVecVar, _tokens);
588 setVectorValues<string>(pVecVar, _tokens);
592 THROW_NCML_INTERNAL_ERROR(
"Expected Vector template type was a simple type but didn't find it!")
599 template<
typename DAPType>
600 void ValuesElement::generateAndSetVectorValues(NCMLParser& p, libdap::Array* pArray)
613 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
614 "Failed to parse the values@start=" + _start +
" for " + toString() +
" at scope=" + p.getScopeString());
624 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
625 "Failed to parse the values@increment=" + _start +
" for " + toString() +
" at scope="
626 + p.getScopeString());
630 int numPoints = pArray->length();
631 NCML_ASSERT(numPoints >= 1);
632 vector<DAPType> values;
633 values.reserve(numPoints);
636 for (
int i = 1; i < numPoints; ++i) {
640 NCML_ASSERT(values.size() ==
static_cast<unsigned int>(numPoints));
641 pArray->set_value(values, values.size());
644 void ValuesElement::autogenerateAndSetVariableValues(NCMLParser& p, BaseType& var)
647 libdap::Array* pArray =
dynamic_cast<libdap::Array*
>(&var);
649 THROW_NCML_INTERNAL_ERROR(
650 "ValuesElement::autogenerateAndSetVariableValues: expected variable of type libdap::Array but failed to cast it!");
653 setGotValuesOnOurVariableElement(p);
656 libdap::BaseType* pTemplate = pArray->var();
657 VALID_PTR(pTemplate);
658 switch (pTemplate->type()) {
661 if (getNCMLTypeForVariable(p) ==
"char") {
662 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
"Can't use values@start for non-numeric values!");
666 generateAndSetVectorValues<dods_byte>(p, pArray);
671 generateAndSetVectorValues<dods_int16>(p, pArray);
675 generateAndSetVectorValues<dods_uint16>(p, pArray);
679 generateAndSetVectorValues<dods_int32>(p, pArray);
683 generateAndSetVectorValues<dods_uint32>(p, pArray);
687 generateAndSetVectorValues<dods_float32>(p, pArray);
691 generateAndSetVectorValues<dods_float64>(p, pArray);
697 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
"Can't use values@start for non-numeric values!")
702 THROW_NCML_INTERNAL_ERROR(
"Expected Vector template type was a simple type but didn't find it!")
709 std::string ValuesElement::getNCMLTypeForVariable(NCMLParser& p)
const
711 const VariableElement* pMyParent = getContainingVariableElement(p);
712 VALID_PTR(pMyParent);
713 return pMyParent->type();
716 const VariableElement*
717 ValuesElement::getContainingVariableElement(NCMLParser& p)
const
719 const VariableElement* ret = 0;
722 NCMLParser::ElementStackConstIterator it;
723 NCMLParser::ElementStackConstIterator endIt = p.getElementStackEnd();
724 for (it = p.getElementStackBegin(); it != endIt; ++it) {
725 const NCMLElement* pElt = *it;
726 const VariableElement* pVarElt =
dynamic_cast<const VariableElement*
>(pElt);
735 void ValuesElement::setGotValuesOnOurVariableElement(NCMLParser& p)
738 VariableElement* pContainingVar =
const_cast<VariableElement*
>(getContainingVariableElement(p));
739 VALID_PTR(pContainingVar);
740 pContainingVar->setGotValues();
745 void ValuesElement::dealWithEmptyStringValues()
754 vector<string> ValuesElement::getValidAttributes()
756 vector<string> validAttrs;
757 validAttrs.reserve(3);
758 validAttrs.push_back(
"start");
759 validAttrs.push_back(
"increment");
760 validAttrs.push_back(
"separator");